Merge "ASoC: msm: Safe error recovery for column data and hw delay"
diff --git a/Documentation/cpuidle/driver.txt b/Documentation/cpuidle/driver.txt
index 7a9e09e..1b0d81d 100644
--- a/Documentation/cpuidle/driver.txt
+++ b/Documentation/cpuidle/driver.txt
@@ -15,11 +15,17 @@
 cpuidle driver initializes the cpuidle_device structure for each CPU device
 and registers with cpuidle using cpuidle_register_device.
 
+If all the idle states are the same, the wrapper function cpuidle_register
+could be used instead.
+
 It can also support the dynamic changes (like battery <-> AC), by using
 cpuidle_pause_and_lock, cpuidle_disable_device and cpuidle_enable_device,
 cpuidle_resume_and_unlock.
 
 Interfaces:
+extern int cpuidle_register(struct cpuidle_driver *drv,
+                            const struct cpumask *const coupled_cpus);
+extern int cpuidle_unregister(struct cpuidle_driver *drv);
 extern int cpuidle_register_driver(struct cpuidle_driver *drv);
 extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
 extern int cpuidle_register_device(struct cpuidle_device *dev);
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
index 917ea75..0696730 100644
--- a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -1,52 +1,106 @@
 * Low Power Management Levels
 
 The application processor in MSM can do a variety of C-States for low power
-management. These C-States are invoked by the CPUIdle framework when the core
-becomes idle. But based on the time available until the next scheduled wakeup,
-the system can do several low power modes. The combination is captured in the
-device tree as lpm-level.
+management. The LPM module performs the CPU and System low power modes based
+on it latency and residency information of the individual CPU/System low power
+levels.
 
-The required nodes for lpm-levels are:
+The first level node represents the properties of the system and includes
+second level node to represent the low power modes of cpu and system.
+
+[First Level Nodes]
+Required properties:
 
 - compatible: "qcom,lpm-levels"
-- reg: The numeric level id
+
+The optional nodes for the First level nodes are:
+- qcom,no-l2-saw: Indicates if this target has an L2 SAW (SPM and AVS wrapper).
+- qcom,default-l2-state: Indicates what the default low power state of the L2
+		SAW should be. This property should be mentioned when there is
+		a L2 saw.
+- qcom,allow-synced-levels:  Indicates if certain low power modes should be
+		synchronized across all cores so as to configure a system
+		low power mode.
+
+[Second Level Nodes]
+Required properties to define CPU low power modes :
+- compatible = "qcom,cpu-modes";
 - qcom,mode: The sleep mode of the processor, values for the property are:
 		"wfi" - Wait for Interrupt
-		"ramp_down_and_wfi" - Ramp down and wait for interrupt
+		"retention" - Retention
 		"standalone_pc" - Standalone power collapse
 		"pc" - Power Collapse
-		"retention" - Retention
-		"pc_suspend" - Suspended Power Collapse
-		"pc_no_xo_shutdown" - Power Collapse with no XO shutdown
+- qcom,latency-us: The latency in handling the interrupt if this level was
+		chosen, in uSec
+- qcom,ss-power: The steady state power expelled when the processor is in this
+		 level in mWatts
+- qcom,energy-overhead: The energy used up in entering and exiting this level
+		 in mWatts.uSec
+- qcom,time-overhead: The time spent in entering and exiting this level in uS
+
+Required propertieis to define System low power mode :
+- compatible: "qcom,system-modes"
 - qcom,l2: The state of L2 cache. Values are:
 		"l2_cache_pc" - L2 cache in power collapse
-		"l2_cache_pc_no_rpm" - L2 cache in power collapse. This mode wouldn't inform the RPM
+		"l2_cache_pc_no_rpm" - L2 cache in power collapse. This mode
+				wouldn't inform the RPM
 		"l2_cache_retenetion" - L2 cache in retention
 		"l2_cache_gdhs" - L2 cache in GDHS
 		"l2_cache_active" - L2 cache in active mode
-- qcom,latency-us: The latency in handling the interrupt if this level was
-	chosen, in uSec
-- qcom,ss-power: The steady state power expelled when the processor is in this
-	level in mWatts
-- qcom,energy-overhead: The energy used up in entering and exiting this level
-	in mWatts.uSec
-- qcom,time-overhead: The time spent in entering and exiting this level in uS
 
-The optional nodes for lpm-levels are :
--  qcom,no-l2-saw: Indicates if this target has an L2 SAW (SPM and AVS wrapper).
--  qcom,default-l2-state: Indicates what the default low power state of the L2 SAW should be. This property is used only when there is an L2 SAW.
+- qcom,latency-us: The latency in handling the interrupt if this level was
+		chosen, in uSec
+- qcom,ss-power: The steady state power expelled when the processor is in this
+		 level in mWatts
+- qcom,energy-overhead: The energy used up in entering and exiting this level
+		 in mWatts.uSec
+- qcom,time-overhead: The time spent in entering and exiting this level in uS
+- qcom,min-cpu-mode: The min cpu sleep mode at which the given system level is
+		 valid. All cpus should have entered this low power mode before
+		 this system level can be chosen.
 
 Example:
-
 qcom,lpm-levels {
-	qcom,no-l2-saw;
-	qcom,lpm-level@0 {
-		reg = <0>;
-		qcom,mode = "wfi";
-		qcom,l2 = "l2_cache_active";
-		qcom,latency-us = <100>;
-		qcom,ss-power = <650>;
-		qcom,energy-overhead = <801>;
-		qcom,time-overhead = <200>;
-	};
+		compatible = "qcom,lpm-levels";
+		qcom,default-l2-state = "l2_cache_retention";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		qcom,cpu-modes {
+			compatible = "qcom,cpu-modes";
+			qcom,cpu-mode@0 {
+				qcom,mode = "wfi";
+				qcom,latency-us = <1>;
+				qcom,ss-power = <715>;
+				qcom,energy-overhead = <17700>;
+				qcom,time-overhead = <2>;
+			};
+
+			qcom,cpu-mode@1 {
+				qcom,mode = "retention";
+				qcom,latency-us = <35>;
+				qcom,ss-power = <542>;
+				qcom,energy-overhead = <34920>;
+				qcom,time-overhead = <40>;
+			};
+		};
+		qcom,system-modes {
+			compatible = "qcom,system-modes";
+
+			qcom,system-mode@0 {
+				qcom,l2 = "l2_cache_gdhs";
+				qcom,latency-us = <20000>;
+				qcom,ss-power = <163>;
+				qcom,energy-overhead = <1577736>;
+				qcom,time-overhead = <5067>;
+			};
+
+			qcom,system-mode@1 {
+				qcom,l2 = "l2_cache_pc";
+				qcom,latency-us = <30000>;
+				qcom,ss-power = <83>;
+				qcom,energy-overhead = <2274420>;
+				qcom,time-overhead = <6605>;
+			};
+		};
 };
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 08d2c2d..0e236f2 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -178,34 +178,33 @@
 - qcom,mdss-dsi-bllp-power-mode:	Boolean to determine DSI lane state during
 					blanking low power period (BLLP) mode.
 - qcom,mdss-dsi-traffic-mode:		Specifies the panel traffic mode.
-					0 = non burst with sync pulses (default mode).
-					1 = non burst with sync start event.
-					2 = burst mode.
+					"non_burst_sync_pulse" = non burst with sync pulses (default).
+					"non_burst_sync_event" = non burst with sync start event.
+					"burst_mode" = burst mode.
 - qcom,mdss-dsi-pixel-packing:		Specifies if pixel packing is used (in case of RGB666).
-					0 = Tight packing (default value).
-					1 = Loose packing.
+					"tight" = Tight packing (default value).
+					"loose" = Loose packing.
 - qcom,mdss-dsi-virtual-channel-id:	Specifies the virtual channel identefier.
 					0 = default value.
 - qcom,mdss-dsi-color-order:		Specifies the R, G and B channel ordering.
-					0 = DSI_RGB_SWAP_RGB (default value)
-					1 = DSI_RGB_SWAP_RBG
-					2 = DSI_RGB_SWAP_BGR
-					3 = DSI_RGB_SWAP_BRG
-					4 = DSI_RGB_SWAP_GRB
-					5 = DSI_RGB_SWAP_GBR
+					"rgb_swap_rgb" = DSI_RGB_SWAP_RGB (default value)
+					"rgb_swap_rbg" = DSI_RGB_SWAP_RBG
+					"rgb_swap_brg" = DSI_RGB_SWAP_BRG
+					"rgb_swap_grb" = DSI_RGB_SWAP_GRB
+					"rgb_swap_gbr" = DSI_RGB_SWAP_GBR
 - qcom,mdss-dsi-lane-0-state:		Boolean that specifies whether data lane 0 is enabled.
 - qcom,mdss-dsi-lane-1-state:		Boolean that specifies whether data lane 1 is enabled.
 - qcom,mdss-dsi-lane-2-state:		Boolean that specifies whether data lane 2 is enabled.
 - qcom,mdss-dsi-lane-3-state:		Boolean that specifies whether data lane 3 is enabled.
 - qcom,mdss-dsi-lane-map:		Specifies the data lane swap configuration.
-					0 = <0 1 2 3> (default value)
-					1 = <3 0 1 2>
-					2 = <2 3 0 1>
-					3 = <1 2 3 0>
-					4 = <0 3 2 1>
-					5 = <1 0 3 2>
-					6 = <2 1 0 3>
-					7 = <3 2 1 0>
+					"lane_map_0123" = <0 1 2 3> (default value)
+					"lane_map_3012" = <3 0 1 2>
+					"lane_map_2301" = <2 3 0 1>
+					"lane_map_1230" = <1 2 3 0>
+					"lane_map_0321" = <0 3 2 1>
+					"lane_map_1032" = <1 0 3 2>
+					"lane_map_2103" = <2 1 0 3>
+					"lane_map_3210" = <3 2 1 0>
 - qcom,mdss-dsi-t-clk-post:		Specifies the byte clock cycles after mode switch.
 					0x03 = default value.
 - qcom,mdss-dsi-t-clk-pre:		Specifies the byte clock cycles before mode switch.
@@ -214,16 +213,16 @@
 					0 = stream 0 (default)
 					1 = stream 1
 - qcom,mdss-dsi-mdp-trigger:		Specifies the trigger mechanism to be used for MDP path.
-					0 = no trigger
-					2 = Tear check signal line used for trigger
-					4 = Triggered by software (default)
-					6 = Software trigger and TE
+					"none" = no trigger
+					"trigger_te" = Tear check signal line used for trigger
+					"trigger_sw" = Triggered by software (default)
+					"trigger_sw_te" = Software trigger and TE
 - qcom,mdss-dsi-dma-trigger:		Specifies the trigger mechanism to be used for DMA path.
-					0 = no trigger
-					2 = Tear check signal line used for trigger
-					4 = Triggered by software (default)
-					5 = Software trigger and start/end of frame trigger.
-					6 = Software trigger and TE
+					"none" = no trigger
+					"trigger_te" = Tear check signal line used for trigger
+					"trigger_sw" = Triggered by software (default)
+					"trigger_sw_seof" = Software trigger and start/end of frame trigger.
+					"trigger_sw_te" = Software trigger and TE
 - qcom,mdss-dsi-panel-framerate:	Specifies the frame rate for the panel.
 					60 = 60 frames per second (default)
 - qcom,mdss-dsi-panel-clockrate:	Specifies the panel clock speed in Hz.
diff --git a/Documentation/devicetree/bindings/nfc/nfc-nci.txt b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
index 5c53470..dca7d5c 100644
--- a/Documentation/devicetree/bindings/nfc/nfc-nci.txt
+++ b/Documentation/devicetree/bindings/nfc/nfc-nci.txt
@@ -8,7 +8,7 @@
 - reg: NCI i2c slave address.
 - qcom,dis-gpio: specific gpio for hardware reset.
 - qcom,irq-gpio: specific gpio for read interrupt.
-- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", ...)
+- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK","GPCLK2" ...)
 - qcom,clk-en-gpio: msm gpio clock,used ony if clock source is msm gpio
 - vlogic-supply: LDO for power supply
 - interrupt-parent: Should be phandle for the interrupt controller
diff --git a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
index 2963d15..17e6e94 100644
--- a/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-generic-720p-cmd.dtsi
@@ -37,7 +37,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [05 01 00 00 78 00 01 11
@@ -52,8 +51,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <0>;
-		qcom,mdss-dsi-traffic-mode = <1>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -73,8 +71,8 @@
 		qcom,mdss-dsi-bl-max-level = <255>;
 		qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
 		qcom,mdss-dsi-bl-pmic-bank-select = <7>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
 	};
diff --git a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
index 92e6fc1..88ccd08 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8379a-wvga-video.dtsi
@@ -38,7 +38,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [
@@ -137,8 +136,8 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <1>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-lane-map = "lane_map_3012";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -148,8 +147,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <255>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
 
diff --git a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
index 8f94502..8c79bb9 100755
--- a/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8389b-qhd-video.dtsi
@@ -38,7 +38,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [
@@ -115,8 +114,8 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <1>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-lane-map = "lane_map_3012";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -126,8 +125,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <26>;
 		qcom,mdss-dsi-bl-max-level = <255>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
 
diff --git a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
index 83351ca..5302d8ae 100644
--- a/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-hx8394a-720p-video.dtsi
@@ -38,7 +38,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [39 01 00 00 00 00 04 b9 ff 83 94
@@ -62,8 +61,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -75,8 +73,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x2d>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
 
diff --git a/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi b/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
index 1b64cf7..be42509 100644
--- a/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-jdi-1080p-video.dtsi
@@ -38,7 +38,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 55 00
@@ -51,8 +50,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <0>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -64,8 +62,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-dma-trigger = <0x04>;
-		qcom,mdss-dsi-mdp-trigger = <0x0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
 	};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
index 9bb11da..8be4e34 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -38,10 +38,9 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
-		qcom,mdss-dsi-pixel-packing = <0>;
+		qcom,mdss-dsi-pixel-packing = "tight";
 		qcom,mdss-dsi-on-command = [29 01 00 00 00 00 06 F0 55 AA 52 08 00
 				29 01 00 00 00 00 03 B1 68 21
 				23 01 00 00 00 00 02 B5 C8
@@ -252,8 +251,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -265,8 +263,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x2D>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <255>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
 
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
index a24cb58..d3547d8 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-cmd.dtsi
@@ -38,7 +38,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 FF EE
@@ -510,8 +509,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -528,8 +526,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x2c>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
 		qcom,mdss-pan-physical-width-dimension = <59>;
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 79618b9..8d28996 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,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 FF EE
@@ -511,8 +510,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -524,8 +522,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x2c>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
 		qcom,mdss-pan-physical-width-dimension = <59>;
diff --git a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
index 2312b37..770bac4 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35596-1080p-video.dtsi
@@ -38,7 +38,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [29 01 00 00 00 00 02 FF EE
@@ -566,8 +565,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -579,8 +577,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x38>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
 
diff --git a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
index 393419b..8d6e703 100644
--- a/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-otm8018b-fwvga-video.dtsi
@@ -38,7 +38,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [
@@ -247,8 +246,8 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-h-sync-pulse = <0>;
-		qcom,mdss-dsi-traffic-mode = <1>;
-		qcom,mdss-dsi-lane-map = <1>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-lane-map = "lane_map_3012";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -258,8 +257,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <26>;
 		qcom,mdss-dsi-bl-max-level = <255>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
 
diff --git a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
index 285d8fc..d23e3de 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -38,7 +38,7 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <2>;
+		qcom,mdss-dsi-color-order = "rgb_swap_bgr";
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [05 01 00 00 32 00 02 01 00
@@ -53,8 +53,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <0>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -64,8 +63,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x1c>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <4>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "trigger_sw";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>;
 
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
index b510e6b..60bba5d 100644
--- a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -31,16 +31,17 @@
 		qcom,mdss-dsi-h-pulse-width = <14>;
 		qcom,mdss-dsi-h-sync-skew = <0>;
 		qcom,mdss-dsi-v-back-porch = <14>;
-		qcom,mdss-dsi-v-front-porch = <11>;
+		qcom,mdss-dsi-v-front-porch = <30>;
 		qcom,mdss-dsi-v-pulse-width = <2>;
 		qcom,mdss-dsi-h-left-border = <0>;
 		qcom,mdss-dsi-h-right-border = <0>;
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-pixel-packing = "tight";
 		qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 FF 01
 			29 01 00 00 00 00 05 C6 63 00 81 31
 			29 01 00 00 00 00 05 CB E7 80 73 33
@@ -81,40 +82,38 @@
 			29 01 00 00 00 00 05 F6 00 00 00 00
 			29 01 00 00 00 00 05 F7 00 00 00 00
 			29 01 00 00 00 00 03 E1 90 00
-			29 01 00 00 00 00 03 DE 95 CF
+			29 01 00 00 00 00 07 DE 95 CF E2 CE 11 15
 			29 01 00 00 00 00 02 CF 46
 			29 01 00 00 00 00 03 C5 77 47
 			29 01 00 00 00 00 03 ED 00 20
 			05 01 00 00 B4 00 02 11 00
 			05 01 00 00 82 00 02 29 00
 			15 01 00 00 00 00 02 53 2c];
-
-		qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 10 00
-			05 01 00 00 32 00 02 53 00
-			05 01 00 00 00 00 02 c2 00
+		qcom,mdss-dsi-off-command = [15 01 00 00 32 00 02 10 00
+			15 01 00 00 32 00 02 53 00
+			15 01 00 00 00 00 02 c2 00
 			39 01 00 00 00 00 02 cf 40
-			05 01 00 00 50 00 03 de 84 00
+			15 01 00 00 50 00 03 de 84 00
 			39 01 00 00 00 00 02 cb 22
-			05 01 00 00 00 00 02 c3 00];
-
+			15 01 00 00 00 00 02 c3 00];
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <1>;
-		qcom,mdss-dsi-traffic-mode = <2>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "burst_mode";
+		qcom,mdss-dsi-lane-map = "lane_map_0123";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-lane-0-state;
 		qcom,mdss-dsi-lane-1-state;
 		qcom,mdss-dsi-lane-2-state;
 		qcom,mdss-dsi-lane-3-state;
-		qcom,mdss-dsi-panel-timings = [a8 1f 17 00 2f 2d 1c 21 29 03 04 00];
+		qcom,mdss-dsi-panel-timings = [68 1d 15 00 2e 2d 19 1f 24 03 04 00];
 		qcom,mdss-dsi-t-clk-post = <0x20>;
 		qcom,mdss-dsi-t-clk-pre = <0x2f>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
-		qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>;
+		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
 	};
 };
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 f7de416..10f53b9 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -38,7 +38,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [23 01 00 00 0a 00 02 b0 00
@@ -74,8 +73,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-h-sync-pulse = <0>;
-		qcom,mdss-dsi-traffic-mode = <1>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -87,8 +85,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-dma-trigger = <0x04>;
-		qcom,mdss-dsi-mdp-trigger = <0x0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-pan-enable-dynamic-fps;
 		qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
index d170833..168dda4 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-cmd.dtsi
@@ -39,7 +39,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [
@@ -146,8 +145,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-h-sync-pulse = <0>;
-		qcom,mdss-dsi-traffic-mode = <1>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -163,8 +161,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <255>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <2>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "trigger_te";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
 	};
diff --git a/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
index 546a90f..121e54d 100644
--- a/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-truly-wvga-video.dtsi
@@ -39,7 +39,6 @@
 		qcom,mdss-dsi-v-top-border = <0>;
 		qcom,mdss-dsi-v-bottom-border = <0>;
 		qcom,mdss-dsi-bpp = <24>;
-		qcom,mdss-dsi-color-order = <0>;
 		qcom,mdss-dsi-underflow-color = <0xff>;
 		qcom,mdss-dsi-border-color = <0>;
 		qcom,mdss-dsi-on-command = [
@@ -150,8 +149,7 @@
 		qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
 		qcom,mdss-dsi-h-sync-pulse = <0>;
-		qcom,mdss-dsi-traffic-mode = <1>;
-		qcom,mdss-dsi-lane-map = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
 		qcom,mdss-dsi-bllp-eof-power-mode;
 		qcom,mdss-dsi-bllp-power-mode;
 		qcom,mdss-dsi-lane-0-state;
@@ -161,8 +159,8 @@
 		qcom,mdss-dsi-t-clk-pre = <0x1b>;
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <255>;
-		qcom,mdss-dsi-dma-trigger = <4>;
-		qcom,mdss-dsi-mdp-trigger = <0>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
 	};
diff --git a/arch/arm/boot/dts/msm8226-v1-pm.dtsi b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
index 16b10fd..38ca03b 100644
--- a/arch/arm/boot/dts/msm8226-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v1-pm.dtsi
@@ -111,44 +111,68 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,lpm-level@0 {
-			reg = <0x0>;
-			qcom,mode = "wfi";
-			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <1>;
-			qcom,ss-power = <530>;
-			qcom,energy-overhead = <52800>;
-			qcom,time-overhead = <100>;
+		qcm,cpu-modes {
+			compatible = "qcom,cpu-modes";
+
+			qcom,cpu-modes@0 {
+				qcom,mode = "wfi";
+				qcom,latency-us = <1>;
+				qcom,ss-power = <530>;
+				qcom,energy-overhead = <52800>;
+				qcom,time-overhead = <100>;
+			};
+
+			qcom,cpu-modes@1 {
+				qcom,mode = "standalone_pc";
+				qcom,latency-us = <500>;
+				qcom,ss-power = <410>;
+				qcom,energy-overhead = <603400>;
+				qcom,time-overhead = <1200>;
+				qcom,use-broadcast-timer;
+			};
+
+			qcom,cpu-modes@2 {
+				qcom,mode = "pc";
+				qcom,latency-us = <550>;
+				qcom,ss-power = <372>;
+				qcom,energy-overhead = <700000>;
+				qcom,time-overhead = <1410>;
+				qcom,use-broadcast-timer;
+			};
 		};
 
-		qcom,lpm-level@1 {
-			reg = <0x1>;
-			qcom,mode = "standalone_pc";
-			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <500>;
-			qcom,ss-power = <410>;
-			qcom,energy-overhead = <603400>;
-			qcom,time-overhead = <1200>;
-		};
+		qcom,system-modes {
+			compatible = "qcom,system-modes";
 
-		qcom,lpm-level@2 {
-			reg = <0x2>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc_no_rpm";
-			qcom,latency-us = <1000>;
-			qcom,ss-power = <315>;
-			qcom,energy-overhead = <1027150>;
-			qcom,time-overhead = <2400>;
-		};
+			qcom,system-modes@0 {
+				qcom,l2 = "l2_cache_gdhs";
+				qcom,latency-us = <10700>;
+				qcom,ss-power = <372>;
+				qcom,energy-overhead = <738750>;
+				qcom,time-overhead = <1410>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 
-		qcom,lpm-level@3 {
-			reg = <0x3>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <11000>;
-			qcom,ss-power = <315>;
-			qcom,energy-overhead = <1027150>;
-			qcom,time-overhead = <2400>;
+			qcom,system-modes@1 {
+				qcom,l2 = "l2_cache_pc_no_rpm";
+				qcom,latency-us = <1000>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "spc";
+				qcom,sync-cpus;
+			};
+
+			qcom,system-modes@2 {
+				qcom,l2 = "l2_cache_pc";
+				qcom,latency-us = <12700>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8226-v2-pm.dtsi b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
index 0e634ff..a0da9cc 100644
--- a/arch/arm/boot/dts/msm8226-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2-pm.dtsi
@@ -113,54 +113,68 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,lpm-level@0 {
-			reg = <0x0>;
-			qcom,mode = "wfi";
-			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <1>;
-			qcom,ss-power = <530>;
-			qcom,energy-overhead = <52800>;
-			qcom,time-overhead = <100>;
+		qcm,cpu-modes {
+			compatible = "qcom,cpu-modes";
+
+			qcom,cpu-modes@0 {
+				qcom,mode = "wfi";
+				qcom,latency-us = <1>;
+				qcom,ss-power = <530>;
+				qcom,energy-overhead = <52800>;
+				qcom,time-overhead = <100>;
+			};
+
+			qcom,cpu-modes@1 {
+				qcom,mode = "standalone_pc";
+				qcom,latency-us = <500>;
+				qcom,ss-power = <410>;
+				qcom,energy-overhead = <603400>;
+				qcom,time-overhead = <1200>;
+				qcom,use-broadcast-timer;
+			};
+
+			qcom,cpu-modes@2 {
+				qcom,mode = "pc";
+				qcom,latency-us = <550>;
+				qcom,ss-power = <372>;
+				qcom,energy-overhead = <700000>;
+				qcom,time-overhead = <1410>;
+				qcom,use-broadcast-timer;
+			};
 		};
 
-		qcom,lpm-level@1 {
-			reg = <0x1>;
-			qcom,mode = "standalone_pc";
-			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <500>;
-			qcom,ss-power = <410>;
-			qcom,energy-overhead = <603400>;
-			qcom,time-overhead = <1200>;
-		};
+		qcom,system-modes {
+			compatible = "qcom,system-modes";
 
-		qcom,lpm-level@2 {
-			reg = <0x2>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_gdhs";
-			qcom,latency-us = <10700>;
-			qcom,ss-power = <372>;
-			qcom,energy-overhead = <738750>;
-			qcom,time-overhead = <1410>;
-		};
+			qcom,system-modes@0 {
+				qcom,l2 = "l2_cache_gdhs";
+				qcom,latency-us = <10700>;
+				qcom,ss-power = <372>;
+				qcom,energy-overhead = <738750>;
+				qcom,time-overhead = <1410>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 
-		qcom,lpm-level@3 {
-			reg = <0x3>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc_no_rpm";
-			qcom,latency-us = <1000>;
-			qcom,ss-power = <315>;
-			qcom,energy-overhead = <1027150>;
-			qcom,time-overhead = <2400>;
-		};
+			qcom,system-modes@1 {
+				qcom,l2 = "l2_cache_pc_no_rpm";
+				qcom,latency-us = <1000>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "spc";
+				qcom,sync-cpus;
+			};
 
-		qcom,lpm-level@4 {
-			reg = <0x4>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <11000>;
-			qcom,ss-power = <315>;
-			qcom,energy-overhead = <1027150>;
-			qcom,time-overhead = <2400>;
+			qcom,system-modes@2 {
+				qcom,l2 = "l2_cache_pc";
+				qcom,latency-us = <12700>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
index bb866b2..719830e 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -33,18 +33,17 @@
 		<0x44 0x80 0x6a 0x81 0x34 0x82 0x13 0x83 0xffffffff>;
 	};
 
-	i2c@f9925000 { /* BLSP-1 QUP-3 */
+	i2c@f9924000 { /* BLSP-1 QUP-2 */
 		nfc-nci@e {
 			compatible = "qcom,nfc-nci";
 			reg = <0x0e>;
 			qcom,irq-gpio = <&msmgpio 77 0x00>;
 			qcom,dis-gpio = <&msmgpio 93 0x00>;
 			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
-			qcom,clk-src = "GPCLK";
+			qcom,clk-src = "GPCLK2";
 			interrupt-parent = <&msmgpio>;
 			interrupts = <77 0>;
 			qcom,clk-gpio = <&msmgpio 75 0x00>;
-			vlogic-supply = <&pm8110_l14>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8610-v1-pm.dtsi b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
index 62aa0f4..e5aa53c 100644
--- a/arch/arm/boot/dts/msm8610-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v1-pm.dtsi
@@ -111,46 +111,69 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,lpm-level@0 {
-			reg = <0x0>;
-			qcom,mode = "wfi";
-			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <1>;
-			qcom,ss-power = <530>;
-			qcom,energy-overhead = <52800>;
-			qcom,time-overhead = <100>;
+		qcm,cpu-modes {
+			compatible = "qcom,cpu-modes";
+
+			qcom,cpu-modes@0 {
+				qcom,mode = "wfi";
+				qcom,latency-us = <1>;
+				qcom,ss-power = <530>;
+				qcom,energy-overhead = <52800>;
+				qcom,time-overhead = <100>;
+			};
+
+			qcom,cpu-modes@1 {
+				qcom,mode = "standalone_pc";
+				qcom,latency-us = <500>;
+				qcom,ss-power = <410>;
+				qcom,energy-overhead = <603400>;
+				qcom,time-overhead = <1200>;
+				qcom,use-broadcast-timer;
+			};
+
+			qcom,cpu-modes@2 {
+				qcom,mode = "pc";
+				qcom,latency-us = <550>;
+				qcom,ss-power = <372>;
+				qcom,energy-overhead = <700000>;
+				qcom,time-overhead = <1410>;
+				qcom,use-broadcast-timer;
+			};
 		};
 
-		qcom,lpm-level@1 {
-			reg = <0x1>;
-			qcom,mode = "standalone_pc";
-			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <500>;
-			qcom,ss-power = <410>;
-			qcom,energy-overhead = <603400>;
-			qcom,time-overhead = <1410>;
-		};
+		qcom,system-modes {
+			compatible = "qcom,system-modes";
 
-		qcom,lpm-level@2 {
-			reg = <0x2>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc_no_rpm";
-			qcom,latency-us = <1000>;
-			qcom,ss-power = <315>;
-			qcom,energy-overhead = <1027150>;
-			qcom,time-overhead = <2400>;
-		};
+			qcom,system-modes@0 {
+				qcom,l2 = "l2_cache_gdhs";
+				qcom,latency-us = <10700>;
+				qcom,ss-power = <372>;
+				qcom,energy-overhead = <738750>;
+				qcom,time-overhead = <1410>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 
-		qcom,lpm-level@3 {
-			reg = <0x3>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <12700>;
-			qcom,ss-power = <315>;
-			qcom,energy-overhead = <1027150>;
-			qcom,time-overhead = <2400>;
-		};
+			qcom,system-modes@1 {
+				qcom,l2 = "l2_cache_pc_no_rpm";
+				qcom,latency-us = <1000>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "spc";
+				qcom,sync-cpus;
+			};
 
+			qcom,system-modes@2 {
+				qcom,l2 = "l2_cache_pc";
+				qcom,latency-us = <12700>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
+		};
 	};
 
 	qcom,pm-boot {
diff --git a/arch/arm/boot/dts/msm8610-v2-pm.dtsi b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
index e401f7a..c819c49 100644
--- a/arch/arm/boot/dts/msm8610-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-v2-pm.dtsi
@@ -113,54 +113,68 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		qcom,lpm-level@0 {
-			reg = <0x0>;
-			qcom,mode = "wfi";
-			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <1>;
-			qcom,ss-power = <530>;
-			qcom,energy-overhead = <52800>;
-			qcom,time-overhead = <100>;
+		qcm,cpu-modes {
+			compatible = "qcom,cpu-modes";
+
+			qcom,cpu-modes@0 {
+				qcom,mode = "wfi";
+				qcom,latency-us = <1>;
+				qcom,ss-power = <530>;
+				qcom,energy-overhead = <52800>;
+				qcom,time-overhead = <100>;
+			};
+
+			qcom,cpu-modes@1 {
+				qcom,mode = "standalone_pc";
+				qcom,latency-us = <500>;
+				qcom,ss-power = <410>;
+				qcom,energy-overhead = <603400>;
+				qcom,time-overhead = <1200>;
+				qcom,use-broadcast-timer;
+			};
+
+			qcom,cpu-modes@2 {
+				qcom,mode = "pc";
+				qcom,latency-us = <550>;
+				qcom,ss-power = <372>;
+				qcom,energy-overhead = <700000>;
+				qcom,time-overhead = <1410>;
+				qcom,use-broadcast-timer;
+			};
 		};
 
-		qcom,lpm-level@1 {
-			reg = <0x1>;
-			qcom,mode = "standalone_pc";
-			qcom,l2 = "l2_cache_active";
-			qcom,latency-us = <500>;
-			qcom,ss-power = <410>;
-			qcom,energy-overhead = <603400>;
-			qcom,time-overhead = <1200>;
-		};
+		qcom,system-modes {
+			compatible = "qcom,system-modes";
 
-		qcom,lpm-level@2 {
-			reg = <0x2>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_gdhs";
-			qcom,latency-us = <11700>;
-			qcom,ss-power = <372>;
-			qcom,energy-overhead = <738750>;
-			qcom,time-overhead = <1410>;
-		};
+			qcom,system-modes@0 {
+				qcom,l2 = "l2_cache_gdhs";
+				qcom,latency-us = <10700>;
+				qcom,ss-power = <372>;
+				qcom,energy-overhead = <738750>;
+				qcom,time-overhead = <1410>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 
-		qcom,lpm-level@3 {
-			reg = <0x3>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc_no_rpm";
-			qcom,latency-us = <1000>;
-			qcom,ss-power = <315>;
-			qcom,energy-overhead = <1027150>;
-			qcom,time-overhead = <2400>;
-		};
+			qcom,system-modes@1 {
+				qcom,l2 = "l2_cache_pc_no_rpm";
+				qcom,latency-us = <1000>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "spc";
+				qcom,sync-cpus;
+			};
 
-		qcom,lpm-level@4 {
-			reg = <0x4>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <12700>;
-			qcom,ss-power = <315>;
-			qcom,energy-overhead = <1027150>;
-			qcom,time-overhead = <2400>;
+			qcom,system-modes@2 {
+				qcom,l2 = "l2_cache_pc";
+				qcom,latency-us = <12700>;
+				qcom,ss-power = <315>;
+				qcom,energy-overhead = <1027150>;
+				qcom,time-overhead = <2400>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 26efa78..908b8e4 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -529,6 +529,21 @@
                 qcom,master-id = <86>;
 	};
 
+
+	i2c@f9924000 { /* BLSP-1 QUP-3 */
+		cell-index = <2>;
+		compatible = "qcom,i2c-qup";
+		reg-names = "qup_phys_addr";
+		reg = <0xf9924000 0x1000>;
+		interrupt-names = "qup_err_intr";
+		interrupts = <0 96 0>;
+		qcom,i2c-bus-freq = <100000>;
+		qcom,i2c-src-freq = <19200000>;
+		qcom,sda-gpio = <&msmgpio 8 0>;
+		qcom,scl-gpio = <&msmgpio 9 0>;
+		qcom,master-id = <86>;
+	};
+
 	i2c@f9925000 { /* BLSP-1 QUP-3 */
 		cell-index = <0>;
 		compatible = "qcom,i2c-qup";
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index eba053f..e2d40f7 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -130,68 +130,65 @@
 		compatible = "qcom,lpm-levels";
 		qcom,default-l2-state = "l2_cache_retention";
 		#address-cells = <1>;
-		#size-cells = <0>;
+		#size-cells = <1>;
 
-		qcom,lpm-level@0 {
-			reg = <0x0>;
-			qcom,mode = "wfi";
-			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <1>;
-			qcom,ss-power = <715>;
-			qcom,energy-overhead = <17700>;
-			qcom,time-overhead = <2>;
+		qcom,cpu-modes {
+			compatible = "qcom,cpu-modes";
+			qcom,cpu-mode@0 {
+				qcom,mode = "wfi";
+				qcom,latency-us = <1>;
+				qcom,ss-power = <715>;
+				qcom,energy-overhead = <17700>;
+				qcom,time-overhead = <2>;
+			};
+
+			qcom,cpu-mode@1 {
+				qcom,mode = "retention";
+				qcom,latency-us = <35>;
+				qcom,ss-power = <542>;
+				qcom,energy-overhead = <34920>;
+				qcom,time-overhead = <40>;
+			};
+
+			qcom,cpu-mode@2 {
+				qcom,mode = "standalone_pc";
+				qcom,latency-us = <300>;
+				qcom,ss-power = <476>;
+				qcom,energy-overhead = <225300>;
+				qcom,time-overhead = <350>;
+			};
+
+			qcom,cpu-mode@3 {
+				qcom,mode = "pc";
+				qcom,latency-us = <500>;
+				qcom,ss-power = <400>;
+				qcom,energy-overhead = <280000>;
+				qcom,time-overhead = <500>;
+			};
+
 		};
+		qcom,system-modes {
+			compatible = "qcom,system-modes";
 
-		qcom,lpm-level@1 {
-			reg = <0x1>;
-			qcom,mode = "retention";
-			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <35>;
-			qcom,ss-power = <542>;
-			qcom,energy-overhead = <34920>;
-			qcom,time-overhead = <40>;
-		};
+			qcom,system-mode@0 {
+				qcom,l2 = "l2_cache_gdhs";
+				qcom,latency-us = <20000>;
+				qcom,ss-power = <163>;
+				qcom,energy-overhead = <1577736>;
+				qcom,time-overhead = <5067>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 
-
-		qcom,lpm-level@2 {
-			reg = <0x2>;
-			qcom,mode = "standalone_pc";
-			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <300>;
-			qcom,ss-power = <476>;
-			qcom,energy-overhead = <225300>;
-			qcom,time-overhead = <350>;
-		};
-
-		qcom,lpm-level@3 {
-			reg = <0x3>;
-			qcom,mode = "standalone_pc";
-			qcom,l2 = "l2_cache_gdhs";
-			qcom,latency-us = <320>;
-			qcom,ss-power = <476>;
-			qcom,energy-overhead = <225300>;
-			qcom,time-overhead = <375>;
-		};
-
-		qcom,lpm-level@4 {
-			reg = <0x4>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_gdhs";
-			qcom,gpio-detectable;
-			qcom,latency-us = <20000>;
-			qcom,ss-power = <163>;
-			qcom,energy-overhead = <1577736>;
-			qcom,time-overhead = <5067>;
-		};
-
-		qcom,lpm-level@5 {
-			reg = <0x5>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <30000>;
-			qcom,ss-power = <83>;
-			qcom,energy-overhead = <2274420>;
-			qcom,time-overhead = <6605>;
+			qcom,system-mode@1 {
+				qcom,l2 = "l2_cache_pc";
+				qcom,latency-us = <30000>;
+				qcom,ss-power = <83>;
+				qcom,energy-overhead = <2274420>;
+				qcom,time-overhead = <6605>;
+				qcom,min-cpu-mode = "pc";
+				qcom,sync-cpus;
+			};
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
index 5769446..366faef 100644
--- a/arch/arm/boot/dts/msm8974pro-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -128,60 +128,69 @@
 
 	qcom,lpm-levels {
 		compatible = "qcom,lpm-levels";
+		qcom,allow-synced-levels;
 		qcom,default-l2-state = "l2_cache_retention";
 		#address-cells = <1>;
-		#size-cells = <0>;
+		#size-cells = <1>;
 
-		qcom,lpm-level@0 {
-			reg = <0x0>;
-			qcom,mode = "wfi";
-			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <1>;
-			qcom,ss-power = <715>;
-			qcom,energy-overhead = <17700>;
-			qcom,time-overhead = <2>;
+		qcom,cpu-modes {
+			compatible = "qcom,cpu-modes";
+			qcom,cpu-mode@0 {
+				qcom,mode = "wfi";
+				qcom,latency-us = <1>;
+				qcom,ss-power = <715>;
+				qcom,energy-overhead = <17700>;
+				qcom,time-overhead = <2>;
+			};
+
+			qcom,cpu-mode@1 {
+				qcom,mode = "retention";
+				qcom,latency-us = <35>;
+				qcom,ss-power = <542>;
+				qcom,energy-overhead = <34920>;
+				qcom,time-overhead = <40>;
+			};
+
+			qcom,cpu-mode@2 {
+				qcom,mode = "standalone_pc";
+				qcom,latency-us = <300>;
+				qcom,ss-power = <476>;
+				qcom,energy-overhead = <225300>;
+				qcom,time-overhead = <350>;
+			};
+
+			qcom,cpu-mode@3 {
+				qcom,mode = "pc";
+				qcom,latency-us = <500>;
+				qcom,ss-power = <400>;
+				qcom,energy-overhead = <280000>;
+				qcom,time-overhead = <500>;
+				qcom,use-broadcast-timer;
+			};
+
 		};
+		qcom,system-modes {
+			compatible = "qcom,system-modes";
 
-		qcom,lpm-level@1 {
-			reg = <0x1>;
-			qcom,mode = "retention";
-			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <35>;
-			qcom,ss-power = <542>;
-			qcom,energy-overhead = <34920>;
-			qcom,time-overhead = <40>;
-		};
+			qcom,system-mode@0 {
+				qcom,l2 = "l2_cache_gdhs";
+				qcom,latency-us = <20000>;
+				qcom,ss-power = <163>;
+				qcom,energy-overhead = <1577736>;
+				qcom,time-overhead = <5067>;
+				qcom,min-cpu-mode= "pc";
+				qcom,sync-cpus;
+			};
 
-
-		qcom,lpm-level@2 {
-			reg = <0x2>;
-			qcom,mode = "standalone_pc";
-			qcom,l2 = "l2_cache_retention";
-			qcom,latency-us = <300>;
-			qcom,ss-power = <476>;
-			qcom,energy-overhead = <225300>;
-			qcom,time-overhead = <350>;
-		};
-
-		qcom,lpm-level@3 {
-			reg = <0x3>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_gdhs";
-			qcom,gpio-detectable;
-			qcom,latency-us = <20000>;
-			qcom,ss-power = <163>;
-			qcom,energy-overhead = <1577736>;
-			qcom,time-overhead = <5067>;
-		};
-
-		qcom,lpm-level@4 {
-			reg = <0x4>;
-			qcom,mode = "pc";
-			qcom,l2 = "l2_cache_pc";
-			qcom,latency-us = <30000>;
-			qcom,ss-power = <83>;
-			qcom,energy-overhead = <2274420>;
-			qcom,time-overhead = <6605>;
+			qcom,system-mode@1 {
+				qcom,l2 = "l2_cache_pc";
+				qcom,latency-us = <30000>;
+				qcom,ss-power = <83>;
+				qcom,energy-overhead = <2274420>;
+				qcom,time-overhead = <6605>;
+				qcom,min-cpu-mode = "pc";
+				qcom,sync-cpus;
+			};
 		};
 	};
 
@@ -313,7 +322,6 @@
 		ranges;
 		reg = <0xfe805664 0x40>;
 		qcom,pc-mode = "tz_l2_int";
-		qcom,use-sync-timer;
 		qcom,cpus-as-clocks;
 
 		qcom,pm-snoc-client {
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index dac2286..c5aa51a 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -270,6 +270,7 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 9d4d37b..f4ee78d 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -271,6 +271,7 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index c5f0ddd..87b5648 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -81,6 +81,7 @@
 CONFIG_AEABI=y
 CONFIG_COMPACTION=y
 CONFIG_CC_STACKPROTECTOR=y
+CONFIG_KSM=y
 CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -246,6 +247,7 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 303e911..88906aa 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -82,6 +82,7 @@
 CONFIG_AEABI=y
 CONFIG_COMPACTION=y
 CONFIG_CC_STACKPROTECTOR=y
+CONFIG_KSM=y
 CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -248,6 +249,7 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 731538f..76117b0 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -299,6 +299,7 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 67ceaed..b57504c 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -307,6 +307,7 @@
 CONFIG_DIAG_CHAR=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MSM=y
+CONFIG_MSM_ADSPRPC=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QUP=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 9ba1436..0e8f4916 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -49,6 +49,13 @@
  *
  *		Unconditionally clean and invalidate the entire cache.
  *
+ *     flush_kern_louis()
+ *
+ *             Flush data cache levels up to the level of unification
+ *             inner shareable and invalidate the I-cache.
+ *             Only needed from v7 onwards, falls back to flush_cache_all()
+ *             for all other processor versions.
+ *
  *	flush_user_all()
  *
  *		Clean and invalidate all user space cache entries
@@ -112,6 +119,7 @@
 struct cpu_cache_fns {
 	void (*flush_icache_all)(void);
 	void (*flush_kern_all)(void);
+	void (*flush_kern_louis)(void);
 	void (*flush_user_all)(void);
 	void (*flush_user_range)(unsigned long, unsigned long, unsigned int);
 
@@ -136,6 +144,7 @@
 
 #define __cpuc_flush_icache_all		cpu_cache.flush_icache_all
 #define __cpuc_flush_kern_all		cpu_cache.flush_kern_all
+#define __cpuc_flush_kern_louis		cpu_cache.flush_kern_louis
 #define __cpuc_flush_user_all		cpu_cache.flush_user_all
 #define __cpuc_flush_user_range		cpu_cache.flush_user_range
 #define __cpuc_coherent_kern_range	cpu_cache.coherent_kern_range
@@ -158,6 +167,7 @@
 
 extern void __cpuc_flush_icache_all(void);
 extern void __cpuc_flush_kern_all(void);
+extern void __cpuc_flush_kern_louis(void);
 extern void __cpuc_flush_user_all(void);
 extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);
 extern void __cpuc_coherent_kern_range(unsigned long, unsigned long);
@@ -225,6 +235,11 @@
 	__flush_icache_preferred();
 }
 
+/*
+ * Flush caches up to Level of Unification Inner Shareable
+ */
+#define flush_cache_louis()		__cpuc_flush_kern_louis()
+
 #define flush_cache_all()		__cpuc_flush_kern_all()
 
 static inline void vivt_flush_cache_mm(struct mm_struct *mm)
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index 7e30874..2d6a7de 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -132,6 +132,7 @@
 #ifndef MULTI_CACHE
 #define __cpuc_flush_icache_all		__glue(_CACHE,_flush_icache_all)
 #define __cpuc_flush_kern_all		__glue(_CACHE,_flush_kern_cache_all)
+#define __cpuc_flush_kern_louis		__glue(_CACHE,_flush_kern_cache_louis)
 #define __cpuc_flush_user_all		__glue(_CACHE,_flush_user_cache_all)
 #define __cpuc_flush_user_range		__glue(_CACHE,_flush_user_cache_range)
 #define __cpuc_coherent_kern_range	__glue(_CACHE,_coherent_kern_range)
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 92e4f18..8c0a923 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -480,7 +480,7 @@
 	if (!clk)
 		return -ENOMEM;
 
-	clk->features = CLOCK_EVT_FEAT_ONESHOT;
+	clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
 	clk->name = "arch_mem_timer";
 	clk->rating = 400;
 	clk->set_mode = arch_timer_set_mode_mem;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index c0f6b10..4b8d443 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -266,7 +266,7 @@
 	select MSM_L2_SPM
 	select MSM_NATIVE_RESTART
 	select MSM_RESTART_V2
-	select MSM_PM8X60 if PM
+	select MSM_PM if PM
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select MSM_RPM_SMD
@@ -297,7 +297,7 @@
 	select MULTI_IRQ_HANDLER
 	select MSM_NATIVE_RESTART
 	select MSM_RESTART_V2
-	select MSM_PM8X60 if PM
+	select MSM_PM if PM
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select REGULATOR
@@ -308,7 +308,6 @@
 	select QMI_ENCDEC
 	select MSM_SPM_V2
 	select MSM_L2_SPM
-	select MSM_PM8X60 if PM
 	select MSM_RPM_SMD
 	select ENABLE_VMALLOC_SAVINGS
 
@@ -428,7 +427,7 @@
 	select MSM_NATIVE_RESTART
 	select MSM_RESTART_V2
 	select MSM_SPM_V2
-	select MSM_PM8X60 if PM
+	select MSM_PM if PM
 	select MULTI_IRQ_HANDLER
 	select GPIO_MSM_V3
 	select MAY_HAVE_SPARSE_IRQ
@@ -459,7 +458,7 @@
 	select MSM_RPM_SMD
 	select MSM_SPM_V2
 	select MSM_L2_SPM
-	select MSM_PM8X60 if PM
+	select MSM_PM if PM
 	select MEMORY_HOLE_CARVEOUT
 	select MSM_BUS_SCALING
 	select MSM_CORTEX_A7
@@ -500,7 +499,7 @@
 	select MSM_RPM_SMD
 	select MSM_SPM_V2
 	select MSM_L2_SPM
-	select MSM_PM8X60 if PM
+	select MSM_PM if PM
 	select MEMORY_HOLE_CARVEOUT
 	select MSM_BUS_SCALING
 	select MSM_CORTEX_A7
@@ -533,7 +532,7 @@
 	select MSM_L2_SPM
 	select MSM_NATIVE_RESTART
 	select MSM_RESTART_V2
-	select MSM_PM8X60 if PM
+	select MSM_PM if PM
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select ARM_HAS_SG_CHAIN
@@ -661,7 +660,7 @@
 config MSM_LPM_TEST
 	bool "Low Power Mode test framework"
 	depends on MSM_RPM || MSM_RPM_SMD
-	depends on MSM_PM8X60
+	depends on MSM_PM
 	help
 	  LPM_TEST is a test framework that assists in exercising the low
 	  power mode algorithm on MSM targets. This test framework tracks
@@ -2437,7 +2436,7 @@
 	depends on PM
 	bool
 
-config MSM_PM8X60
+config MSM_PM
 	depends on PM
 	bool
 
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index d269e92..4fc1590 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -207,7 +207,7 @@
 endif
 obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
 
-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+#obj-$(CONFIG_CPU_IDLE) += cpuidle.o
 
 ifdef CONFIG_MSM_CAMERA_V4L2
 	obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-camera.o
@@ -311,7 +311,7 @@
 obj-$(CONFIG_ARCH_MSM8610) += clock-dsi-8610.o
 obj-$(CONFIG_ARCH_MSMKRYPTON) += clock-local2.o clock-pll.o clock-krypton.o clock-rpm.o clock-voter.o
 
-obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
+obj-$(CONFIG_MSM_PM) += msm-pm.o pm-data.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire-keypad.o board-sapphire-panel.o
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index b5ea3a5..03f8837 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -252,6 +252,30 @@
 	},
 };
 
+static struct gpiomux_setting gpio_i2c_nfc_pvt_config = {
+		.func = GPIOMUX_FUNC_5, /*active 1*/ /* 0 */
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	};
+
+static struct msm_gpiomux_config msm_nfc_configs[] __initdata = {
+	{
+		.gpio   = 8,            /* BLSP1 QUP2 I2C_SDA */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_nfc_pvt_config,
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_nfc_pvt_config,
+		},
+	},
+	{
+		.gpio   = 9,            /* BLSP1 QUP2 I2C_SCL */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &gpio_i2c_nfc_pvt_config,
+			[GPIOMUX_SUSPENDED] = &gpio_i2c_nfc_pvt_config,
+		},
+	},
+};
+
+
 static struct msm_gpiomux_config msm_atmel_configs[] __initdata = {
 	{
 		.gpio      = 0,		/* TOUCH RESET */
@@ -427,6 +451,16 @@
 	},
 };
 
+static struct msm_gpiomux_config msm_non_qrd_configs[] __initdata = {
+	{
+		.gpio = 8, /* CAM1_STANDBY_N */
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+		},
+	},
+};
+
 static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
 	{
 		.gpio = 13, /* CAM_MCLK0 */
@@ -625,7 +659,13 @@
 	msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
 	msm_gpiomux_install(msm_gpio_int_configs,
 			ARRAY_SIZE(msm_gpio_int_configs));
-	if (of_board_is_qrd())
+	if (of_board_is_qrd()) {
 		msm_gpiomux_install(msm_interrupt_configs,
 			ARRAY_SIZE(msm_interrupt_configs));
+		msm_gpiomux_install(msm_nfc_configs,
+			ARRAY_SIZE(msm_nfc_configs));
+	} else {
+		msm_gpiomux_install(msm_non_qrd_configs,
+			ARRAY_SIZE(msm_non_qrd_configs));
+	}
 }
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 665c040..dcc7c76 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2893,12 +2893,13 @@
 	CLK_LOOKUP("core_clk_src",          sdcc2_apps_clk_src.c, ""),
 	CLK_LOOKUP("core_clk_src",       usb_hs_system_clk_src.c, ""),
 	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9923000.i2c"),
+	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9924000.i2c"),
 	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
 	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9927000.i2c"),
 	CLK_LOOKUP("iface_clk",           gcc_blsp1_ahb_clk.c, "f9926000.spi"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup1_i2c_apps_clk.c, "f9923000.i2c"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup1_spi_apps_clk.c, ""),
-	CLK_LOOKUP("core_clk",  gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+	CLK_LOOKUP("core_clk",  gcc_blsp1_qup2_i2c_apps_clk.c, "f9924000.i2c"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup2_spi_apps_clk.c, ""),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
 	CLK_LOOKUP("core_clk",  gcc_blsp1_qup3_spi_apps_clk.c, ""),
@@ -2923,6 +2924,7 @@
 	CLK_LOOKUP("iface_clk",       gcc_copss_smmu_ahb_clk.c, ""),
 	CLK_LOOKUP("iface_clk",        gcc_lpss_smmu_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk",                  gcc_gp1_clk.c, "0-000e"),
+	CLK_LOOKUP("core_clk_pvt",              gcc_gp1_clk.c, "2-000e"),
 	CLK_LOOKUP("core_clk",                  gcc_gp2_clk.c, ""),
 	CLK_LOOKUP("core_clk",                  gcc_gp3_clk.c, ""),
 	CLK_LOOKUP("core_clk",         gcc_lpass_q6_axi_clk.c, ""),
diff --git a/arch/arm/mach-msm/clock-krait-8974.c b/arch/arm/mach-msm/clock-krait-8974.c
index 6ada01f..24fe303 100644
--- a/arch/arm/mach-msm/clock-krait-8974.c
+++ b/arch/arm/mach-msm/clock-krait-8974.c
@@ -732,8 +732,8 @@
 	 * that the clocks have already been prepared and enabled by the time
 	 * they take over.
 	 */
-	clk_prepare_enable(&l2_clk.c);
 	for_each_online_cpu(cpu) {
+		clk_prepare_enable(&l2_clk.c);
 		WARN(clk_prepare_enable(cpu_clk[cpu]),
 			"Unable to turn on CPU%d clock", cpu);
 	}
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 85a1468..60856c2 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -324,11 +324,15 @@
 	case CPU_UP_CANCELED:
 		if (is_clk) {
 			clk_disable_unprepare(cpu_clk[cpu]);
+			clk_disable_unprepare(l2_clk);
 			update_l2_bw(NULL);
 		}
 		break;
 	case CPU_UP_PREPARE:
 		if (is_clk) {
+			rc = clk_prepare_enable(l2_clk);
+			if (rc < 0)
+				return NOTIFY_BAD;
 			rc = clk_prepare_enable(cpu_clk[cpu]);
 			if (rc < 0)
 				return NOTIFY_BAD;
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 20e3c3b..174a50a 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -11,6 +11,7 @@
 #include <linux/errno.h>
 #include <linux/smp.h>
 #include <linux/cpu.h>
+#include <linux/ratelimit.h>
 
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
@@ -150,6 +151,29 @@
 	.notifier_call = hotplug_rtb_callback,
 };
 
+static int hotplug_cpu_check_callback(struct notifier_block *nfb,
+				      unsigned long action, void *hcpu)
+{
+	int cpu = (int)hcpu;
+
+	switch (action & (~CPU_TASKS_FROZEN)) {
+	case CPU_DOWN_PREPARE:
+		if (cpu == 0) {
+			pr_err_ratelimited("CPU0 hotplug is not supported\n");
+			return NOTIFY_BAD;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+static struct notifier_block hotplug_cpu_check_notifier = {
+	.notifier_call = hotplug_cpu_check_callback,
+	.priority = INT_MAX,
+};
+
 int msm_platform_secondary_init(unsigned int cpu)
 {
 	int ret;
@@ -170,6 +194,12 @@
 
 static int __init init_hotplug(void)
 {
-	return register_hotcpu_notifier(&hotplug_rtb_notifier);
+	int rc;
+
+	rc = register_hotcpu_notifier(&hotplug_rtb_notifier);
+	if (rc)
+		return rc;
+
+	return register_hotcpu_notifier(&hotplug_cpu_check_notifier);
 }
 early_initcall(init_hotplug);
diff --git a/arch/arm/mach-msm/idle-macros.S b/arch/arm/mach-msm/idle-macros.S
deleted file mode 100644
index 3d0c937..0000000
--- a/arch/arm/mach-msm/idle-macros.S
+++ /dev/null
@@ -1,153 +0,0 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <asm/hardware/cache-l2x0.h>
-
-/* Add 300 NOPs after 'wfi' for 8x25 target */
-.macro DELAY_8x25, rept
-#ifdef CONFIG_ARCH_MSM8625
-	.rept   \rept
-	nop
-	.endr
-#endif
-.endm
-
-/* Switch between smp_to_amp/amp_to_smp configuration */
-.macro SET_SMP_COHERENCY, on = 0
-	ldr     r0, =target_type
-	ldr     r0, [r0]
-	mov     r1, #TARGET_IS_8625
-	cmp     r0, r1
-	bne     skip\@
-	mrc	p15, 0, r0, c1, c0, 1	/* read ACTLR register */
-	.if     \on
-	orr	r0, r0, #(1 << 6)	/* Set the SMP bit in ACTLR */
-	.else
-	bic	r0, r0, #(1 << 6)	/* Clear the SMP bit */
-	.endif
-	mcr	p15, 0, r0, c1, c0, 1	/* write ACTLR register */
-	isb
-skip\@:
-.endm
-
-/*
- * Enable the "L2" cache, not require to restore the controller registers
- */
-.macro ENABLE_8x25_L2
-	ldr     r0, =target_type
-	ldr     r0, [r0]
-	mov     r1, #TARGET_IS_8625
-	cmp     r0, r1
-	bne     skip_enable\@
-	ldr     r0, =apps_power_collapse
-	ldr     r0, [r0]
-	cmp     r0, #POWER_COLLAPSED
-	bne     skip_enable\@
-	ldr     r0, =l2x0_base_addr
-	ldr	r0, [r0]
-	mov	r1, #0x1
-	str	r1, [r0, #L2X0_CTRL]
-	dmb
-skip_enable\@:
-.endm
-
-/*
- * Perform the required operation
- * operation: type of operation on l2 cache (e.g: clean&inv or inv)
- * l2_enable: enable or disable
- */
-.macro DO_CACHE_OPERATION, operation, l2_enable
-	ldr     r2, =l2x0_base_addr
-	ldr	r2, [r2]
-	ldr     r0, =0xffff
-	str     r0, [r2, #\operation]
-wait\@:
-	ldr	r0, [r2, #\operation]
-	ldr	r1, =0xffff
-	ands    r0, r0, r1
-	bne     wait\@
-l2x_sync\@:
-	mov	r0, #0x0
-	str	r0, [r2, #L2X0_CACHE_SYNC]
-sync\@:
-	ldr	r0, [r2, #L2X0_CACHE_SYNC]
-	ands	r0, r0, #0x1
-	bne	sync\@
-	mov     r1, #\l2_enable
-	str     r1, [r2, #L2X0_CTRL]
-.endm
-
-/*
- * Clean and invalidate the L2 cache.
- * 1. Check the target type
- * 2. Check whether we are coming from PC are not
- * 3. Save 'aux', 'data latency', & 'prefetch ctlr' registers
- * 4. Start L2 clean & invalidation operation
- * 5. Disable the L2 cache
- */
-.macro SUSPEND_8x25_L2
-	ldr     r0, =target_type
-	ldr     r0, [r0]
-	mov     r1, #TARGET_IS_8625
-	cmp     r0, r1
-	bne     skip_suspend\@
-	ldr	r0, =apps_power_collapse
-	ldr	r0, [r0]
-	cmp	r0, #POWER_COLLAPSED
-	bne	skip_suspend\@
-	ldr	r0, =l2x0_saved_ctrl_reg_val
-	ldr	r1, =l2x0_base_addr
-	ldr	r1, [r1]
-	ldr	r2, [r1, #L2X0_AUX_CTRL]
-	str	r2, [r0, #0x0] /* store aux_ctlr reg value */
-	ldr     r2, [r1, #L2X0_DATA_LATENCY_CTRL]
-	str     r2, [r0, #0x4] /* store data latency reg value */
-	ldr     r2, [r1, #L2X0_PREFETCH_CTRL]
-	str     r2, [r0, #0x8] /* store prefetch_ctlr reg value */
-	DO_CACHE_OPERATION L2X0_CLEAN_INV_WAY OFF
-	dmb
-skip_suspend\@:
-.endm
-
-/*
- * Coming back from a successful PC
- * 1. Check the target type
- * 2. Check whether we are going to PC are not
- * 3. Disable the L2 cache
- * 4. Restore 'aux', 'data latency', & 'prefetch ctlr' reg
- * 5. Invalidate the cache
- * 6. Enable the L2 cache
- */
-.macro RESUME_8x25_L2
-	ldr     r0, =target_type
-	ldr     r0, [r0]
-	mov     r1, #TARGET_IS_8625
-	cmp     r0, r1
-	bne     skip_resume\@
-	ldr	r0, =apps_power_collapse
-	ldr	r0, [r0]
-	cmp	r0, #POWER_COLLAPSED
-	bne	skip_resume\@
-	ldr     r1, =l2x0_base_addr
-	ldr	r1, [r1]
-	mov     r0, #0x0
-	str     r0, [r1, #L2X0_CTRL]
-	ldr     r0, =l2x0_saved_ctrl_reg_val
-	ldr     r2, [r0, #0x0]
-	str	r2, [r1, #L2X0_AUX_CTRL] /* restore aux_ctlr reg value */
-	ldr	r2, [r0, #0x4]
-	str	r2, [r1, #L2X0_DATA_LATENCY_CTRL]
-	ldr	r2, [r0, #0x8]
-	str     r2, [r1, #L2X0_PREFETCH_CTRL]
-	DO_CACHE_OPERATION L2X0_INV_WAY ON
-skip_resume\@:
-.endm
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 2956bd6..a133470 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -19,357 +19,7 @@
 #include <linux/threads.h>
 #include <asm/assembler.h>
 
-#include "idle.h"
-#include "idle-macros.S"
-
-#ifdef CONFIG_MSM_SCM
-#define SCM_SVC_BOOT 0x1
-#define SCM_CMD_TERMINATE_PC 0x2
-#define SCM_CMD_CORE_HOTPLUGGED 0x10
-#endif
-
-ENTRY(msm_arch_idle)
-#ifdef CONFIG_ARCH_MSM_KRAIT
-	mrc 	p15, 0, r0, c0, c0, 0
-	bic	r1, r0, #0xff
-	movw	r2, #0x0400
-	movt	r2, #0x511F
-	movw	r3, #0x0600
-	movt	r3, #0x510F
-	cmp	r2, r1
-	cmpne	r3, r1
-	bne	go_wfi
-
-	mrs	r0, cpsr
-	cpsid	if
-
-	mrc	p15, 7, r1, c15, c0, 5
-	bic	r2, r1, #0x20000
-	mcr	p15, 7, r2, c15, c0, 5
-	isb
-
-go_wfi:
-	wfi
-	bne	wfi_done
-	mcr	p15, 7, r1, c15, c0, 5
-	isb
-	msr	cpsr_c, r0
-
-wfi_done:
-	bx	lr
-#else
-	wfi
-#ifdef CONFIG_ARCH_MSM8X60
-	mrc	p14, 1, r1, c1, c5, 4 /* read ETM PDSR to clear sticky bit */
-	mrc     p14, 0, r1, c1, c5, 4 /* read DBG PRSR to clear sticky bit */
-	isb
-#endif
-	bx	lr
-#endif
-ENTRY(msm_pm_pc_hotplug)
-	stmfd	sp!, {lr}
-#if defined(CONFIG_MSM_FIQ_SUPPORT)
-	cpsid   f
-#endif
-
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
-	bl      msm_jtag_save_state
-#endif
-	mov	r1, #0
-	mcr	p15, 2, r1, c0, c0, 0 /*CCSELR*/
-	isb
-	mrc	p15, 1, r1, c0, c0, 0 /*CCSIDR*/
-	mov	r2, #1
-	and	r1, r2, r1, ASR #30 /* Check if the cache is write back */
-	cmp	r1, #1
-	bleq	v7_flush_kern_cache_all
-
-	mrc	p15, 0, r0, c0, c0, 5	/* MPIDR */
-	and	r0, r0, #15		/* what CPU am I */
-
-	ldr	r1, =msm_pc_debug_counters /*load the IMEM debug location */
-	ldr	r1, [r1]
-	cmp	r1, #0
-	beq	skip_hp_debug1
-	add	r1, r1, r0, LSL #4	/* debug location for this CPU */
-	ldr	r2, [r1]
-	add	r2, #1
-	str	r2, [r1]
-skip_hp_debug1:
-
-#ifdef CONFIG_MSM_SCM
-	ldr	r0, =SCM_SVC_BOOT
-	ldr	r1, =SCM_CMD_TERMINATE_PC
-	ldr	r2, =SCM_CMD_CORE_HOTPLUGGED
-	bl	scm_call_atomic1
-#else
-	mrc     p15, 0, r3, c1, c0, 0    /* read current CR    */
-	bic     r0, r3, #(1 << 2)        /* clear dcache bit   */
-	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
-	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
-	isb
-	wfi
-	mcr     p15, 0, r3, c1, c0, 0    /* restore d/i cache  */
-	isb
-#endif
-
-#if defined(CONFIG_MSM_FIQ_SUPPORT)
-	cpsie   f
-#endif
-	mrc	p15, 0, r0, c0, c0, 5 /* MPIDR */
-	and	r0, r0, #15              /* what CPU am I                  */
-
-	ldr	r1, =msm_pc_debug_counters /*load the IMEM debug location */
-	ldr	r1, [r1]
-	cmp	r1, #0
-	beq	skip_hp_debug2
-	add	r1, r1, r0, LSL #4	/* debug location for this CPU */
-	add	r1, #8
-	ldr	r2, [r1]
-	add	r2, #1
-	str	r2, [r1]
-skip_hp_debug2:
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
-	bl	msm_jtag_restore_state
-#endif
-	mov     r0, #0                   /* return power collapse failed */
-	ldmfd	sp!, {lr}
-	bx      lr
-
-ENTRY(msm_pm_collapse)
-#if defined(CONFIG_MSM_FIQ_SUPPORT)
-	cpsid   f
-#endif
-
-	ldr     r0, =msm_saved_state	/* address of msm_saved_state ptr */
-	ldr	r0, [r0]		/* load ptr */
-#if (NR_CPUS >= 2)
-	mrc	p15, 0, r1, c0, c0, 5	/* MPIDR */
-	ands	r1, r1, #15		/* What CPU am I */
-	mov	r2, #CPU_SAVED_STATE_SIZE
-	mul	r1, r1, r2
-	add	r0, r0, r1
-#endif
-
-	stmia   r0!, {r4-r14}
-	mrc     p15, 0, r1, c1, c0, 0 /* MMU control */
-	mrc     p15, 0, r2, c2, c0, 0 /* TTBR0 */
-	mrc     p15, 0, r3, c3, c0, 0 /* dacr */
-#ifdef CONFIG_ARCH_MSM_SCORPION
-	/* This instruction is not valid for non scorpion processors */
-	mrc     p15, 3, r4, c15, c0, 3 /* L2CR1 is the L2 cache control reg 1 */
-#endif
-	mrc     p15, 0, r5, c10, c2, 0 /* PRRR */
-	mrc     p15, 0, r6, c10, c2, 1 /* NMRR */
-	mrc     p15, 0, r7, c1, c0, 1 /* ACTLR */
-	mrc     p15, 0, r8, c2, c0, 1 /* TTBR1 */
-	mrc     p15, 0, r9, c13, c0, 3 /* TPIDRURO */
-	mrc     p15, 0, ip, c13, c0, 1 /* context ID */
-	stmia   r0!, {r1-r9, ip}
-
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
-	bl      msm_jtag_save_state
-#endif
-
-	ldr	r0, =msm_pm_flush_l2_flag
-	ldr	r0, [r0]
-	mov	r1, #0
-	mcr	p15, 2, r1, c0, c0, 0 /*CCSELR*/
-	isb
-	mrc	p15, 1, r1, c0, c0, 0 /*CCSIDR*/
-	mov	r2, #1
-	and	r1, r2, r1, ASR #30 /* Check if the cache is write back */
-	orr	r1, r0, r1
-	and	r1, r1, #1
-	cmp	r1, #1
-	bne	skip
-	bl	v7_flush_dcache_all
-	ldr	r1, =msm_pm_flush_l2_fn
-	ldr	r1, [r1]
-	cmp	r1, #0
-	blxne	r1
-
-skip:
-	ldr	r1, =msm_pm_disable_l2_fn
-	ldr	r1, [r1]
-	cmp	r1, #0
-	blxne	r1
-	dmb
-
-	mrc	p15, 0, r0, c0, c0, 5	/* MPIDR */
-	and	r0, r0, #15		/* what CPU am I */
-
-	ldr	r1, =msm_pc_debug_counters /*load the IMEM debug location */
-	ldr	r1, [r1]
-	cmp	r1, #0
-	beq	skip_pc_debug1
-	add	r1, r1, r0, LSL #4	/* debug location for this CPU */
-	ldr	r2, [r1]
-	add	r2, #1
-	str	r2, [r1]
-skip_pc_debug1:
-
-#ifdef CONFIG_MSM_SCM
-	ldr	r0, =SCM_SVC_BOOT
-	ldr	r1, =SCM_CMD_TERMINATE_PC
-	ldr	r2, =msm_pm_flush_l2_flag
-	ldr	r2, [r2]
-	bl	scm_call_atomic1
-#else
-	mrc     p15, 0, r4, c1, c0, 0    /* read current CR    */
-	bic     r0, r4, #(1 << 2)        /* clear dcache bit   */
-	bic     r0, r0, #(1 << 12)       /* clear icache bit   */
-	mcr     p15, 0, r0, c1, c0, 0    /* disable d/i cache  */
-	isb
-
-	SUSPEND_8x25_L2
-	SET_SMP_COHERENCY OFF
-	wfi
-	DELAY_8x25 300
-
-	mcr     p15, 0, r4, c1, c0, 0    /* restore d/i cache  */
-	isb
-	ENABLE_8x25_L2 /* enable only l2, no need to restore the reg back */
-	SET_SMP_COHERENCY ON
-#endif
-
-#if defined(CONFIG_MSM_FIQ_SUPPORT)
-	cpsie   f
-#endif
-	mrc	p15, 0, r0, c0, c0, 5 /* MPIDR */
-	and	r0, r0, #15              /* what CPU am I                  */
-
-	ldr	r1, =msm_pc_debug_counters /*load the IMEM debug location */
-	ldr	r1, [r1]
-	cmp	r1, #0
-	beq	skip_pc_debug2
-	add	r1, r1, r0, LSL #4	/* debug location for this CPU */
-	add	r1, #8
-	ldr	r2, [r1]
-	add	r2, #1
-	str	r2, [r1]
-
-skip_pc_debug2:
-	ldr	r1, =msm_pm_enable_l2_fn
-	ldr	r1, [r1]
-	cmp	r1, #0
-	blxne	r1
-	dmb
-
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
-	bl	msm_jtag_restore_state
-#endif
-	ldr     r0, =msm_saved_state	/* address of msm_saved_state ptr */
-	ldr	r0, [r0]		/* load ptr */
-#if (NR_CPUS >= 2)
-	mrc	p15, 0, r1, c0, c0, 5	/* MPIDR */
-	ands	r1, r1, #15		/* What CPU am I */
-	mov	r2, #CPU_SAVED_STATE_SIZE
-	mul	r2, r2, r1
-	add	r0, r0, r2
-#endif
-	ldmfd   r0, {r4-r14}		 /* restore registers */
-	mov     r0, #0                   /* return power collapse failed */
-	bx      lr
-
-ENTRY(msm_pm_collapse_exit)
-#if 0 /* serial debug */
-	mov     r0, #0x80000016
-	mcr     p15, 0, r0, c15, c2, 4
-	mov     r0, #0xA9000000
-	add     r0, r0, #0x00A00000 /* UART1 */
-	/*add     r0, r0, #0x00C00000*/ /* UART3 */
-	mov     r1, #'A'
-	str     r1, [r0, #0x00C]
-#endif
-	ldr     r1, =msm_saved_state_phys
-	ldr     r2, =msm_pm_collapse_exit
-	adr     r3, msm_pm_collapse_exit
-	add     r1, r1, r3
-	sub     r1, r1, r2
-	ldr	r1, [r1]
-	add	r1, r1, #CPU_SAVED_STATE_SIZE
-#if (NR_CPUS >= 2)
-	mrc	p15, 0, r2, c0, c0, 5	/* MPIDR */
-	ands	r2, r2, #15		/* What CPU am I */
-	mov	r3, #CPU_SAVED_STATE_SIZE
-	mul	r2, r2, r3
-	add	r1, r1, r2
-#endif
-
-	ldmdb   r1!, {r2-r11}
-	mcr     p15, 0, r4, c3, c0, 0 /* dacr */
-	mcr     p15, 0, r3, c2, c0, 0 /* TTBR0 */
-#ifdef CONFIG_ARCH_MSM_SCORPION
-	/* This instruction is not valid for non scorpion processors */
-	mcr     p15, 3, r5, c15, c0, 3 /* L2CR1 */
-#endif
-	mcr     p15, 0, r6, c10, c2, 0 /* PRRR */
-	mcr     p15, 0, r7, c10, c2, 1 /* NMRR */
-	mcr     p15, 0, r8, c1, c0, 1 /* ACTLR */
-	mcr     p15, 0, r9, c2, c0, 1 /* TTBR1 */
-	mcr     p15, 0, r10, c13, c0, 3 /* TPIDRURO */
-	mcr     p15, 0, r11, c13, c0, 1 /* context ID */
-	isb
-	ldmdb   r1!, {r4-r14}
-	ldr	r0, =msm_pm_pc_pgd
-	ldr	r1, =msm_pm_collapse_exit
-	adr	r3, msm_pm_collapse_exit
-	add	r0, r0, r3
-	sub	r0, r0, r1
-	ldr	r0, [r0]
-	mrc     p15, 0, r1, c2, c0, 0 /* save current TTBR0 */
-	and	r3, r1, #0x7f /* mask to get TTB flags */
-	orr	r0, r0, r3 /* add TTB flags to switch TTBR value */
-	mcr     p15, 0, r0, c2, c0, 0 /* temporary switch TTBR0 */
-	isb
-	mcr     p15, 0, r2, c1, c0, 0   /* MMU control */
-	isb
-msm_pm_mapped_pa:
-	/* Switch to virtual */
-	ldr     r0, =msm_pm_pa_to_va
-	mov     pc, r0
-msm_pm_pa_to_va:
-	mcr     p15, 0, r1, c2, c0, 0 /* restore TTBR0 */
-	isb
-	mcr     p15, 0, r3, c8, c7, 0   /* UTLBIALL */
-	mcr     p15, 0, r3, c7, c5, 6   /* BPIALL */
-	dsb
-	isb
-
-#ifdef CONFIG_ARCH_MSM_KRAIT
-	mrc	p15, 0, r1, c0, c0, 0
-	ldr	r3, =0xff00fc00
-	and	r3, r1, r3
-	ldr 	r1, =0x51000400
-	cmp	r3, r1
-	mrceq	p15, 7, r3, c15, c0, 2
-	biceq	r3, r3, #0x400
-	mcreq	p15, 7, r3, c15, c0, 2
-#else
-	RESUME_8x25_L2
-	SET_SMP_COHERENCY ON
-#endif
-
-	ldr	r1, =msm_pm_enable_l2_fn
-	ldr	r1, [r1]
-	cmp	r1, #0
-	stmfd   sp!, {lr}
-	blxne	r1
-	dmb
-#if defined(CONFIG_MSM_JTAG) || defined(CONFIG_MSM_JTAG_MM)
-	bl      msm_jtag_restore_state
-#endif
-	ldmfd   sp!, {lr}
-	mov     r0, #1
-	bx      lr
-	nop
-	nop
-	nop
-	nop
-	nop
-1:	b       1b
-
+	.arm
 ENTRY(msm_pm_boot_entry)
 	mrc     p15, 0, r0, c0, c0, 5    /* MPIDR                          */
 	and     r0, r0, #15              /* what CPU am I                  */
@@ -399,80 +49,14 @@
 	add     r1, r1, r0, LSL #2       /* locate boot vector for our cpu */
 	ldr     pc, [r1]                 /* jump                           */
 
-ENTRY(msm_pm_set_l2_flush_flag)
-	ldr     r1, =msm_pm_flush_l2_flag
-	str     r0, [r1]
-	bx      lr
-
-ENTRY(msm_pm_get_l2_flush_flag)
-	ldr     r1, =msm_pm_flush_l2_flag
-	ldr     r0, [r1]
-	bx      lr
+3:	.long	.
 
 	.data
 
-	.globl msm_pm_pc_pgd
-msm_pm_pc_pgd:
-	.long	0x0
-
-	.globl msm_saved_state
-msm_saved_state:
-	.long	0x0
-
-	.globl msm_saved_state_phys
-msm_saved_state_phys:
-	.long	0x0
-
 	.globl msm_pm_boot_vector
 msm_pm_boot_vector:
 	.space  4 * NR_CPUS
 
-	.globl target_type
-target_type:
-	.long  0x0
-
-	.globl apps_power_collapse
-apps_power_collapse:
-	.long 0x0
-
-	.globl l2x0_base_addr
-l2x0_base_addr:
-	.long 0x0
-
 	.globl msm_pc_debug_counters_phys
 msm_pc_debug_counters_phys:
 	.long 0x0
-
-	.globl msm_pc_debug_counters
-msm_pc_debug_counters:
-	.long 0x0
-
-	.globl msm_pm_enable_l2_fn
-msm_pm_enable_l2_fn:
-	.long 0x0
-
-	.globl msm_pm_disable_l2_fn
-msm_pm_disable_l2_fn:
-	.long 0x0
-
-	.globl msm_pm_flush_l2_fn
-msm_pm_flush_l2_fn:
-	.long 0x0
-
-/*
- * Default the l2 flush flag to 1 so that caches are flushed during power
- * collapse unless the  L2 driver decides to flush them only during L2
- * Power collapse.
- */
-msm_pm_flush_l2_flag:
-	.long 0x1
-
-/*
- * Save & restore l2x0 registers while system is entering and resuming
- * from Power Collapse.
- * 1. aux_ctrl_save (0x0)
- * 2. data_latency_ctrl (0x4)
- * 3. prefetch control (0x8)
- */
-l2x0_saved_ctrl_reg_val:
-	.space 4 * 3
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 72f1a03..0fb96c3 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -14,49 +14,13 @@
 #ifndef _ARCH_ARM_MACH_MSM_IDLE_H_
 #define _ARCH_ARM_MACH_MSM_IDLE_H_
 
-/* 11 general purpose registers (r4-r14), 10 cp15 registers */
-#define CPU_SAVED_STATE_SIZE (4 * 11 + 4 * 10)
-
-#define ON	1
-#define OFF	0
-#define TARGET_IS_8625	1
-#define POWER_COLLAPSED 1
-
-#ifndef __ASSEMBLY__
-
-int msm_arch_idle(void);
-int msm_pm_collapse(void);
-int msm_pm_pc_hotplug(void);
-void msm_pm_collapse_exit(void);
-extern void *msm_saved_state;
-extern void (*msm_pm_disable_l2_fn)(void);
-extern void (*msm_pm_enable_l2_fn)(void);
-extern void (*msm_pm_flush_l2_fn)(void);
-extern unsigned long msm_saved_state_phys;
-
 #ifdef CONFIG_CPU_V7
-void msm_pm_boot_entry(void);
-void msm_pm_set_l2_flush_flag(unsigned int flag);
-int msm_pm_get_l2_flush_flag(void);
-extern unsigned long msm_pm_pc_pgd;
 extern unsigned long msm_pm_boot_vector[NR_CPUS];
-extern uint32_t target_type;
-extern uint32_t apps_power_collapse;
-extern uint32_t *l2x0_base_addr;
+void msm_pm_boot_entry(void);
 #else
-static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
-{
-	/* empty */
-}
 static inline void msm_pm_boot_entry(void)
 {
 	/* empty */
 }
-static inline void msm_pm_write_boot_vector(unsigned int cpu,
-						unsigned long address)
-{
-	/* empty */
-}
-#endif
 #endif
 #endif
diff --git a/arch/arm/mach-msm/include/mach/mpm.h b/arch/arm/mach-msm/include/mach/mpm.h
index e76a6a9..abfac48 100644
--- a/arch/arm/mach-msm/include/mach/mpm.h
+++ b/arch/arm/mach-msm/include/mach/mpm.h
@@ -112,11 +112,13 @@
  * @sclk_count: wakeup time in sclk counts for programmed RPM wakeup
  * @from_idle: indicates if the sytem is entering low power mode as a part of
  *		suspend/idle task.
+ * @cpumask: the next cpu to wakeup.
  *
  * Low power management code calls into this API to configure the MPM to
  * monitor the active irqs before going to sleep.
  */
-void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle);
+void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle,
+		const struct cpumask *cpumask);
 /**
  * msm_mpm_exit_sleep() -Called from PM code after resuming from low power mode
  *
@@ -159,7 +161,8 @@
 { return false; }
 static inline bool msm_mpm_gpio_irqs_detectable(bool from_idle)
 { return false; }
-static inline void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle) {}
+static inline void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle
+		const struct cpumask *cpumask) {}
 static inline void msm_mpm_exit_sleep(bool from_idle) {}
 static inline void __init of_mpm_init(struct device_node *node) {}
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index cd07662..e3bd488 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -24,6 +24,7 @@
 #include <mach/msm_smem.h>
 
 typedef struct smd_channel smd_channel_t;
+struct cpumask;
 
 #define SMD_MAX_CH_NAME_LEN 20 /* includes null char at end */
 
@@ -217,13 +218,15 @@
  * particular channel.
  * @ch:      open channel handle to use for the edge
  * @mask:    1 = mask interrupts; 0 = unmask interrupts
+ * @cpumask  cpumask for the next cpu scheduled to be woken up
  * @returns: 0 for success; < 0 for failure
  *
  * Note that this enables/disables all interrupts from the remote subsystem for
  * all channels.  As such, it should be used with care and only for specific
  * use cases such as power-collapse sequencing.
  */
-int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask);
+int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask,
+		const struct cpumask *cpumask);
 
 /* Starts a packet transaction.  The size of the packet may exceed the total
  * size of the smd ring buffer.
@@ -411,7 +414,8 @@
 {
 }
 
-static inline int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask)
+static inline int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask,
+		struct cpumask *cpumask)
 {
 	return -ENODEV;
 }
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index 249a334..b707df1 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -19,73 +19,115 @@
 #include <linux/mutex.h>
 #include <linux/cpu.h>
 #include <linux/of.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/tick.h>
+#include <linux/suspend.h>
+#include <linux/pm_qos.h>
+#include <linux/of_platform.h>
 #include <mach/mpm.h>
+#include <mach/cpuidle.h>
+#include <mach/event_timer.h>
 #include "pm.h"
 #include "rpm-notifier.h"
 #include "spm.h"
 #include "idle.h"
 
+#define SCLK_HZ (32768)
+
 enum {
 	MSM_LPM_LVL_DBG_SUSPEND_LIMITS = BIT(0),
 	MSM_LPM_LVL_DBG_IDLE_LIMITS = BIT(1),
 };
 
-enum {
-	MSM_SCM_L2_ON = 0,
-	MSM_SCM_L2_OFF = 1,
-	MSM_SCM_L2_GDHS = 3,
-};
-
-struct msm_rpmrs_level {
-	enum msm_pm_sleep_mode sleep_mode;
-	uint32_t l2_cache;
-	bool available;
+struct power_params {
 	uint32_t latency_us;
-	uint32_t steady_state_power;
+	uint32_t ss_power;
 	uint32_t energy_overhead;
 	uint32_t time_overhead_us;
+	uint32_t target_residency_us;
 };
 
+struct lpm_cpu_level {
+	const char *name;
+	enum msm_pm_sleep_mode mode;
+	struct power_params pwr;
+	bool use_bc_timer;
+	bool sync;
+};
+
+struct lpm_system_level {
+	const char *name;
+	uint32_t l2_mode;
+	struct power_params pwr;
+	enum msm_pm_sleep_mode min_cpu_mode;
+	int num_cpu_votes;
+	bool notify_rpm;
+	bool available;
+	bool sync;
+};
+
+struct lpm_system_state {
+	struct lpm_cpu_level *cpu_level;
+	int num_cpu_levels;
+	struct lpm_system_level *system_level;
+	int num_system_levels;
+	enum msm_pm_sleep_mode sync_cpu_mode;
+	int last_entered_cluster_index;
+	bool allow_synched_levels;
+	bool no_l2_saw;
+	struct spinlock sync_lock;
+	int num_cores_in_sync;
+};
+
+static struct lpm_system_state sys_state;
+static bool suspend_in_progress;
+
 struct lpm_lookup_table {
 	uint32_t modes;
 	const char *mode_name;
 };
 
-static void msm_lpm_level_update(void);
-
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+static void lpm_system_level_update(void);
+static void setup_broadcast_timer(void *arg);
+static int lpm_cpu_callback(struct notifier_block *cpu_nb,
 				unsigned long action, void *hcpu);
 
-static struct notifier_block __refdata msm_lpm_cpu_nblk = {
-	.notifier_call = msm_lpm_cpu_callback,
+static struct notifier_block __refdata lpm_cpu_nblk = {
+	.notifier_call = lpm_cpu_callback,
 };
 
 static uint32_t allowed_l2_mode;
 static uint32_t sysfs_dbg_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
 static uint32_t default_l2_mode;
 
-static bool no_l2_saw;
 
-static ssize_t msm_lpm_levels_attr_show(
+static ssize_t lpm_levels_attr_show(
 	struct kobject *kobj, struct kobj_attribute *attr, char *buf);
-static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+static ssize_t lpm_levels_attr_store(struct kobject *kobj,
 	struct kobj_attribute *attr, const char *buf, size_t count);
 
-#define ADJUST_LATENCY(x)	\
-	((x == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE) ?\
-		(num_online_cpus()) / 2 : 0)
 
-static int msm_lpm_lvl_dbg_msk;
+static int lpm_lvl_dbg_msk;
 
 module_param_named(
-	debug_mask, msm_lpm_lvl_dbg_msk, int, S_IRUGO | S_IWUSR | S_IWGRP
+	debug_mask, lpm_lvl_dbg_msk, int, S_IRUGO | S_IWUSR | S_IWGRP
 );
 
-static struct msm_rpmrs_level *msm_lpm_levels;
-static int msm_lpm_level_count;
+static bool menu_select;
+module_param_named(
+	menu_select, menu_select, bool, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+static int num_powered_cores;
+static struct hrtimer lpm_hrtimer;
 
 static struct kobj_attribute lpm_l2_kattr = __ATTR(l2,  S_IRUGO|S_IWUSR,\
-		msm_lpm_levels_attr_show, msm_lpm_levels_attr_store);
+		lpm_levels_attr_show, lpm_levels_attr_store);
 
 static struct attribute *lpm_levels_attr[] = {
 	&lpm_l2_kattr.attr,
@@ -97,7 +139,7 @@
 };
 
 /* SYSFS */
-static ssize_t msm_lpm_levels_attr_show(
+static ssize_t lpm_levels_attr_show(
 	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
 	struct kernel_param kp;
@@ -115,7 +157,7 @@
 	return rc;
 }
 
-static ssize_t msm_lpm_levels_attr_store(struct kobject *kobj,
+static ssize_t lpm_levels_attr_store(struct kobject *kobj,
 	struct kobj_attribute *attr, const char *buf, size_t count)
 {
 	struct kernel_param kp;
@@ -128,64 +170,49 @@
 		return rc;
 
 	sysfs_dbg_l2_mode = temp;
-	msm_lpm_level_update();
+	lpm_system_level_update();
 
 	return count;
 }
 
-static int msm_pm_get_sleep_mode_value(struct device_node *node,
-			const char *key, uint32_t *sleep_mode_val)
+static int msm_pm_get_sleep_mode_value(const char *mode_name)
 {
-	int i;
-	struct lpm_lookup_table {
-		uint32_t modes;
-		const char *mode_name;
-	};
 	struct lpm_lookup_table pm_sm_lookup[] = {
 		{MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
 			"wfi"},
-		{MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
-			"ramp_down_and_wfi"},
 		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
 			"standalone_pc"},
 		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
 			"pc"},
 		{MSM_PM_SLEEP_MODE_RETENTION,
 			"retention"},
-		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
-			"pc_suspend"},
-		{MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN,
-			"pc_no_xo_shutdown"}
 	};
-	int ret;
-	const char *mode_name;
+	int i;
+	int ret = -EINVAL;
 
-	ret = of_property_read_string(node, key, &mode_name);
-	if (!ret) {
-		ret = -EINVAL;
-		for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
-			if (!strcmp(mode_name, pm_sm_lookup[i].mode_name)) {
-				*sleep_mode_val = pm_sm_lookup[i].modes;
-				ret = 0;
-				break;
-			}
+	for (i = 0; i < ARRAY_SIZE(pm_sm_lookup); i++) {
+		if (!strcmp(mode_name, pm_sm_lookup[i].mode_name)) {
+			ret = pm_sm_lookup[i].modes;
+			break;
 		}
 	}
 	return ret;
 }
 
-static int msm_lpm_set_l2_mode(int sleep_mode)
+static int lpm_set_l2_mode(struct lpm_system_state *system_state,
+				int sleep_mode)
 {
 	int lpm = sleep_mode;
 	int rc = 0;
 
-	if (no_l2_saw)
+	if (system_state->no_l2_saw)
 		goto bail_set_l2_mode;
 
 	msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
 
 	switch (sleep_mode) {
 	case MSM_SPM_L2_MODE_POWER_COLLAPSE:
+		pr_info("Configuring for L2 power collapse\n");
 		msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
 		break;
 	case MSM_SPM_L2_MODE_GDHS:
@@ -209,244 +236,341 @@
 			WARN_ON_ONCE(1);
 		else
 			pr_err("%s: Failed to set L2 low power mode %d, ERR %d",
-			__func__, lpm, rc);
+					__func__, lpm, rc);
 	}
-
 bail_set_l2_mode:
 	return rc;
 }
 
-static void msm_lpm_level_update(void)
+static void lpm_system_level_update(void)
 {
-	int lpm_level;
-	struct msm_rpmrs_level *level = NULL;
+	int i;
+	struct lpm_system_level *l = NULL;
 	uint32_t max_l2_mode;
 	static DEFINE_MUTEX(lpm_lock);
 
 	mutex_lock(&lpm_lock);
 
+	if (num_powered_cores == 1)
+		allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+	else if (sys_state.allow_synched_levels)
+		allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+	else
+		allowed_l2_mode = default_l2_mode;
 	max_l2_mode = min(allowed_l2_mode, sysfs_dbg_l2_mode);
 
-	for (lpm_level = 0; lpm_level < msm_lpm_level_count; lpm_level++) {
-		level = &msm_lpm_levels[lpm_level];
-		level->available = !(level->l2_cache > max_l2_mode);
+	for (i = 0; i < sys_state.num_system_levels; i++) {
+		l = &sys_state.system_level[i];
+		l->available = !(l->l2_mode > max_l2_mode);
 	}
 	mutex_unlock(&lpm_lock);
 }
 
-int msm_lpm_enter_sleep(uint32_t sclk_count, void *limits,
-		bool from_idle, bool notify_rpm)
+static int lpm_system_mode_select(
+		struct lpm_system_state *system_state,
+		uint32_t sleep_us, bool from_idle)
 {
-	int ret = 0;
-	int debug_mask;
-	uint32_t l2 = *(uint32_t *)limits;
+	int best_level = -1;
+	int i;
+	uint32_t best_level_pwr = ~0UL;
+	uint32_t pwr;
+	uint32_t latency_us = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 
-	if (from_idle)
-		debug_mask = msm_lpm_lvl_dbg_msk &
-			MSM_LPM_LVL_DBG_IDLE_LIMITS;
-	else
-		debug_mask = msm_lpm_lvl_dbg_msk &
-			MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+	if (!system_state->system_level)
+		return -EINVAL;
 
-	if (debug_mask)
-		pr_info("%s(): l2:%d", __func__, l2);
+	for (i = 0; i < system_state->num_system_levels; i++) {
+		struct lpm_system_level *system_level =
+			&system_state->system_level[i];
+		struct power_params *pwr_param = &system_level->pwr;
 
-	ret = msm_lpm_set_l2_mode(l2);
+		if (!system_level->available)
+			continue;
 
-	if (ret) {
-		if (ret == -ENXIO)
-			ret = 0;
-		else {
-			pr_warn("%s(): Failed to set L2 SPM Mode %d",
-					__func__, l2);
-			goto bail;
+		if (system_level->sync &&
+			system_level->num_cpu_votes != num_powered_cores)
+			continue;
+
+		if (latency_us < pwr_param->latency_us)
+			continue;
+
+		if (sleep_us < pwr_param->time_overhead_us)
+			continue;
+
+		/*
+		 * After the suspend prepare notifications its possible
+		 * for the CPU to enter a system sleep mode. But MPM would have
+		 * already requested a XO clock based on the wakeup irqs. To
+		 * prevent suspend votes from being overriden by idle irqs, MPM
+		 * doesn't send an updated MPM vote after suspend_prepare
+		 * callback.
+		 * To ensure that XO sleep vote isn't used if and when the
+		 * device enters idle PC after suspend prepare callback,
+		 * disallow any low power modes that notifies RPM after suspend
+		 * prepare function is called
+		 */
+		if (suspend_in_progress && system_level->notify_rpm &&
+				from_idle)
+			continue;
+
+		if ((sleep_us >> 10) > pwr_param->time_overhead_us) {
+			pwr = pwr_param->ss_power;
+		} else {
+			pwr = pwr_param->ss_power;
+			pwr -= (pwr_param->time_overhead_us
+					* pwr_param->ss_power) / sleep_us;
+			pwr += pwr_param->energy_overhead / sleep_us;
+		}
+
+		if (best_level_pwr >= pwr) {
+			best_level = i;
+			best_level_pwr = pwr;
 		}
 	}
+	return best_level;
+}
 
-	if (notify_rpm) {
-		ret = msm_rpm_enter_sleep(debug_mask);
+static void lpm_system_prepare(struct lpm_system_state *system_state,
+		int index, bool from_idle)
+{
+	struct lpm_system_level *lvl;
+	struct clock_event_device *bc = tick_get_broadcast_device()->evtdev;
+	uint32_t sclk;
+	int64_t us = (~0ULL);
+	int dbg_mask;
+	int ret;
+	const struct cpumask *nextcpu;
+
+	spin_lock(&system_state->sync_lock);
+	if (num_powered_cores != system_state->num_cores_in_sync) {
+		spin_unlock(&system_state->sync_lock);
+		return;
+	}
+
+	if (from_idle) {
+		dbg_mask = lpm_lvl_dbg_msk & MSM_LPM_LVL_DBG_IDLE_LIMITS;
+		us = ktime_to_us(ktime_sub(bc->next_event, ktime_get()));
+		nextcpu = bc->cpumask;
+	} else {
+		dbg_mask = lpm_lvl_dbg_msk & MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+		nextcpu = cpumask_of(smp_processor_id());
+	}
+
+	lvl = &system_state->system_level[index];
+
+	ret = lpm_set_l2_mode(system_state, lvl->l2_mode);
+
+	if (ret && ret != -ENXIO) {
+		pr_warn("%s(): Cannot set L2 Mode %d, ret:%d\n",
+				__func__, lvl->l2_mode, ret);
+		goto bail_system_sleep;
+	}
+
+	if (lvl->notify_rpm) {
+		ret = msm_rpm_enter_sleep(dbg_mask, nextcpu);
 		if (ret) {
-			pr_warn("%s(): RPM failed to enter sleep err:%d\n",
-					__func__, ret);
-			goto bail;
+			pr_err("rpm_enter_sleep() failed with rc = %d\n", ret);
+			goto bail_system_sleep;
 		}
 
-		msm_mpm_enter_sleep(sclk_count, from_idle);
+
+		if (!from_idle)
+			us = USEC_PER_SEC * msm_pm_sleep_time_override;
+
+		do_div(us, USEC_PER_SEC/SCLK_HZ);
+		sclk = (uint32_t)us;
+		msm_mpm_enter_sleep(sclk, from_idle, nextcpu);
 	}
-bail:
-	return ret;
-}
-
-static void msm_lpm_exit_sleep(void *limits, bool from_idle,
-		bool notify_rpm, bool collapsed)
-{
-
-	msm_lpm_set_l2_mode(default_l2_mode);
-
-	if (notify_rpm) {
-		msm_mpm_exit_sleep(from_idle);
-		msm_rpm_exit_sleep();
-	}
-}
-
-void msm_lpm_show_resources(void)
-{
-	/* TODO */
+	system_state->last_entered_cluster_index = index;
+	spin_unlock(&system_state->sync_lock);
 	return;
+
+bail_system_sleep:
+	if (default_l2_mode != system_state->system_level[index].l2_mode)
+		lpm_set_l2_mode(system_state, default_l2_mode);
+	spin_unlock(&system_state->sync_lock);
+}
+
+static void lpm_system_unprepare(struct lpm_system_state *system_state,
+		int cpu_index, bool from_idle)
+{
+	int index, i;
+	struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+	bool first_core_up;
+
+	if (cpu_level->mode < system_state->sync_cpu_mode)
+		return;
+
+	spin_lock(&system_state->sync_lock);
+
+	first_core_up = (system_state->num_cores_in_sync == num_powered_cores);
+
+	system_state->num_cores_in_sync--;
+
+	if (!system_state->system_level)
+		goto unlock_and_return;
+
+	index = system_state->last_entered_cluster_index;
+
+	for (i = 0; i < system_state->num_system_levels; i++) {
+		struct lpm_system_level *system_lvl
+					= &system_state->system_level[i];
+		if (cpu_level->mode >= system_lvl->min_cpu_mode)
+			system_lvl->num_cpu_votes--;
+	}
+
+	if (!first_core_up)
+		goto unlock_and_return;
+
+	if (default_l2_mode != system_state->system_level[index].l2_mode)
+		lpm_set_l2_mode(system_state, default_l2_mode);
+
+	if (system_state->system_level[index].notify_rpm) {
+		msm_rpm_exit_sleep();
+		msm_mpm_exit_sleep(from_idle);
+	}
+unlock_and_return:
+	spin_unlock(&system_state->sync_lock);
 }
 
 s32 msm_cpuidle_get_deep_idle_latency(void)
 {
 	int i;
-	struct msm_rpmrs_level *level = msm_lpm_levels, *best = level;
+	struct lpm_cpu_level *level = sys_state.cpu_level;
 
 	if (!level)
 		return 0;
 
-	for (i = 0; i < msm_lpm_level_count; i++, level++) {
-		if (!level->available)
-			continue;
-		if (level->sleep_mode != MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
-			continue;
-		/* Pick the first power collapse mode by default */
-		if (best->sleep_mode != MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
-			best = level;
-		/* Find the lowest latency for power collapse */
-		if (level->latency_us < best->latency_us)
-			best = level;
+	for (i = 0; i < sys_state.num_cpu_levels; i++, level++) {
+		if (level->mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+			break;
 	}
-	return best->latency_us - 1;
+
+	if (i ==  sys_state.num_cpu_levels)
+		return 0;
+	else
+		return level->pwr.latency_us;
 }
 
-static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
+static int lpm_cpu_callback(struct notifier_block *cpu_nb,
 	unsigned long action, void *hcpu)
 {
-	switch (action) {
+	switch (action & ~CPU_TASKS_FROZEN) {
 	case CPU_UP_PREPARE:
-	case CPU_UP_PREPARE_FROZEN:
-		allowed_l2_mode = default_l2_mode;
-		msm_lpm_level_update();
+		++num_powered_cores;
+		lpm_system_level_update();
 		break;
-	case CPU_DEAD_FROZEN:
 	case CPU_DEAD:
 	case CPU_UP_CANCELED:
-	case CPU_UP_CANCELED_FROZEN:
-		if (num_online_cpus() == 1)
-			allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
-		msm_lpm_level_update();
+		num_powered_cores = num_online_cpus();
+		lpm_system_level_update();
+		break;
+	case CPU_ONLINE:
+		smp_call_function_single((unsigned long)hcpu,
+				setup_broadcast_timer, (void *)true, 1);
+		break;
+	default:
 		break;
 	}
 	return NOTIFY_OK;
 }
 
-static void *msm_lpm_lowest_limits(bool from_idle,
-		enum msm_pm_sleep_mode sleep_mode,
-		struct msm_pm_time_params *time_param, uint32_t *power)
+static enum hrtimer_restart lpm_hrtimer_cb(struct hrtimer *h)
 {
-	unsigned int cpu = smp_processor_id();
-	struct msm_rpmrs_level *best_level = NULL;
-	uint32_t best_level_pwr = 0;
-	uint32_t pwr;
+	return HRTIMER_NORESTART;
+}
+
+static void msm_pm_set_timer(uint32_t modified_time_us)
+{
+	u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
+	ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
+	lpm_hrtimer.function = lpm_hrtimer_cb;
+	hrtimer_start(&lpm_hrtimer, modified_ktime, HRTIMER_MODE_REL_PINNED);
+}
+
+static noinline int lpm_cpu_power_select(struct cpuidle_device *dev, int *index)
+{
+	int best_level = -1;
+	uint32_t best_level_pwr = ~0UL;
+	uint32_t latency_us = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
+	uint32_t sleep_us =
+		(uint32_t)(ktime_to_us(tick_nohz_get_sleep_length()));
+	uint32_t modified_time_us = 0;
+	uint32_t next_event_us = 0;
+	uint32_t power;
 	int i;
-	bool modify_event_timer;
-	uint32_t next_wakeup_us = time_param->sleep_us;
-	uint32_t lvl_latency_us = 0;
-	uint32_t lvl_overhead_us = 0;
-	uint32_t lvl_overhead_energy = 0;
 
-	if (!msm_lpm_levels)
-		return NULL;
+	if (!sys_state.cpu_level)
+		return -EINVAL;
 
-	for (i = 0; i < msm_lpm_level_count; i++) {
-		struct msm_rpmrs_level *level = &msm_lpm_levels[i];
+	if (!dev->cpu)
+		next_event_us = (uint32_t)(ktime_to_us(get_next_event_time()));
 
-		modify_event_timer = false;
+	for (i = 0; i < sys_state.num_cpu_levels; i++) {
+		struct lpm_cpu_level *level = &sys_state.cpu_level[i];
+		struct power_params *pwr = &level->pwr;
+		uint32_t next_wakeup_us = sleep_us;
+		enum msm_pm_sleep_mode mode = level->mode;
+		bool allow;
 
-		if (!level->available)
+		if (level->sync && num_online_cpus() > 1
+				&& !sys_state.allow_synched_levels)
 			continue;
 
-		if (sleep_mode != level->sleep_mode)
+		allow = msm_cpu_pm_check_mode(dev->cpu, mode, true);
+
+		if (!allow)
 			continue;
 
-		lvl_latency_us =
-			level->latency_us + (level->latency_us *
-						ADJUST_LATENCY(sleep_mode));
-
-		lvl_overhead_us =
-			level->time_overhead_us + (level->time_overhead_us *
-						ADJUST_LATENCY(sleep_mode));
-
-		lvl_overhead_energy =
-			level->energy_overhead + level->energy_overhead *
-						ADJUST_LATENCY(sleep_mode);
-
-		if (time_param->latency_us < lvl_latency_us)
+		if (latency_us < pwr->latency_us)
 			continue;
 
-		if (time_param->next_event_us &&
-			time_param->next_event_us < lvl_latency_us)
-			continue;
+		if (next_event_us)
+			if (next_event_us < pwr->latency_us)
+				continue;
 
-		if (time_param->next_event_us) {
-			if ((time_param->next_event_us < time_param->sleep_us)
-			|| ((time_param->next_event_us - lvl_latency_us) <
-				time_param->sleep_us)) {
-				modify_event_timer = true;
-				next_wakeup_us = time_param->next_event_us -
-						lvl_latency_us;
+			if (((next_event_us - pwr->latency_us) < sleep_us)
+					|| (next_event_us < sleep_us)) {
+				next_wakeup_us = next_event_us
+					- pwr->latency_us;
 			}
-		}
 
-		if (next_wakeup_us <= lvl_overhead_us)
+		if (next_wakeup_us <= pwr->time_overhead_us)
 			continue;
 
-		if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == sleep_mode)
-			|| (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == sleep_mode))
-			if (!cpu && msm_rpm_waiting_for_ack())
+		if ((MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE == mode)
+			|| (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode))
+			if (!dev->cpu && msm_rpm_waiting_for_ack())
 					break;
 
-		if (next_wakeup_us <= 1) {
-			pwr = lvl_overhead_energy;
-		} else if (next_wakeup_us <= lvl_overhead_us) {
-			pwr = lvl_overhead_energy / next_wakeup_us;
-		} else if ((next_wakeup_us >> 10)
-				> lvl_overhead_us) {
-			pwr = level->steady_state_power;
+		if ((next_wakeup_us >> 10) > pwr->latency_us) {
+			power = pwr->ss_power;
 		} else {
-			pwr = level->steady_state_power;
-			pwr -= (lvl_overhead_us *
-				level->steady_state_power) /
-						next_wakeup_us;
-			pwr += lvl_overhead_energy / next_wakeup_us;
+			power = pwr->ss_power;
+			power -= (pwr->latency_us * pwr->ss_power)
+					/ next_wakeup_us;
+			power += pwr->energy_overhead / next_wakeup_us;
 		}
 
-		if (!best_level || (best_level_pwr >= pwr)) {
-			best_level = level;
-			best_level_pwr = pwr;
-			if (power)
-				*power = pwr;
-			if (modify_event_timer &&
-				(sleep_mode !=
-					MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
-				time_param->modified_time_us =
-					time_param->next_event_us -
-						lvl_latency_us;
+		if (best_level_pwr >= power) {
+			best_level = i;
+			best_level_pwr = power;
+			if (next_event_us < sleep_us &&
+				(mode != MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT))
+				modified_time_us = next_event_us
+							- pwr->latency_us;
 			else
-				time_param->modified_time_us = 0;
+				modified_time_us = 0;
 		}
 	}
 
-	return best_level ? &best_level->l2_cache : NULL;
+	if (modified_time_us && !dev->cpu)
+		msm_pm_set_timer(modified_time_us);
+
+	return best_level;
 }
 
-static struct msm_pm_sleep_ops msm_lpm_ops = {
-	.lowest_limits = msm_lpm_lowest_limits,
-	.enter_sleep = msm_lpm_enter_sleep,
-	.exit_sleep = msm_lpm_exit_sleep,
-};
-
-static int msm_lpm_get_l2_cache_value(struct device_node *node,
-			char *key, uint32_t *l2_val)
+static int lpm_get_l2_cache_value(const char *l2_str)
 {
 	int i;
 	struct lpm_lookup_table l2_mode_lookup[] = {
@@ -456,24 +580,14 @@
 		{MSM_SPM_L2_MODE_RETENTION, "l2_cache_retention"},
 		{MSM_SPM_L2_MODE_DISABLED, "l2_cache_active"}
 	};
-	const char *l2_str;
-	int ret;
 
-	ret = of_property_read_string(node, key, &l2_str);
-	if (!ret) {
-		ret = -EINVAL;
-		for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++) {
-			if (!strcmp(l2_str, l2_mode_lookup[i].mode_name)) {
-				*l2_val = l2_mode_lookup[i].modes;
-				ret = 0;
-				break;
-			}
-		}
-	}
-	return ret;
+	for (i = 0; i < ARRAY_SIZE(l2_mode_lookup); i++)
+		if (!strcmp(l2_str, l2_mode_lookup[i].mode_name))
+			return  l2_mode_lookup[i].modes;
+	return -EINVAL;
 }
 
-static int __devinit msm_lpm_levels_sysfs_add(void)
+static int lpm_levels_sysfs_add(void)
 {
 	struct kobject *module_kobj = NULL;
 	struct kobject *low_power_kobj = NULL;
@@ -500,126 +614,548 @@
 	if (rc) {
 		if (low_power_kobj) {
 			sysfs_remove_group(low_power_kobj,
-						&lpm_levels_attr_grp);
+					&lpm_levels_attr_grp);
 			kobject_del(low_power_kobj);
 		}
 	}
 
 	return rc;
 }
-
-static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
+static int lpm_cpu_menu_select(struct cpuidle_device *dev, int *index)
 {
-	struct msm_rpmrs_level *levels = NULL;
-	struct msm_rpmrs_level *level = NULL;
+	int j;
+
+	for (; *index >= 0; (*index)--) {
+		int mode = 0;
+		bool allow = false;
+
+		allow = msm_cpu_pm_check_mode(dev->cpu, mode, true);
+
+		if (!allow)
+			continue;
+
+		for (j = sys_state.num_cpu_levels; j >= 0; j--) {
+			struct lpm_cpu_level *l = &sys_state.cpu_level[j];
+			if (mode == l->mode)
+				return j;
+		}
+	}
+	return -EPERM;
+}
+
+static inline void lpm_cpu_prepare(struct lpm_system_state *system_state,
+		int cpu_index, bool from_idle)
+{
+	struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+	unsigned int cpu = smp_processor_id();
+
+	/* Use broadcast timer for aggregating sleep mode within a cluster.
+	 * A broadcast timer could be used because of harware restriction or
+	 * to ensure that we BC timer is used incase a cpu mode could trigger
+	 * a cluster level sleep
+	 */
+	if (from_idle && (cpu_level->use_bc_timer ||
+			(cpu_level->mode >= system_state->sync_cpu_mode)))
+		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
+}
+
+static inline void lpm_cpu_unprepare(struct lpm_system_state *system_state,
+		int cpu_index, bool from_idle)
+{
+	struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+	unsigned int cpu = smp_processor_id();
+
+	if (from_idle && (cpu_level->use_bc_timer ||
+			(cpu_level->mode >= system_state->sync_cpu_mode)))
+		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
+}
+
+static int lpm_system_select(struct lpm_system_state *system_state,
+		int cpu_index, bool from_idle)
+{
+	uint64_t us = (~0ULL);
+	struct clock_event_device *ed;
+	struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+	int i;
+	bool last_core_down;
+
+	if (cpu_level->mode < system_state->sync_cpu_mode)
+		return -EINVAL;
+
+	spin_lock(&system_state->sync_lock);
+
+	last_core_down =
+		(++system_state->num_cores_in_sync == num_powered_cores);
+
+	if (!system_state->system_level) {
+		spin_unlock(&system_state->sync_lock);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < system_state->num_system_levels; i++) {
+		struct lpm_system_level *system_lvl =
+			&system_state->system_level[i];
+		if (cpu_level->mode >= system_lvl->min_cpu_mode)
+			system_lvl->num_cpu_votes++;
+	}
+	spin_unlock(&system_state->sync_lock);
+
+	if (!last_core_down)
+		return -EBUSY;
+
+	ed = tick_get_broadcast_device()->evtdev;
+	if (!ed)
+		return -EINVAL;
+
+	if (from_idle)
+		us = ktime_to_us(ktime_sub(ed->next_event, ktime_get()));
+	else
+		us = (~0ULL);
+
+	return lpm_system_mode_select(system_state, (uint32_t)(us), from_idle);
+}
+
+static void lpm_enter_low_power(struct lpm_system_state *system_state,
+		int cpu_index, bool from_idle)
+{
+	int idx;
+	struct lpm_cpu_level *cpu_level = &system_state->cpu_level[cpu_index];
+
+	cpu_level = &system_state->cpu_level[cpu_index];
+
+	lpm_cpu_prepare(system_state, cpu_index, from_idle);
+
+	idx = lpm_system_select(system_state, cpu_index, from_idle);
+
+	if (idx >= 0)
+		lpm_system_prepare(system_state, idx, from_idle);
+
+	msm_cpu_pm_enter_sleep(cpu_level->mode, from_idle);
+
+	lpm_system_unprepare(system_state, cpu_index, from_idle);
+
+	lpm_cpu_unprepare(system_state, cpu_index, from_idle);
+}
+
+static int lpm_cpuidle_enter(struct cpuidle_device *dev,
+		struct cpuidle_driver *drv, int index)
+{
+	int64_t time = ktime_to_ns(ktime_get());
+	int idx;
+
+	idx = menu_select ? lpm_cpu_menu_select(dev, &index) :
+			lpm_cpu_power_select(dev, &index);
+	if (idx < 0) {
+		local_irq_enable();
+		return -EPERM;
+	}
+
+	lpm_enter_low_power(&sys_state, idx, true);
+
+	time = ktime_to_ns(ktime_get()) - time;
+	do_div(time, 1000);
+	dev->last_residency = (int)time;
+	local_irq_enable();
+	return index;
+}
+
+static int lpm_suspend_enter(suspend_state_t state)
+{
+	int i;
+
+	for (i = sys_state.num_cpu_levels - 1; i >= 0; i--) {
+		bool allow = msm_cpu_pm_check_mode(smp_processor_id(),
+				sys_state.cpu_level[i].mode, false);
+		if (allow)
+			break;
+	}
+
+	if (i < 0)
+		return -EINVAL;
+
+	lpm_enter_low_power(&sys_state, i,  false);
+
+	return 0;
+}
+
+static int lpm_suspend_prepare(void)
+{
+	suspend_in_progress = true;
+	msm_mpm_suspend_prepare();
+	return 0;
+}
+
+static void lpm_suspend_wake(void)
+{
+	msm_mpm_suspend_wake();
+	suspend_in_progress = false;
+}
+
+static struct platform_device lpm_dev = {
+	.name = "msm_pm",
+	.id = -1,
+};
+
+static const struct platform_suspend_ops lpm_suspend_ops = {
+	.enter = lpm_suspend_enter,
+	.valid = suspend_valid_only_mem,
+	.prepare_late = lpm_suspend_prepare,
+	.wake = lpm_suspend_wake,
+};
+
+static void setup_broadcast_timer(void *arg)
+{
+	unsigned long reason = (unsigned long)arg;
+	int cpu = smp_processor_id();
+
+	reason = reason ?
+		CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
+
+	clockevents_notify(reason, &cpu);
+}
+
+static struct cpuidle_driver msm_cpuidle_driver = {
+	.name = "msm_idle",
+	.owner = THIS_MODULE,
+};
+
+static void lpm_cpuidle_init(void)
+{
+	int i = 0;
+	int state_count = 0;
+
+	if (!sys_state.cpu_level)
+		return;
+	BUG_ON(sys_state.num_cpu_levels > CPUIDLE_STATE_MAX);
+
+	for (i = 0; i < sys_state.num_cpu_levels; i++) {
+		struct cpuidle_state *st = &msm_cpuidle_driver.states[i];
+		struct lpm_cpu_level *cpu_level = &sys_state.cpu_level[i];
+		snprintf(st->name, CPUIDLE_NAME_LEN, "C%u\n", i);
+		snprintf(st->desc, CPUIDLE_DESC_LEN, cpu_level->name);
+		st->flags = 0;
+		st->exit_latency = cpu_level->pwr.latency_us;
+		st->power_usage = cpu_level->pwr.ss_power;
+		st->target_residency = 0;
+		st->enter = lpm_cpuidle_enter;
+		state_count++;
+	}
+	msm_cpuidle_driver.state_count = state_count;
+	msm_cpuidle_driver.safe_state_index = 0;
+
+	if (cpuidle_register(&msm_cpuidle_driver, NULL))
+		pr_err("%s(): Failed to register CPUIDLE device\n", __func__);
+}
+
+static int lpm_parse_power_params(struct device_node *node,
+		struct power_params *pwr)
+{
+	char *key;
+	int ret;
+
+	key = "qcom,latency-us";
+	ret  = of_property_read_u32(node, key, &pwr->latency_us);
+	if (ret)
+		goto fail;
+
+	key = "qcom,ss-power";
+	ret = of_property_read_u32(node, key, &pwr->ss_power);
+	if (ret)
+		goto fail;
+
+	key = "qcom,energy-overhead";
+	ret = of_property_read_u32(node, key, &pwr->energy_overhead);
+	if (ret)
+		goto fail;
+
+	key = "qcom,time-overhead";
+	ret = of_property_read_u32(node, key, &pwr->time_overhead_us);
+	if (ret)
+		goto fail;
+fail:
+	if (ret)
+		pr_err("%s(): Error reading %s\n", __func__, key);
+	return ret;
+}
+
+static int lpm_cpu_probe(struct platform_device *pdev)
+{
+	struct lpm_cpu_level *level = NULL, *l;
 	struct device_node *node = NULL;
-	char *key = NULL;
-	uint32_t val = 0;
-	int ret = 0;
-	uint32_t num_levels = 0;
-	int idx = 0;
+	int num_levels = 0;
+	char *key;
+	int ret;
 
 	for_each_child_of_node(pdev->dev.of_node, node)
 		num_levels++;
 
-	levels = kzalloc(num_levels * sizeof(struct msm_rpmrs_level),
+	level = kzalloc(num_levels * sizeof(struct lpm_cpu_level),
 			GFP_KERNEL);
-	if (!levels)
+
+	if (!level)
 		return -ENOMEM;
 
+	l = &level[0];
 	for_each_child_of_node(pdev->dev.of_node, node) {
-		level = &levels[idx++];
-		level->available = false;
 
 		key = "qcom,mode";
-		ret = msm_pm_get_sleep_mode_value(node, key, &val);
-		if (ret)
+		ret = of_property_read_string(node, key, &l->name);
+
+		if (ret) {
+			pr_err("%s(): Cannot read cpu mode%s\n", __func__, key);
 			goto fail;
-		level->sleep_mode = val;
+		}
+
+		l->mode = msm_pm_get_sleep_mode_value(l->name);
+
+		if (l->mode < 0) {
+			pr_err("%s():Cannot parse cpu mode:%s\n", __func__,
+					l->name);
+			goto fail;
+		}
+
+		if (l->mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+			l->sync = true;
+
+		key = "qcom,use-broadcast-timer";
+		l->use_bc_timer = of_property_read_bool(node, key);
+
+		ret = lpm_parse_power_params(node, &l->pwr);
+		if (ret) {
+			pr_err("%s(): cannot Parse power params\n", __func__);
+			goto fail;
+		}
+		l++;
+	}
+	sys_state.cpu_level = level;
+	sys_state.num_cpu_levels = num_levels;
+	return ret;
+fail:
+	kfree(level);
+	return ret;
+}
+
+static int lpm_system_probe(struct platform_device *pdev)
+{
+	struct lpm_system_level *level = NULL, *l;
+	int num_levels = 0;
+	struct device_node *node;
+	char *key;
+	int ret;
+
+	for_each_child_of_node(pdev->dev.of_node, node)
+		num_levels++;
+
+	level = kzalloc(num_levels * sizeof(struct lpm_system_level),
+			GFP_KERNEL);
+
+	if (!level)
+		return -ENOMEM;
+
+	l = &level[0];
+	for_each_child_of_node(pdev->dev.of_node, node) {
 
 		key = "qcom,l2";
-		ret = msm_lpm_get_l2_cache_value(node, key, &val);
-		if (ret)
+		ret = of_property_read_string(node, key, &l->name);
+		if (ret) {
+			pr_err("%s(): Failed to read L2 mode\n", __func__);
 			goto fail;
-		level->l2_cache = val;
+		}
 
-		key = "qcom,latency-us";
-		ret = of_property_read_u32(node, key, &val);
-		if (ret)
+		l->l2_mode = lpm_get_l2_cache_value(l->name);
+
+		if (l->l2_mode < 0) {
+			pr_err("%s(): Failed to read l2 cache mode\n",
+					__func__);
 			goto fail;
-		level->latency_us = val;
+		}
 
-		key = "qcom,ss-power";
-		ret = of_property_read_u32(node, key, &val);
-		if (ret)
+		if (l->l2_mode == MSM_SPM_L2_MODE_GDHS ||
+				l->l2_mode == MSM_SPM_L2_MODE_POWER_COLLAPSE)
+			l->notify_rpm = true;
+
+		if (l->l2_mode >= MSM_SPM_L2_MODE_GDHS)
+			l->sync = true;
+
+		ret = lpm_parse_power_params(node, &l->pwr);
+		if (ret) {
+			pr_err("%s(): Failed to parse power params\n",
+					__func__);
 			goto fail;
-		level->steady_state_power = val;
+		}
 
-		key = "qcom,energy-overhead";
-		ret = of_property_read_u32(node, key, &val);
-		if (ret)
-			goto fail;
-		level->energy_overhead = val;
+		key = "qcom,sync-cpus";
+		l->sync = of_property_read_bool(node, key);
 
-		key = "qcom,time-overhead";
-		ret = of_property_read_u32(node, key, &val);
-		if (ret)
-			goto fail;
-		level->time_overhead_us = val;
+		if (l->sync) {
+			const char *name;
 
-		level->available = true;
+			key = "qcom,min-cpu-mode";
+			ret = of_property_read_string(node, key, &name);
+			if (ret) {
+				pr_err("%s(): Required key %snot found\n",
+						__func__, name);
+				goto fail;
+			}
+
+			l->min_cpu_mode = msm_pm_get_sleep_mode_value(name);
+
+			if (l->min_cpu_mode < 0) {
+				pr_err("%s(): Cannot parse cpu mode:%s\n",
+						__func__, name);
+				goto fail;
+			}
+
+			if (l->min_cpu_mode < sys_state.sync_cpu_mode)
+				sys_state.sync_cpu_mode = l->min_cpu_mode;
+		}
+
+		l++;
 	}
+	sys_state.system_level = level;
+	sys_state.num_system_levels = num_levels;
+	return ret;
+fail:
+	kfree(level);
+	return ret;
+}
+
+static int lpm_probe(struct platform_device *pdev)
+{
+	struct device_node *node = NULL;
+	char *key = NULL;
+	int ret;
 
 	node = pdev->dev.of_node;
+
+	key = "qcom,allow-synced-levels";
+	sys_state.allow_synched_levels = of_property_read_bool(node, key);
+
 	key = "qcom,no-l2-saw";
-	no_l2_saw = of_property_read_bool(node, key);
+	sys_state.no_l2_saw = of_property_read_bool(node, key);
 
-	msm_lpm_levels = levels;
-	msm_lpm_level_count = idx;
+	sys_state.sync_cpu_mode = MSM_PM_SLEEP_MODE_NR;
+	spin_lock_init(&sys_state.sync_lock);
+	sys_state.num_cores_in_sync = 0;
 
-	if (num_online_cpus() == 1)
-		allowed_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
+	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+	if (ret)
+		goto fail;
 
 	/* Do the following two steps only if L2 SAW is present */
-	if (!no_l2_saw) {
-		key = "qcom,default-l2-state";
-		if (msm_lpm_get_l2_cache_value(node, key, &default_l2_mode))
-			goto fail;
+	num_powered_cores = num_online_cpus();
 
-		if (msm_lpm_levels_sysfs_add())
+	if (!sys_state.no_l2_saw) {
+		int ret;
+		const char *l2;
+		key = "qcom,default-l2-state";
+		ret = of_property_read_string(node, key, &l2);
+		if (ret) {
+			pr_err("%s(): Failed to read default L2 mode\n",
+					__func__);
 			goto fail;
-		register_hotcpu_notifier(&msm_lpm_cpu_nblk);
-		msm_pm_set_l2_flush_flag(0);
+		}
+
+		default_l2_mode = lpm_get_l2_cache_value(l2);
+		if (default_l2_mode < 0) {
+			pr_err("%s(): Unable to parse default L2 mode\n",
+					__func__);
+			goto fail;
+		}
+
+		if (lpm_levels_sysfs_add())
+			goto fail;
+		msm_pm_set_l2_flush_flag(MSM_SCM_L2_ON);
 	} else {
-		msm_pm_set_l2_flush_flag(1);
+		msm_pm_set_l2_flush_flag(MSM_SCM_L2_OFF);
 		default_l2_mode = MSM_SPM_L2_MODE_POWER_COLLAPSE;
 	}
 
-	msm_lpm_level_update();
-	msm_pm_set_sleep_ops(&msm_lpm_ops);
+	get_cpu();
+	on_each_cpu(setup_broadcast_timer, (void *)true, 1);
+	put_cpu();
+
+	register_hotcpu_notifier(&lpm_cpu_nblk);
+
+	lpm_system_level_update();
+	platform_device_register(&lpm_dev);
+	suspend_set_ops(&lpm_suspend_ops);
+	hrtimer_init(&lpm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	lpm_cpuidle_init();
 	return 0;
 fail:
 	pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
-	kfree(levels);
 	return -EFAULT;
 }
 
-static struct of_device_id msm_lpm_levels_match_table[] = {
+static struct of_device_id cpu_modes_mtch_tbl[] = {
+	{.compatible = "qcom,cpu-modes"},
+	{},
+};
+
+static struct platform_driver cpu_modes_driver = {
+	.probe = lpm_cpu_probe,
+	.driver = {
+		.name = "cpu-modes",
+		.owner = THIS_MODULE,
+		.of_match_table = cpu_modes_mtch_tbl,
+	},
+};
+
+static struct of_device_id system_modes_mtch_tbl[] = {
+	{.compatible = "qcom,system-modes"},
+	{},
+};
+
+static struct platform_driver system_modes_driver = {
+	.probe = lpm_system_probe,
+	.driver = {
+		.name = "system-modes",
+		.owner = THIS_MODULE,
+		.of_match_table = system_modes_mtch_tbl,
+	},
+};
+
+static struct of_device_id lpm_levels_match_table[] = {
 	{.compatible = "qcom,lpm-levels"},
 	{},
 };
 
-static struct platform_driver msm_lpm_levels_driver = {
-	.probe = msm_lpm_levels_probe,
+static struct platform_driver lpm_levels_driver = {
+	.probe = lpm_probe,
 	.driver = {
 		.name = "lpm-levels",
 		.owner = THIS_MODULE,
-		.of_match_table = msm_lpm_levels_match_table,
+		.of_match_table = lpm_levels_match_table,
 	},
 };
 
-static int __init msm_lpm_levels_module_init(void)
+static int __init lpm_levels_module_init(void)
 {
-	return platform_driver_register(&msm_lpm_levels_driver);
+	int rc;
+	rc = platform_driver_register(&cpu_modes_driver);
+	if (rc) {
+		pr_err("Error registering %s\n", cpu_modes_driver.driver.name);
+		goto fail;
+	}
+
+	rc = platform_driver_register(&system_modes_driver);
+	if (rc) {
+		platform_driver_unregister(&cpu_modes_driver);
+		pr_err("Error registering %s\n",
+				system_modes_driver.driver.name);
+		goto fail;
+	}
+
+	rc = platform_driver_register(&lpm_levels_driver);
+	if (rc) {
+		platform_driver_unregister(&cpu_modes_driver);
+		platform_driver_unregister(&system_modes_driver);
+		pr_err("Error registering %s\n",
+				lpm_levels_driver.driver.name);
+	}
+fail:
+	return rc;
 }
-late_initcall(msm_lpm_levels_module_init);
+late_initcall(lpm_levels_module_init);
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index e364393..5b351b4 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -505,7 +505,9 @@
 	return msm_mpm_interrupts_detectable(MSM_MPM_GIC_IRQ_DOMAIN,
 			from_idle);
 }
-void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle)
+
+void msm_mpm_enter_sleep(uint32_t sclk_count, bool from_idle,
+		const struct cpumask *cpumask)
 {
 	cycle_t wakeup = (u64)sclk_count * ARCH_TIMER_HZ;
 
@@ -522,6 +524,7 @@
 	}
 
 	msm_mpm_set(wakeup, !from_idle);
+	irq_set_affinity(msm_mpm_dev_data.mpm_ipc_irq, cpumask);
 }
 
 void msm_mpm_exit_sleep(bool from_idle)
diff --git a/arch/arm/mach-msm/msm-pm.c b/arch/arm/mach-msm/msm-pm.c
new file mode 100644
index 0000000..5f8657e
--- /dev/null
+++ b/arch/arm/mach-msm/msm-pm.c
@@ -0,0 +1,1230 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/ktime.h>
+#include <linux/smp.h>
+#include <linux/tick.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/cpu_pm.h>
+#include <asm/uaccess.h>
+#include <asm/suspend.h>
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+#include <mach/scm.h>
+#include <mach/msm_bus.h>
+#include <mach/jtag.h>
+#include "acpuclock.h"
+#include "avs.h"
+#include "idle.h"
+#include "pm.h"
+#include "scm-boot.h"
+#include "spm.h"
+#include "pm-boot.h"
+
+#define CREATE_TRACE_POINTS
+#include <mach/trace_msm_low_power.h>
+
+#define SCM_CMD_TERMINATE_PC	(0x2)
+#define SCM_CMD_CORE_HOTPLUGGED (0x10)
+
+#define GET_CPU_OF_ATTR(attr) \
+	(container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+#define SCLK_HZ (32768)
+
+#define MAX_BUF_SIZE  512
+
+static int msm_pm_debug_mask = 1;
+module_param_named(
+	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static bool use_acpuclk_apis;
+
+enum {
+	MSM_PM_DEBUG_SUSPEND = BIT(0),
+	MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
+	MSM_PM_DEBUG_SUSPEND_LIMITS = BIT(2),
+	MSM_PM_DEBUG_CLOCK = BIT(3),
+	MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
+	MSM_PM_DEBUG_IDLE_CLK = BIT(5),
+	MSM_PM_DEBUG_IDLE = BIT(6),
+	MSM_PM_DEBUG_IDLE_LIMITS = BIT(7),
+	MSM_PM_DEBUG_HOTPLUG = BIT(8),
+};
+
+enum msm_pc_count_offsets {
+	MSM_PC_ENTRY_COUNTER,
+	MSM_PC_EXIT_COUNTER,
+	MSM_PC_FALLTHRU_COUNTER,
+	MSM_PC_NUM_COUNTERS,
+};
+
+enum {
+	MSM_PM_MODE_ATTR_SUSPEND,
+	MSM_PM_MODE_ATTR_IDLE,
+	MSM_PM_MODE_ATTR_NR,
+};
+
+static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
+	[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
+	[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
+};
+
+struct msm_pm_kobj_attribute {
+	unsigned int cpu;
+	struct kobj_attribute ka;
+};
+
+struct msm_pm_sysfs_sleep_mode {
+	struct kobject *kobj;
+	struct attribute_group attr_group;
+	struct attribute *attrs[MSM_PM_MODE_ATTR_NR + 1];
+	struct msm_pm_kobj_attribute kas[MSM_PM_MODE_ATTR_NR];
+};
+
+static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
+	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
+	[MSM_PM_SLEEP_MODE_RETENTION] = "retention",
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
+		"standalone_power_collapse",
+};
+
+static bool msm_pm_ldo_retention_enabled = true;
+static bool msm_no_ramp_down_pc;
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
+DEFINE_PER_CPU(struct clk *, cpu_clks);
+static struct clk *l2_clk;
+
+static void (*msm_pm_disable_l2_fn)(void);
+static void (*msm_pm_enable_l2_fn)(void);
+static void (*msm_pm_flush_l2_fn)(void);
+static void __iomem *msm_pc_debug_counters;
+
+/*
+ * Default the l2 flush flag to OFF so the caches are flushed during power
+ * collapse unless the explicitly voted by lpm driver.
+ */
+static enum msm_pm_l2_scm_flag msm_pm_flush_l2_flag = MSM_SCM_L2_OFF;
+
+void msm_pm_set_l2_flush_flag(enum msm_pm_l2_scm_flag flag)
+{
+	msm_pm_flush_l2_flag = flag;
+}
+EXPORT_SYMBOL(msm_pm_set_l2_flush_flag);
+
+static enum msm_pm_l2_scm_flag msm_pm_get_l2_flush_flag(void)
+{
+	return msm_pm_flush_l2_flag;
+}
+
+static cpumask_t retention_cpus;
+static DEFINE_SPINLOCK(retention_lock);
+
+static int msm_pm_get_pc_mode(struct device_node *node,
+		const char *key, uint32_t *pc_mode_val)
+{
+	struct pc_mode_of {
+		uint32_t mode;
+		char *mode_name;
+	};
+	int i;
+	struct pc_mode_of pc_modes[] = {
+				{MSM_PM_PC_TZ_L2_INT, "tz_l2_int"},
+				{MSM_PM_PC_NOTZ_L2_EXT, "no_tz_l2_ext"},
+				{MSM_PM_PC_TZ_L2_EXT , "tz_l2_ext"} };
+	int ret;
+	const char *pc_mode_str;
+	*pc_mode_val = MSM_PM_PC_TZ_L2_INT;
+
+	ret = of_property_read_string(node, key, &pc_mode_str);
+	if (!ret) {
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(pc_modes); i++) {
+			if (!strncmp(pc_mode_str, pc_modes[i].mode_name,
+				strlen(pc_modes[i].mode_name))) {
+				*pc_mode_val = pc_modes[i].mode;
+				ret = 0;
+				break;
+			}
+		}
+	} else {
+		pr_debug("%s: Cannot read %s,defaulting to 0", __func__, key);
+		ret = 0;
+	}
+	return ret;
+}
+
+/*
+ * Write out the attribute.
+ */
+static ssize_t msm_pm_mode_attr_show(
+	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct kernel_param kp;
+		unsigned int cpu;
+		struct msm_pm_platform_data *mode;
+
+		if (msm_pm_sleep_mode_labels[i] == NULL)
+			continue;
+
+		if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+			continue;
+
+		cpu = GET_CPU_OF_ATTR(attr);
+		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+
+		if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
+			u32 arg = mode->suspend_enabled;
+			kp.arg = &arg;
+			ret = param_get_ulong(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
+			u32 arg = mode->idle_enabled;
+			kp.arg = &arg;
+			ret = param_get_ulong(buf, &kp);
+		}
+
+		break;
+	}
+
+	if (ret > 0) {
+		strlcat(buf, "\n", PAGE_SIZE);
+		ret++;
+	}
+
+	return ret;
+}
+
+static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct kernel_param kp;
+		unsigned int cpu;
+		struct msm_pm_platform_data *mode;
+
+		if (msm_pm_sleep_mode_labels[i] == NULL)
+			continue;
+
+		if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
+			continue;
+
+		cpu = GET_CPU_OF_ATTR(attr);
+		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+
+		if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
+			kp.arg = &mode->suspend_enabled;
+			ret = param_set_byte(buf, &kp);
+		} else if (!strcmp(attr->attr.name,
+			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
+			kp.arg = &mode->idle_enabled;
+			ret = param_set_byte(buf, &kp);
+		}
+
+		break;
+	}
+
+	return ret ? ret : count;
+}
+
+static int msm_pm_mode_sysfs_add_cpu(
+	unsigned int cpu, struct kobject *modes_kobj)
+{
+	char cpu_name[8];
+	struct kobject *cpu_kobj;
+	struct msm_pm_sysfs_sleep_mode *mode = NULL;
+	int i, j, k;
+	int ret;
+
+	snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
+	cpu_kobj = kobject_create_and_add(cpu_name, modes_kobj);
+	if (!cpu_kobj) {
+		pr_err("%s: cannot create %s kobject\n", __func__, cpu_name);
+		ret = -ENOMEM;
+		goto mode_sysfs_add_cpu_exit;
+	}
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		int idx = MSM_PM_MODE(cpu, i);
+
+		if ((!msm_pm_sleep_modes[idx].suspend_supported)
+			&& (!msm_pm_sleep_modes[idx].idle_supported))
+			continue;
+
+		if (!msm_pm_sleep_mode_labels[i] ||
+				!msm_pm_sleep_mode_labels[i][0])
+			continue;
+
+		mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+		if (!mode) {
+			pr_err("%s: cannot allocate memory for attributes\n",
+				__func__);
+			ret = -ENOMEM;
+			goto mode_sysfs_add_cpu_exit;
+		}
+
+		mode->kobj = kobject_create_and_add(
+				msm_pm_sleep_mode_labels[i], cpu_kobj);
+		if (!mode->kobj) {
+			pr_err("%s: cannot create kobject\n", __func__);
+			ret = -ENOMEM;
+			goto mode_sysfs_add_cpu_exit;
+		}
+
+		for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
+			if ((k == MSM_PM_MODE_ATTR_IDLE) &&
+				!msm_pm_sleep_modes[idx].idle_supported)
+				continue;
+			if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
+			     !msm_pm_sleep_modes[idx].suspend_supported)
+				continue;
+			sysfs_attr_init(&mode->kas[j].ka.attr);
+			mode->kas[j].cpu = cpu;
+			mode->kas[j].ka.attr.mode = 0644;
+			mode->kas[j].ka.show = msm_pm_mode_attr_show;
+			mode->kas[j].ka.store = msm_pm_mode_attr_store;
+			mode->kas[j].ka.attr.name = msm_pm_mode_attr_labels[k];
+			mode->attrs[j] = &mode->kas[j].ka.attr;
+			j++;
+		}
+		mode->attrs[j] = NULL;
+
+		mode->attr_group.attrs = mode->attrs;
+		ret = sysfs_create_group(mode->kobj, &mode->attr_group);
+		if (ret) {
+			pr_err("%s: cannot create kobject attribute group\n",
+				__func__);
+			goto mode_sysfs_add_cpu_exit;
+		}
+	}
+
+	ret = 0;
+
+mode_sysfs_add_cpu_exit:
+	if (ret) {
+		if (mode && mode->kobj)
+			kobject_del(mode->kobj);
+		kfree(mode);
+	}
+
+	return ret;
+}
+
+int msm_pm_mode_sysfs_add(void)
+{
+	struct kobject *module_kobj;
+	struct kobject *modes_kobj;
+	unsigned int cpu;
+	int ret;
+
+	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!module_kobj) {
+		pr_err("%s: cannot find kobject for module %s\n",
+			__func__, KBUILD_MODNAME);
+		ret = -ENOENT;
+		goto mode_sysfs_add_exit;
+	}
+
+	modes_kobj = kobject_create_and_add("modes", module_kobj);
+	if (!modes_kobj) {
+		pr_err("%s: cannot create modes kobject\n", __func__);
+		ret = -ENOMEM;
+		goto mode_sysfs_add_exit;
+	}
+
+	for_each_possible_cpu(cpu) {
+		ret = msm_pm_mode_sysfs_add_cpu(cpu, modes_kobj);
+		if (ret)
+			goto mode_sysfs_add_exit;
+	}
+
+	ret = 0;
+
+mode_sysfs_add_exit:
+	return ret;
+}
+
+static inline void msm_arch_idle(void)
+{
+	mb();
+	wfi();
+}
+
+static bool msm_pm_is_L1_writeback(void)
+{
+	u32 sel = 0, cache_id;
+
+	asm volatile ("mcr p15, 2, %[ccselr], c0, c0, 0\n\t"
+		      "isb\n\t"
+		      "mrc p15, 1, %[ccsidr], c0, c0, 0\n\t"
+		      :[ccsidr]"=r" (cache_id)
+		      :[ccselr]"r" (sel)
+		     );
+	return cache_id & BIT(31);
+}
+
+static enum msm_pm_time_stats_id msm_pm_swfi(bool from_idle)
+{
+	msm_arch_idle();
+	return MSM_PM_STAT_IDLE_WFI;
+}
+
+static enum msm_pm_time_stats_id msm_pm_retention(bool from_idle)
+{
+	int ret = 0;
+	int cpu = smp_processor_id();
+
+	spin_lock(&retention_lock);
+
+	if (!msm_pm_ldo_retention_enabled)
+		goto bailout;
+
+	cpumask_set_cpu(cpu, &retention_cpus);
+	spin_unlock(&retention_lock);
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
+	WARN_ON(ret);
+
+	msm_arch_idle();
+	spin_lock(&retention_lock);
+	cpumask_clear_cpu(cpu, &retention_cpus);
+bailout:
+	spin_unlock(&retention_lock);
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+
+	return MSM_PM_STAT_RETENTION;
+}
+
+static inline void msm_pc_inc_debug_count(uint32_t cpu,
+		enum msm_pc_count_offsets offset)
+{
+	uint32_t cnt;
+
+	if (!msm_pc_debug_counters)
+		return;
+
+	cnt = readl_relaxed(msm_pc_debug_counters + cpu * 4 + offset * 4);
+	writel_relaxed(++cnt, msm_pc_debug_counters + cpu * 4 + offset * 4);
+	mb();
+}
+
+static bool msm_pm_pc_hotplug(void)
+{
+	uint32_t cpu = smp_processor_id();
+
+	if (msm_pm_is_L1_writeback())
+		flush_cache_louis();
+
+	msm_pc_inc_debug_count(cpu, MSM_PC_ENTRY_COUNTER);
+
+	scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
+			SCM_CMD_CORE_HOTPLUGGED);
+
+	/* Should not return here */
+	msm_pc_inc_debug_count(cpu, MSM_PC_FALLTHRU_COUNTER);
+	return 0;
+}
+
+static int msm_pm_collapse(unsigned long unused)
+{
+	uint32_t cpu = smp_processor_id();
+
+	if (msm_pm_get_l2_flush_flag() == MSM_SCM_L2_OFF) {
+		flush_cache_all();
+		if (msm_pm_flush_l2_fn)
+			msm_pm_flush_l2_fn();
+	} else if (msm_pm_is_L1_writeback())
+		flush_cache_louis();
+
+	if (msm_pm_disable_l2_fn)
+		msm_pm_disable_l2_fn();
+
+	msm_pc_inc_debug_count(cpu, MSM_PC_ENTRY_COUNTER);
+
+	scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
+				msm_pm_get_l2_flush_flag());
+
+	msm_pc_inc_debug_count(cpu, MSM_PC_FALLTHRU_COUNTER);
+
+	if (msm_pm_enable_l2_fn)
+		msm_pm_enable_l2_fn();
+
+	return 0;
+}
+
+static bool __ref msm_pm_spm_power_collapse(
+	unsigned int cpu, bool from_idle, bool notify_rpm)
+{
+	void *entry;
+	bool collapsed = 0;
+	int ret;
+	bool save_cpu_regs = !cpu || from_idle;
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: notify_rpm %d\n",
+			cpu, __func__, (int) notify_rpm);
+
+	if (from_idle)
+		cpu_pm_enter();
+
+	ret = msm_spm_set_low_power_mode(
+			MSM_SPM_MODE_POWER_COLLAPSE, notify_rpm);
+	WARN_ON(ret);
+
+	entry = save_cpu_regs ?  cpu_resume : msm_secondary_startup;
+
+	msm_pm_boot_config_before_pc(cpu, virt_to_phys(entry));
+
+	if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: program vector to %p\n",
+			cpu, __func__, entry);
+
+	msm_jtag_save_state();
+
+	collapsed = save_cpu_regs ?
+		!cpu_suspend(0, msm_pm_collapse) : msm_pm_pc_hotplug();
+
+	msm_jtag_restore_state();
+
+	if (collapsed) {
+		cpu_init();
+		local_fiq_enable();
+	}
+
+	msm_pm_boot_config_after_pc(cpu);
+
+	if (from_idle)
+		cpu_pm_exit();
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: msm_pm_collapse returned, collapsed %d\n",
+			cpu, __func__, collapsed);
+
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+	return collapsed;
+}
+
+static enum msm_pm_time_stats_id msm_pm_power_collapse_standalone(
+		bool from_idle)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned int avsdscr;
+	unsigned int avscsr;
+	bool collapsed;
+
+	avsdscr = avs_get_avsdscr();
+	avscsr = avs_get_avscsr();
+	avs_set_avscsr(0); /* Disable AVS */
+
+	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
+
+	avs_set_avsdscr(avsdscr);
+	avs_set_avscsr(avscsr);
+	return collapsed ? MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE :
+			MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
+}
+
+static int ramp_down_last_cpu(int cpu)
+{
+	struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+	int ret = 0;
+
+	if (use_acpuclk_apis) {
+		ret = acpuclk_power_collapse();
+		if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+			pr_info("CPU%u: %s: change clk rate(old rate = %d)\n",
+					cpu, __func__, ret);
+	} else {
+		clk_disable(cpu_clk);
+		clk_disable(l2_clk);
+	}
+	return ret;
+}
+
+static int ramp_up_first_cpu(int cpu, int saved_rate)
+{
+	struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
+	int rc = 0;
+
+	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: restore clock rate\n",
+				cpu, __func__);
+
+	if (use_acpuclk_apis) {
+		rc = acpuclk_set_rate(cpu, saved_rate, SETRATE_PC);
+		if (rc)
+			pr_err("CPU:%u: Error restoring cpu clk\n", cpu);
+	} else {
+		if (l2_clk) {
+			rc = clk_enable(l2_clk);
+			if (rc)
+				pr_err("%s(): Error restoring l2 clk\n",
+						__func__);
+		}
+
+		if (cpu_clk) {
+			int ret = clk_enable(cpu_clk);
+
+			if (ret) {
+				pr_err("%s(): Error restoring cpu clk\n",
+						__func__);
+				return ret;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static enum msm_pm_time_stats_id msm_pm_power_collapse(bool from_idle)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned long saved_acpuclk_rate = 0;
+	unsigned int avsdscr;
+	unsigned int avscsr;
+	bool collapsed;
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: idle %d\n",
+			cpu, __func__, (int)from_idle);
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
+
+	avsdscr = avs_get_avsdscr();
+	avscsr = avs_get_avscsr();
+	avs_set_avscsr(0); /* Disable AVS */
+
+	if (cpu_online(cpu) && !msm_no_ramp_down_pc)
+		saved_acpuclk_rate = ramp_down_last_cpu(cpu);
+
+	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
+
+	if (cpu_online(cpu) && !msm_no_ramp_down_pc)
+		ramp_up_first_cpu(cpu, saved_acpuclk_rate);
+
+	avs_set_avsdscr(avsdscr);
+	avs_set_avscsr(avscsr);
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: post power up\n", cpu, __func__);
+
+	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: return\n", cpu, __func__);
+	return collapsed ? MSM_PM_STAT_IDLE_POWER_COLLAPSE :
+			MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+}
+/******************************************************************************
+ * External Idle/Suspend Functions
+ *****************************************************************************/
+
+void arch_idle(void)
+{
+	return;
+}
+
+static inline void msm_pm_ftrace_lpm_enter(unsigned int cpu,
+		uint32_t latency, uint32_t sleep_us,
+		uint32_t wake_up,
+		enum msm_pm_sleep_mode mode)
+{
+	switch (mode) {
+	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+		trace_msm_pm_enter_wfi(cpu, latency, sleep_us, wake_up);
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+		trace_msm_pm_enter_spc(cpu, latency, sleep_us, wake_up);
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		trace_msm_pm_enter_pc(cpu, latency, sleep_us, wake_up);
+		break;
+	case MSM_PM_SLEEP_MODE_RETENTION:
+		trace_msm_pm_enter_ret(cpu, latency, sleep_us, wake_up);
+		break;
+	default:
+		break;
+	}
+}
+
+static inline void msm_pm_ftrace_lpm_exit(unsigned int cpu,
+		enum msm_pm_sleep_mode mode,
+		bool success)
+{
+	switch (mode) {
+	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+		trace_msm_pm_exit_wfi(cpu, success);
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+		trace_msm_pm_exit_spc(cpu, success);
+		break;
+	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
+		trace_msm_pm_exit_pc(cpu, success);
+		break;
+	case MSM_PM_SLEEP_MODE_RETENTION:
+		trace_msm_pm_exit_ret(cpu, success);
+		break;
+	default:
+		break;
+	}
+}
+
+static enum msm_pm_time_stats_id (*execute[MSM_PM_SLEEP_MODE_NR])(bool idle) = {
+	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = msm_pm_swfi,
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
+		msm_pm_power_collapse_standalone,
+	[MSM_PM_SLEEP_MODE_RETENTION] = msm_pm_retention,
+	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = msm_pm_power_collapse,
+};
+
+bool msm_cpu_pm_check_mode(unsigned int cpu, enum msm_pm_sleep_mode mode,
+		bool from_idle)
+{
+	int idx = MSM_PM_MODE(cpu, mode);
+	struct msm_pm_platform_data *d = &msm_pm_sleep_modes[idx];
+
+	if ((mode == MSM_PM_SLEEP_MODE_RETENTION)
+			&& !msm_pm_ldo_retention_enabled)
+		return false;
+
+	if (from_idle)
+		return d->idle_enabled && d->idle_supported;
+	else
+		return d->suspend_enabled && d->suspend_supported;
+}
+
+int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle)
+{
+	int64_t time;
+	bool collapsed = 1;
+	int exit_stat = -1;
+
+	if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
+		pr_info("CPU%u: %s: mode %d\n",
+			smp_processor_id(), __func__, mode);
+	if (!from_idle)
+		pr_info("CPU%u: %s mode:%d\n",
+			smp_processor_id(), __func__, mode);
+
+	time = sched_clock();
+	if (execute[mode])
+		exit_stat = execute[mode](from_idle);
+	time = sched_clock() - time;
+	if (from_idle)
+		msm_pm_ftrace_lpm_exit(smp_processor_id(), mode, collapsed);
+	else
+		exit_stat = MSM_PM_STAT_SUSPEND;
+	if (exit_stat >= 0)
+		msm_pm_add_stat(exit_stat, time);
+	do_div(time, 1000);
+	return collapsed;
+}
+
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
+	int timeout = 10;
+
+	if (!msm_pm_slp_sts)
+		return 0;
+	if (!msm_pm_slp_sts[cpu].base_addr)
+		return 0;
+	while (timeout--) {
+		/*
+		 * Check for the SPM of the core being hotplugged to set
+		 * its sleep state.The SPM sleep state indicates that the
+		 * core has been power collapsed.
+		 */
+		int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr);
+
+		if (acc_sts & msm_pm_slp_sts[cpu].mask)
+			return 0;
+		udelay(100);
+	}
+
+	pr_info("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+		__func__, cpu);
+	return -EBUSY;
+}
+
+void msm_pm_cpu_enter_lowpower(unsigned int cpu)
+{
+	int i;
+	bool allow[MSM_PM_SLEEP_MODE_NR];
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct msm_pm_platform_data *mode;
+
+		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
+		allow[i] = mode->suspend_supported && mode->suspend_enabled;
+	}
+
+	if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
+		pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+		msm_pm_power_collapse(false);
+	else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
+		msm_pm_power_collapse_standalone(false);
+	else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
+		msm_pm_retention(false);
+	else
+		msm_pm_swfi(false);
+}
+
+static void msm_pm_ack_retention_disable(void *data)
+{
+	/*
+	 * This is a NULL function to ensure that the core has woken up
+	 * and is safe to disable retention.
+	 */
+}
+/**
+ * msm_pm_enable_retention() - Disable/Enable retention on all cores
+ * @enable: Enable/Disable retention
+ *
+ */
+void msm_pm_enable_retention(bool enable)
+{
+	if (enable == msm_pm_ldo_retention_enabled)
+		return;
+
+	msm_pm_ldo_retention_enabled = enable;
+
+	/*
+	 * If retention is being disabled, wakeup all online core to ensure
+	 * that it isn't executing retention. Offlined cores need not be woken
+	 * up as they enter the deepest sleep mode, namely RPM assited power
+	 * collapse
+	 */
+	if (!enable) {
+		preempt_disable();
+		smp_call_function_many(&retention_cpus,
+				msm_pm_ack_retention_disable,
+				NULL, true);
+		preempt_enable();
+	}
+}
+EXPORT_SYMBOL(msm_pm_enable_retention);
+
+static int msm_pm_snoc_client_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	static struct msm_bus_scale_pdata *msm_pm_bus_pdata;
+	static uint32_t msm_pm_bus_client;
+
+	msm_pm_bus_pdata = msm_bus_cl_get_pdata(pdev);
+
+	if (msm_pm_bus_pdata) {
+		msm_pm_bus_client =
+			msm_bus_scale_register_client(msm_pm_bus_pdata);
+
+		if (!msm_pm_bus_client) {
+			pr_err("%s: Failed to register SNOC client", __func__);
+			rc = -ENXIO;
+			goto snoc_cl_probe_done;
+		}
+
+		rc = msm_bus_scale_client_update_request(msm_pm_bus_client, 1);
+
+		if (rc)
+			pr_err("%s: Error setting bus rate", __func__);
+	}
+
+snoc_cl_probe_done:
+	return rc;
+}
+
+static int msm_cpu_status_probe(struct platform_device *pdev)
+{
+	struct msm_pm_sleep_status_data *pdata;
+	char *key;
+	u32 cpu;
+
+	if (!pdev)
+		return -EFAULT;
+
+	msm_pm_slp_sts = devm_kzalloc(&pdev->dev,
+			sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
+			GFP_KERNEL);
+
+	if (!msm_pm_slp_sts)
+		return -ENOMEM;
+
+	if (pdev->dev.of_node) {
+		struct resource *res;
+		u32 offset;
+		int rc;
+		u32 mask;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (!res)
+			return -ENODEV;
+
+		key = "qcom,cpu-alias-addr";
+		rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
+
+		if (rc)
+			return -ENODEV;
+
+		key = "qcom,sleep-status-mask";
+		rc = of_property_read_u32(pdev->dev.of_node, key, &mask);
+
+		if (rc)
+			return -ENODEV;
+
+		for_each_possible_cpu(cpu) {
+			phys_addr_t base_c = res->start + cpu * offset;
+			msm_pm_slp_sts[cpu].base_addr =
+				devm_ioremap(&pdev->dev, base_c,
+						resource_size(res));
+			msm_pm_slp_sts[cpu].mask = mask;
+
+			if (!msm_pm_slp_sts[cpu].base_addr)
+				return -ENOMEM;
+		}
+	} else {
+		pdata = pdev->dev.platform_data;
+		if (!pdev->dev.platform_data)
+			return -EINVAL;
+
+		for_each_possible_cpu(cpu) {
+			msm_pm_slp_sts[cpu].base_addr =
+				pdata->base_addr + cpu * pdata->cpu_offset;
+			msm_pm_slp_sts[cpu].mask = pdata->mask;
+		}
+	}
+
+	return 0;
+};
+
+static struct of_device_id msm_slp_sts_match_tbl[] = {
+	{.compatible = "qcom,cpu-sleep-status"},
+	{},
+};
+
+static struct platform_driver msm_cpu_status_driver = {
+	.probe = msm_cpu_status_probe,
+	.driver = {
+		.name = "cpu_slp_status",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_slp_sts_match_tbl,
+	},
+};
+
+static struct of_device_id msm_snoc_clnt_match_tbl[] = {
+	{.compatible = "qcom,pm-snoc-client"},
+	{},
+};
+
+static struct platform_driver msm_cpu_pm_snoc_client_driver = {
+	.probe = msm_pm_snoc_client_probe,
+	.driver = {
+		.name = "pm_snoc_client",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_snoc_clnt_match_tbl,
+	},
+};
+
+static int msm_pm_init(void)
+{
+	enum msm_pm_time_stats_id enable_stats[] = {
+		MSM_PM_STAT_IDLE_WFI,
+		MSM_PM_STAT_RETENTION,
+		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
+		MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
+		MSM_PM_STAT_SUSPEND,
+	};
+	msm_pm_mode_sysfs_add();
+	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
+
+	return 0;
+}
+
+static void msm_pm_set_flush_fn(uint32_t pc_mode)
+{
+	msm_pm_disable_l2_fn = NULL;
+	msm_pm_enable_l2_fn = NULL;
+	msm_pm_flush_l2_fn = outer_flush_all;
+
+	if (pc_mode == MSM_PM_PC_NOTZ_L2_EXT) {
+		msm_pm_disable_l2_fn = outer_disable;
+		msm_pm_enable_l2_fn = outer_resume;
+	}
+}
+
+struct msm_pc_debug_counters_buffer {
+	void __iomem *reg;
+	u32 len;
+	char buf[MAX_BUF_SIZE];
+};
+
+static inline u32 msm_pc_debug_counters_read_register(
+		void __iomem *reg, int index , int offset)
+{
+	return readl_relaxed(reg + (index * 4 + offset) * 4);
+}
+
+static char *counter_name[] = {
+		"PC Entry Counter",
+		"Warmboot Entry Counter",
+		"PC Bailout Counter"
+};
+
+static int msm_pc_debug_counters_copy(
+		struct msm_pc_debug_counters_buffer *data)
+{
+	int j;
+	u32 stat;
+	unsigned int cpu;
+
+	for_each_possible_cpu(cpu) {
+		data->len += scnprintf(data->buf + data->len,
+				sizeof(data->buf)-data->len,
+				"CPU%d\n", cpu);
+
+		for (j = 0; j < MSM_PC_NUM_COUNTERS; j++) {
+			stat = msm_pc_debug_counters_read_register(
+					data->reg, cpu, j);
+			data->len += scnprintf(data->buf + data->len,
+					sizeof(data->buf)-data->len,
+					"\t%s : %d\n", counter_name[j],
+					stat);
+		}
+
+	}
+
+	return data->len;
+}
+
+static int msm_pc_debug_counters_file_read(struct file *file,
+		char __user *bufu, size_t count, loff_t *ppos)
+{
+	struct msm_pc_debug_counters_buffer *data;
+
+	data = file->private_data;
+
+	if (!data)
+		return -EINVAL;
+
+	if (!bufu || count < 0)
+		return -EINVAL;
+
+	if (!access_ok(VERIFY_WRITE, bufu, count))
+		return -EFAULT;
+
+	if (*ppos >= data->len && data->len == 0)
+		data->len = msm_pc_debug_counters_copy(data);
+
+	return simple_read_from_buffer(bufu, count, ppos,
+			data->buf, data->len);
+}
+
+static int msm_pc_debug_counters_file_open(struct inode *inode,
+		struct file *file)
+{
+	struct msm_pc_debug_counters_buffer *buf;
+	void __iomem *msm_pc_debug_counters_reg;
+
+	msm_pc_debug_counters_reg = inode->i_private;
+
+	if (!msm_pc_debug_counters_reg)
+		return -EINVAL;
+
+	file->private_data = kzalloc(
+		sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
+
+	if (!file->private_data) {
+		pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+		__func__, sizeof(struct msm_pc_debug_counters_buffer));
+
+		return -ENOMEM;
+	}
+
+	buf = file->private_data;
+	buf->reg = msm_pc_debug_counters_reg;
+
+	return 0;
+}
+
+static int msm_pc_debug_counters_file_close(struct inode *inode,
+		struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static const struct file_operations msm_pc_debug_counters_fops = {
+	.open = msm_pc_debug_counters_file_open,
+	.read = msm_pc_debug_counters_file_read,
+	.release = msm_pc_debug_counters_file_close,
+	.llseek = no_llseek,
+};
+
+static int msm_pm_clk_init(struct platform_device *pdev)
+{
+	bool synced_clocks;
+	u32 cpu;
+	char clk_name[] = "cpu??_clk";
+	bool cpu_as_clocks;
+	char *key;
+
+	key = "qcom,cpus-as-clocks";
+	cpu_as_clocks = of_property_read_bool(pdev->dev.of_node, key);
+
+	if (!cpu_as_clocks) {
+		use_acpuclk_apis = true;
+		return 0;
+	}
+
+	key = "qcom,synced-clocks";
+	synced_clocks = of_property_read_bool(pdev->dev.of_node, key);
+
+	for_each_possible_cpu(cpu) {
+		struct clk *clk;
+		snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
+		clk = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(clk)) {
+			if (cpu && synced_clocks)
+				return 0;
+			else
+				return PTR_ERR(clk);
+		}
+		per_cpu(cpu_clks, cpu) = clk;
+	}
+
+	if (synced_clocks)
+		return 0;
+
+	l2_clk = devm_clk_get(&pdev->dev, "l2_clk");
+
+	return PTR_RET(l2_clk);
+}
+
+static int msm_cpu_pm_probe(struct platform_device *pdev)
+{
+	char *key = NULL;
+	struct dentry *dent = NULL;
+	struct resource *res = NULL;
+	int i;
+	struct msm_pm_init_data_type pdata_local;
+	int ret = 0;
+
+	memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return  0;
+	msm_pc_debug_counters_phys = res->start;
+	WARN_ON(resource_size(res) < SZ_64);
+	msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+					resource_size(res));
+	if (msm_pc_debug_counters) {
+		for (i = 0; i < resource_size(res)/4; i++)
+			__raw_writel(0, msm_pc_debug_counters + i * 4);
+
+		dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
+				msm_pc_debug_counters,
+				&msm_pc_debug_counters_fops);
+		if (!dent)
+			pr_err("%s: ERROR debugfs_create_file failed\n",
+					__func__);
+	} else {
+		msm_pc_debug_counters = 0;
+		msm_pc_debug_counters_phys = 0;
+	}
+
+	if (pdev->dev.of_node) {
+		enum msm_pm_pc_mode_type pc_mode;
+
+		ret = msm_pm_clk_init(pdev);
+		if (ret) {
+			pr_info("msm_pm_clk_init returned error\n");
+			return ret;
+		}
+
+		key = "qcom,pc-mode";
+		ret = msm_pm_get_pc_mode(pdev->dev.of_node, key, &pc_mode);
+		if (ret) {
+			pr_debug("%s: Error reading key %s", __func__, key);
+			return -EINVAL;
+		}
+		msm_pm_set_flush_fn(pc_mode);
+	}
+
+	msm_pm_init();
+	if (pdev->dev.of_node)
+		of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+	return ret;
+}
+
+static struct of_device_id msm_cpu_pm_table[] = {
+	{.compatible = "qcom,pm-8x60"},
+	{},
+};
+
+static struct platform_driver msm_cpu_pm_driver = {
+	.probe = msm_cpu_pm_probe,
+	.driver = {
+		.name = "pm-8x60",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_cpu_pm_table,
+	},
+};
+
+static int __init msm_cpu_pm_init(void)
+{
+	int rc;
+
+	cpumask_clear(&retention_cpus);
+
+	rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
+
+	if (rc) {
+		pr_err("%s(): failed to register driver %s\n", __func__,
+				msm_cpu_pm_snoc_client_driver.driver.name);
+		return rc;
+	}
+
+	return platform_driver_register(&msm_cpu_pm_driver);
+}
+device_initcall(msm_cpu_pm_init);
+
+void __init msm_pm_sleep_status_init(void)
+{
+	platform_driver_register(&msm_cpu_status_driver);
+}
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
deleted file mode 100644
index c8a6496..0000000
--- a/arch/arm/mach-msm/pm-8x60.c
+++ /dev/null
@@ -1,1845 +0,0 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
-#include <linux/completion.h>
-#include <linux/cpuidle.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/ktime.h>
-#include <linux/pm.h>
-#include <linux/pm_qos.h>
-#include <linux/smp.h>
-#include <linux/suspend.h>
-#include <linux/tick.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/of_platform.h>
-#include <linux/regulator/krait-regulator.h>
-#include <linux/cpu.h>
-#include <mach/msm_iomap.h>
-#include <mach/socinfo.h>
-#include <mach/system.h>
-#include <mach/scm.h>
-#include <mach/socinfo.h>
-#define CREATE_TRACE_POINTS
-#include <mach/trace_msm_low_power.h>
-#include <mach/msm-krait-l2-accessors.h>
-#include <mach/msm_bus.h>
-#include <mach/mpm.h>
-#include <asm/cacheflush.h>
-#include <asm/hardware/gic.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/outercache.h>
-#ifdef CONFIG_VFP
-#include <asm/vfp.h>
-#endif
-#include "acpuclock.h"
-#include "clock.h"
-#include "avs.h"
-#include <mach/cpuidle.h>
-#include "idle.h"
-#include "pm.h"
-#include "scm-boot.h"
-#include "spm.h"
-#include "timer.h"
-#include "pm-boot.h"
-#include <mach/event_timer.h>
-#include <linux/cpu_pm.h>
-
-#define SCM_L2_RETENTION	(0x2)
-#define SCM_CMD_TERMINATE_PC	(0x2)
-
-#define GET_CPU_OF_ATTR(attr) \
-	(container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
-
-#define SCLK_HZ (32768)
-
-#define NUM_OF_COUNTERS 3
-#define MAX_BUF_SIZE  512
-
-static int msm_pm_debug_mask = 1;
-module_param_named(
-	debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
-	msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-static bool use_acpuclk_apis;
-
-enum {
-	MSM_PM_DEBUG_SUSPEND = BIT(0),
-	MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
-	MSM_PM_DEBUG_SUSPEND_LIMITS = BIT(2),
-	MSM_PM_DEBUG_CLOCK = BIT(3),
-	MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
-	MSM_PM_DEBUG_IDLE_CLK = BIT(5),
-	MSM_PM_DEBUG_IDLE = BIT(6),
-	MSM_PM_DEBUG_IDLE_LIMITS = BIT(7),
-	MSM_PM_DEBUG_HOTPLUG = BIT(8),
-};
-
-enum {
-	MSM_PM_MODE_ATTR_SUSPEND,
-	MSM_PM_MODE_ATTR_IDLE,
-	MSM_PM_MODE_ATTR_NR,
-};
-
-static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
-	[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
-	[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
-};
-
-struct msm_pm_kobj_attribute {
-	unsigned int cpu;
-	struct kobj_attribute ka;
-};
-
-struct msm_pm_sysfs_sleep_mode {
-	struct kobject *kobj;
-	struct attribute_group attr_group;
-	struct attribute *attrs[MSM_PM_MODE_ATTR_NR + 1];
-	struct msm_pm_kobj_attribute kas[MSM_PM_MODE_ATTR_NR];
-};
-
-static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
-	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
-	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
-	[MSM_PM_SLEEP_MODE_RETENTION] = "retention",
-	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
-		"standalone_power_collapse",
-};
-
-static struct hrtimer pm_hrtimer;
-static struct msm_pm_sleep_ops pm_sleep_ops;
-static bool msm_pm_ldo_retention_enabled = true;
-static bool msm_pm_use_sync_timer;
-static struct msm_pm_cp15_save_data cp15_data;
-static bool msm_pm_retention_calls_tz;
-static bool msm_no_ramp_down_pc;
-static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
-static bool msm_pm_pc_reset_timer;
-
-DEFINE_PER_CPU(struct clk *, cpu_clks);
-static struct clk *l2_clk;
-
-static int msm_pm_get_pc_mode(struct device_node *node,
-		const char *key, uint32_t *pc_mode_val)
-{
-	struct pc_mode_of {
-		uint32_t mode;
-		char *mode_name;
-	};
-	int i;
-	struct pc_mode_of pc_modes[] = {
-				{MSM_PM_PC_TZ_L2_INT, "tz_l2_int"},
-				{MSM_PM_PC_NOTZ_L2_EXT, "no_tz_l2_ext"},
-				{MSM_PM_PC_TZ_L2_EXT , "tz_l2_ext"} };
-	int ret;
-	const char *pc_mode_str;
-
-	ret = of_property_read_string(node, key, &pc_mode_str);
-	if (ret) {
-		pr_debug("%s: Cannot read %s,defaulting to 0", __func__, key);
-		pc_mode_val = MSM_PM_PC_TZ_L2_INT;
-		ret = 0;
-	} else {
-		ret = -EINVAL;
-		for (i = 0; i < ARRAY_SIZE(pc_modes); i++) {
-			if (!strncmp(pc_mode_str, pc_modes[i].mode_name,
-				strlen(pc_modes[i].mode_name))) {
-				*pc_mode_val = pc_modes[i].mode;
-				ret = 0;
-				break;
-			}
-		}
-	}
-	return ret;
-}
-
-/*
- * Write out the attribute.
- */
-static ssize_t msm_pm_mode_attr_show(
-	struct kobject *kobj, struct kobj_attribute *attr, char *buf)
-{
-	int ret = -EINVAL;
-	int i;
-
-	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
-		struct kernel_param kp;
-		unsigned int cpu;
-		struct msm_pm_platform_data *mode;
-
-		if (msm_pm_sleep_mode_labels[i] == NULL)
-			continue;
-
-		if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
-			continue;
-
-		cpu = GET_CPU_OF_ATTR(attr);
-		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
-
-		if (!strcmp(attr->attr.name,
-			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
-			u32 arg = mode->suspend_enabled;
-			kp.arg = &arg;
-			ret = param_get_ulong(buf, &kp);
-		} else if (!strcmp(attr->attr.name,
-			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
-			u32 arg = mode->idle_enabled;
-			kp.arg = &arg;
-			ret = param_get_ulong(buf, &kp);
-		}
-
-		break;
-	}
-
-	if (ret > 0) {
-		strlcat(buf, "\n", PAGE_SIZE);
-		ret++;
-	}
-
-	return ret;
-}
-
-static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
-	struct kobj_attribute *attr, const char *buf, size_t count)
-{
-	int ret = -EINVAL;
-	int i;
-
-	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
-		struct kernel_param kp;
-		unsigned int cpu;
-		struct msm_pm_platform_data *mode;
-
-		if (msm_pm_sleep_mode_labels[i] == NULL)
-			continue;
-
-		if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
-			continue;
-
-		cpu = GET_CPU_OF_ATTR(attr);
-		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
-
-		if (!strcmp(attr->attr.name,
-			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
-			kp.arg = &mode->suspend_enabled;
-			ret = param_set_byte(buf, &kp);
-		} else if (!strcmp(attr->attr.name,
-			msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
-			kp.arg = &mode->idle_enabled;
-			ret = param_set_byte(buf, &kp);
-		}
-
-		break;
-	}
-
-	return ret ? ret : count;
-}
-
-static int __devinit msm_pm_mode_sysfs_add_cpu(
-	unsigned int cpu, struct kobject *modes_kobj)
-{
-	char cpu_name[8];
-	struct kobject *cpu_kobj;
-	struct msm_pm_sysfs_sleep_mode *mode = NULL;
-	int i, j, k;
-	int ret;
-
-	snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
-	cpu_kobj = kobject_create_and_add(cpu_name, modes_kobj);
-	if (!cpu_kobj) {
-		pr_err("%s: cannot create %s kobject\n", __func__, cpu_name);
-		ret = -ENOMEM;
-		goto mode_sysfs_add_cpu_exit;
-	}
-
-	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
-		int idx = MSM_PM_MODE(cpu, i);
-
-		if ((!msm_pm_sleep_modes[idx].suspend_supported)
-			&& (!msm_pm_sleep_modes[idx].idle_supported))
-			continue;
-
-		if (!msm_pm_sleep_mode_labels[i] ||
-				!msm_pm_sleep_mode_labels[i][0])
-			continue;
-
-		mode = kzalloc(sizeof(*mode), GFP_KERNEL);
-		if (!mode) {
-			pr_err("%s: cannot allocate memory for attributes\n",
-				__func__);
-			ret = -ENOMEM;
-			goto mode_sysfs_add_cpu_exit;
-		}
-
-		mode->kobj = kobject_create_and_add(
-				msm_pm_sleep_mode_labels[i], cpu_kobj);
-		if (!mode->kobj) {
-			pr_err("%s: cannot create kobject\n", __func__);
-			ret = -ENOMEM;
-			goto mode_sysfs_add_cpu_exit;
-		}
-
-		for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
-			if ((k == MSM_PM_MODE_ATTR_IDLE) &&
-				!msm_pm_sleep_modes[idx].idle_supported)
-				continue;
-			if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
-			     !msm_pm_sleep_modes[idx].suspend_supported)
-				continue;
-			sysfs_attr_init(&mode->kas[j].ka.attr);
-			mode->kas[j].cpu = cpu;
-			mode->kas[j].ka.attr.mode = 0644;
-			mode->kas[j].ka.show = msm_pm_mode_attr_show;
-			mode->kas[j].ka.store = msm_pm_mode_attr_store;
-			mode->kas[j].ka.attr.name = msm_pm_mode_attr_labels[k];
-			mode->attrs[j] = &mode->kas[j].ka.attr;
-			j++;
-		}
-		mode->attrs[j] = NULL;
-
-		mode->attr_group.attrs = mode->attrs;
-		ret = sysfs_create_group(mode->kobj, &mode->attr_group);
-		if (ret) {
-			pr_err("%s: cannot create kobject attribute group\n",
-				__func__);
-			goto mode_sysfs_add_cpu_exit;
-		}
-	}
-
-	ret = 0;
-
-mode_sysfs_add_cpu_exit:
-	if (ret) {
-		if (mode && mode->kobj)
-			kobject_del(mode->kobj);
-		kfree(mode);
-	}
-
-	return ret;
-}
-
-int __devinit msm_pm_mode_sysfs_add(void)
-{
-	struct kobject *module_kobj;
-	struct kobject *modes_kobj;
-	unsigned int cpu;
-	int ret;
-
-	module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
-	if (!module_kobj) {
-		pr_err("%s: cannot find kobject for module %s\n",
-			__func__, KBUILD_MODNAME);
-		ret = -ENOENT;
-		goto mode_sysfs_add_exit;
-	}
-
-	modes_kobj = kobject_create_and_add("modes", module_kobj);
-	if (!modes_kobj) {
-		pr_err("%s: cannot create modes kobject\n", __func__);
-		ret = -ENOMEM;
-		goto mode_sysfs_add_exit;
-	}
-
-	for_each_possible_cpu(cpu) {
-		ret = msm_pm_mode_sysfs_add_cpu(cpu, modes_kobj);
-		if (ret)
-			goto mode_sysfs_add_exit;
-	}
-
-	ret = 0;
-
-mode_sysfs_add_exit:
-	return ret;
-}
-
-/*
- * Configure hardware registers in preparation for Apps power down.
- */
-static void msm_pm_config_hw_before_power_down(void)
-{
-	return;
-}
-
-/*
- * Clear hardware registers after Apps powers up.
- */
-static void msm_pm_config_hw_after_power_up(void)
-{
-}
-
-/*
- * Configure hardware registers in preparation for SWFI.
- */
-static void msm_pm_config_hw_before_swfi(void)
-{
-	return;
-}
-
-/*
- * Configure/Restore hardware registers in preparation for Retention.
- */
-
-static void msm_pm_config_hw_after_retention(void)
-{
-	int ret;
-
-	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
-	WARN_ON(ret);
-}
-
-static void msm_pm_config_hw_before_retention(void)
-{
-	return;
-}
-
-static void msm_pm_save_cpu_reg(void)
-{
-	int i;
-
-	/* Only on core0 */
-	if (smp_processor_id())
-		return;
-
-	/**
-	 * On some targets, L2 PC will turn off may reset the core
-	 * configuration for the mux and the default may not make the core
-	 * happy when it resumes.
-	 * Save the active vdd, and set the core vdd to QSB max vdd, so that
-	 * when the core resumes, it is capable of supporting the current QSB
-	 * rate. Then restore the active vdd before switching the acpuclk rate.
-	 */
-	if (msm_pm_get_l2_flush_flag() == 1) {
-		cp15_data.active_vdd = msm_spm_get_vdd(0);
-		for (i = 0; i < cp15_data.reg_saved_state_size; i++)
-			cp15_data.reg_val[i] =
-				get_l2_indirect_reg(
-					cp15_data.reg_data[i]);
-		msm_spm_set_vdd(0, cp15_data.qsb_pc_vdd);
-	}
-}
-
-static void msm_pm_restore_cpu_reg(void)
-{
-	int i;
-
-	/* Only on core0 */
-	if (smp_processor_id())
-		return;
-
-	if (msm_pm_get_l2_flush_flag() == 1) {
-		for (i = 0; i < cp15_data.reg_saved_state_size; i++)
-			set_l2_indirect_reg(
-					cp15_data.reg_data[i],
-					cp15_data.reg_val[i]);
-		msm_spm_set_vdd(0, cp15_data.active_vdd);
-	}
-}
-
-static void msm_pm_swfi(void)
-{
-	msm_pm_config_hw_before_swfi();
-	msm_arch_idle();
-}
-
-static void msm_pm_retention(void)
-{
-	int ret = 0;
-
-	msm_pm_config_hw_before_retention();
-	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
-	WARN_ON(ret);
-
-	if (msm_pm_retention_calls_tz)
-		scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
-					SCM_L2_RETENTION);
-	else
-		msm_arch_idle();
-
-	msm_pm_config_hw_after_retention();
-}
-
-static bool __ref msm_pm_spm_power_collapse(
-	unsigned int cpu, bool from_idle, bool notify_rpm)
-{
-	void *entry;
-	bool collapsed = 0;
-	int ret;
-	bool save_cpu_regs = !cpu || from_idle;
-	unsigned int saved_gic_cpu_ctrl;
-
-	saved_gic_cpu_ctrl = readl_relaxed(MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
-	mb();
-
-	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: notify_rpm %d\n",
-			cpu, __func__, (int) notify_rpm);
-
-	if (from_idle == true)
-		cpu_pm_enter();
-
-	ret = msm_spm_set_low_power_mode(
-			MSM_SPM_MODE_POWER_COLLAPSE, notify_rpm);
-	WARN_ON(ret);
-
-	entry = save_cpu_regs ?  msm_pm_collapse_exit : msm_secondary_startup;
-
-	msm_pm_boot_config_before_pc(cpu, virt_to_phys(entry));
-
-	if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: program vector to %p\n",
-			cpu, __func__, entry);
-	if (from_idle && msm_pm_pc_reset_timer)
-		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
-
-#ifdef CONFIG_VFP
-	vfp_pm_suspend();
-#endif
-	collapsed = save_cpu_regs ? msm_pm_collapse() : msm_pm_pc_hotplug();
-
-	if (from_idle && msm_pm_pc_reset_timer)
-		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
-
-	msm_pm_boot_config_after_pc(cpu);
-
-	if (collapsed) {
-#ifdef CONFIG_VFP
-		vfp_pm_resume();
-#endif
-		cpu_init();
-		writel(0xF0, MSM_QGIC_CPU_BASE + GIC_CPU_PRIMASK);
-		writel_relaxed(saved_gic_cpu_ctrl,
-				MSM_QGIC_CPU_BASE + GIC_CPU_CTRL);
-		mb();
-		local_fiq_enable();
-	}
-
-	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: msm_pm_collapse returned, collapsed %d\n",
-			cpu, __func__, collapsed);
-
-	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
-	WARN_ON(ret);
-
-	if (from_idle == true)
-		cpu_pm_exit();
-
-	return collapsed;
-}
-
-static bool msm_pm_power_collapse_standalone(bool from_idle)
-{
-	unsigned int cpu = smp_processor_id();
-	unsigned int avsdscr;
-	unsigned int avscsr;
-	bool collapsed;
-
-	avsdscr = avs_get_avsdscr();
-	avscsr = avs_get_avscsr();
-	avs_set_avscsr(0); /* Disable AVS */
-
-	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
-
-	avs_set_avsdscr(avsdscr);
-	avs_set_avscsr(avscsr);
-	return collapsed;
-}
-
-static int ramp_down_last_cpu(int cpu)
-{
-	struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
-	int ret = 0;
-
-	if (use_acpuclk_apis) {
-		ret = acpuclk_power_collapse();
-		if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
-			pr_info("CPU%u: %s: change clk rate(old rate = %d)\n",
-					cpu, __func__, ret);
-	} else {
-		clk_disable(cpu_clk);
-		clk_disable(l2_clk);
-	}
-	return ret;
-}
-
-static int ramp_up_first_cpu(int cpu, int saved_rate)
-{
-	struct clk *cpu_clk = per_cpu(cpu_clks, cpu);
-	int rc = 0;
-
-	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: restore clock rate\n",
-				cpu, __func__);
-
-	if (use_acpuclk_apis) {
-		rc = acpuclk_set_rate(cpu, saved_rate, SETRATE_PC);
-		if (rc)
-			pr_err("CPU:%u: Error restoring cpu clk\n", cpu);
-	} else {
-		if (l2_clk) {
-			rc = clk_enable(l2_clk);
-			if (rc)
-				pr_err("%s(): Error restoring l2 clk\n",
-						__func__);
-		}
-
-		if (cpu_clk) {
-			int ret = clk_enable(cpu_clk);
-
-			if (ret) {
-				pr_err("%s(): Error restoring cpu clk\n",
-						__func__);
-				return ret;
-			}
-		}
-	}
-
-	return rc;
-}
-
-static bool msm_pm_power_collapse(bool from_idle)
-{
-	unsigned int cpu = smp_processor_id();
-	unsigned long saved_acpuclk_rate = 0;
-	unsigned int avsdscr;
-	unsigned int avscsr;
-	bool collapsed;
-
-	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: idle %d\n",
-			cpu, __func__, (int)from_idle);
-
-	msm_pm_config_hw_before_power_down();
-	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
-
-	avsdscr = avs_get_avsdscr();
-	avscsr = avs_get_avscsr();
-	avs_set_avscsr(0); /* Disable AVS */
-
-	if (cpu_online(cpu) && !msm_no_ramp_down_pc)
-		saved_acpuclk_rate = ramp_down_last_cpu(cpu);
-
-	if (cp15_data.save_cp15)
-		msm_pm_save_cpu_reg();
-
-	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
-
-	if (cp15_data.save_cp15)
-		msm_pm_restore_cpu_reg();
-
-	if (cpu_online(cpu) && !msm_no_ramp_down_pc) {
-		ramp_up_first_cpu(cpu, saved_acpuclk_rate);
-	} else {
-		unsigned int gic_dist_enabled;
-		unsigned int gic_dist_pending;
-		gic_dist_enabled = readl_relaxed(
-				MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR);
-		gic_dist_pending = readl_relaxed(
-				MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET);
-		mb();
-		gic_dist_pending &= gic_dist_enabled;
-
-		if (gic_dist_pending)
-			pr_err("CPU %d interrupted during hotplug.Pending int 0x%x\n",
-					cpu, gic_dist_pending);
-	}
-
-
-	avs_set_avsdscr(avsdscr);
-	avs_set_avscsr(avscsr);
-	msm_pm_config_hw_after_power_up();
-	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: post power up\n", cpu, __func__);
-
-	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: return\n", cpu, __func__);
-	return collapsed;
-}
-
-static int64_t msm_pm_timer_enter_idle(void)
-{
-	if (msm_pm_use_sync_timer)
-		return ktime_to_ns(tick_nohz_get_sleep_length());
-
-	return msm_timer_enter_idle();
-}
-
-static void msm_pm_timer_exit_idle(bool timer_halted)
-{
-	if (msm_pm_use_sync_timer)
-		return;
-
-	msm_timer_exit_idle((int) timer_halted);
-}
-
-static int64_t msm_pm_timer_enter_suspend(int64_t *period)
-{
-	int64_t time = 0;
-
-	if (msm_pm_use_sync_timer) {
-		struct timespec ts;
-		getnstimeofday(&ts);
-		return timespec_to_ns(&ts);
-	}
-
-	time = msm_timer_get_sclk_time(period);
-	if (!time)
-		pr_err("%s: Unable to read sclk.\n", __func__);
-
-	return time;
-}
-
-static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
-{
-	if (msm_pm_use_sync_timer) {
-		struct timespec ts;
-		getnstimeofday(&ts);
-
-		return timespec_to_ns(&ts) - time;
-	}
-
-	if (time != 0) {
-		int64_t end_time = msm_timer_get_sclk_time(NULL);
-		if (end_time != 0) {
-			time = end_time - time;
-			if (time < 0)
-				time += period;
-		} else
-			time = 0;
-	}
-
-	return time;
-}
-
-/**
- * pm_hrtimer_cb() : Callback function for hrtimer created if the
- *                   core needs to be awake to handle an event.
- * @hrtimer : Pointer to hrtimer
- */
-static enum hrtimer_restart pm_hrtimer_cb(struct hrtimer *hrtimer)
-{
-	return HRTIMER_NORESTART;
-}
-
-/**
- * msm_pm_set_timer() : Set an hrtimer to wakeup the core in time
- *                      to handle an event.
- */
-static void msm_pm_set_timer(uint32_t modified_time_us)
-{
-	u64 modified_time_ns = modified_time_us * NSEC_PER_USEC;
-	ktime_t modified_ktime = ns_to_ktime(modified_time_ns);
-	pm_hrtimer.function = pm_hrtimer_cb;
-	hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_REL);
-}
-
-/******************************************************************************
- * External Idle/Suspend Functions
- *****************************************************************************/
-
-void arch_idle(void)
-{
-	return;
-}
-
-static inline void msm_pm_ftrace_lpm_enter(unsigned int cpu,
-		uint32_t latency, uint32_t sleep_us,
-		uint32_t wake_up,
-		enum msm_pm_sleep_mode mode)
-{
-	switch (mode) {
-	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-		trace_msm_pm_enter_wfi(cpu, latency, sleep_us, wake_up);
-		break;
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-		trace_msm_pm_enter_spc(cpu, latency, sleep_us, wake_up);
-		break;
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-		trace_msm_pm_enter_pc(cpu, latency, sleep_us, wake_up);
-		break;
-	case MSM_PM_SLEEP_MODE_RETENTION:
-		trace_msm_pm_enter_ret(cpu, latency, sleep_us, wake_up);
-		break;
-	default:
-		break;
-	}
-}
-
-static inline void msm_pm_ftrace_lpm_exit(unsigned int cpu,
-		enum msm_pm_sleep_mode mode,
-		bool success)
-{
-	switch (mode) {
-	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-		trace_msm_pm_exit_wfi(cpu, success);
-		break;
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-		trace_msm_pm_exit_spc(cpu, success);
-		break;
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-		trace_msm_pm_exit_pc(cpu, success);
-		break;
-	case MSM_PM_SLEEP_MODE_RETENTION:
-		trace_msm_pm_exit_ret(cpu, success);
-		break;
-	default:
-		break;
-	}
-}
-
-static int msm_pm_idle_prepare(struct cpuidle_device *dev,
-		struct cpuidle_driver *drv, int index,
-		void **msm_pm_idle_rs_limits)
-{
-	int i;
-	unsigned int power_usage = -1;
-	int ret = MSM_PM_SLEEP_MODE_NOT_SELECTED;
-	uint32_t modified_time_us = 0;
-	struct msm_pm_time_params time_param;
-
-	time_param.latency_us =
-		(uint32_t) pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
-	time_param.sleep_us =
-		(uint32_t) (ktime_to_us(tick_nohz_get_sleep_length())
-								& UINT_MAX);
-	time_param.modified_time_us = 0;
-
-	if (!dev->cpu)
-		time_param.next_event_us =
-			(uint32_t) (ktime_to_us(get_next_event_time())
-								& UINT_MAX);
-	else
-		time_param.next_event_us = 0;
-
-	for (i = 0; i < dev->state_count; i++) {
-		struct cpuidle_state *state = &drv->states[i];
-		struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
-		enum msm_pm_sleep_mode mode;
-		bool allow;
-		uint32_t power;
-		int idx;
-		void *rs_limits = NULL;
-
-		mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
-		idx = MSM_PM_MODE(dev->cpu, mode);
-
-		allow = msm_pm_sleep_modes[idx].idle_enabled &&
-				msm_pm_sleep_modes[idx].idle_supported;
-
-		switch (mode) {
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-			if (num_online_cpus() > 1)
-				allow = false;
-			break;
-		case MSM_PM_SLEEP_MODE_RETENTION:
-			/*
-			 * The Krait BHS regulator doesn't have enough head
-			 * room to drive the retention voltage on LDO and so
-			 * has disabled retention
-			 */
-			if (!msm_pm_ldo_retention_enabled)
-				allow = false;
-
-			if (msm_pm_retention_calls_tz && num_online_cpus() > 1)
-				allow = false;
-			break;
-		case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-			break;
-		default:
-			allow = false;
-			break;
-		}
-
-		if (!allow)
-			continue;
-
-		if (pm_sleep_ops.lowest_limits)
-			rs_limits = pm_sleep_ops.lowest_limits(true,
-					mode, &time_param, &power);
-
-		if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
-			pr_info("CPU%u:%s:%s, latency %uus, slp %uus, lim %p\n",
-					dev->cpu, __func__, state->desc,
-					time_param.latency_us,
-					time_param.sleep_us, rs_limits);
-		if (!rs_limits)
-			continue;
-
-		if (power < power_usage) {
-			power_usage = power;
-			modified_time_us = time_param.modified_time_us;
-			ret = mode;
-			*msm_pm_idle_rs_limits = rs_limits;
-		}
-
-	}
-
-	if (modified_time_us && !dev->cpu)
-		msm_pm_set_timer(modified_time_us);
-
-	msm_pm_ftrace_lpm_enter(dev->cpu, time_param.latency_us,
-			time_param.sleep_us, time_param.next_event_us,
-			ret);
-
-	return ret;
-}
-
-enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
-	struct cpuidle_driver *drv, int index)
-{
-	int64_t time;
-	bool collapsed = 1;
-	int exit_stat = -1;
-	enum msm_pm_sleep_mode sleep_mode;
-	void *msm_pm_idle_rs_limits = NULL;
-	uint32_t sleep_delay = 1;
-	int ret = -ENODEV;
-	int notify_rpm = false;
-	bool timer_halted = false;
-
-	sleep_mode = msm_pm_idle_prepare(dev, drv, index,
-		&msm_pm_idle_rs_limits);
-
-	if (!msm_pm_idle_rs_limits) {
-		sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
-		goto cpuidle_enter_bail;
-	}
-
-	if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: mode %d\n",
-			smp_processor_id(), __func__, sleep_mode);
-
-	time = ktime_to_ns(ktime_get());
-
-	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
-		int64_t ns = msm_pm_timer_enter_idle();
-		notify_rpm = true;
-		do_div(ns, NSEC_PER_SEC / SCLK_HZ);
-		sleep_delay = (uint32_t)ns;
-
-		if (sleep_delay == 0) /* 0 would mean infinite time */
-			sleep_delay = 1;
-	}
-
-	if (pm_sleep_ops.enter_sleep)
-		ret = pm_sleep_ops.enter_sleep(sleep_delay,
-			msm_pm_idle_rs_limits, true, notify_rpm);
-	if (ret)
-		goto cpuidle_enter_bail;
-
-	switch (sleep_mode) {
-	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
-		msm_pm_swfi();
-		exit_stat = MSM_PM_STAT_IDLE_WFI;
-		break;
-
-	case MSM_PM_SLEEP_MODE_RETENTION:
-		msm_pm_retention();
-		exit_stat = MSM_PM_STAT_RETENTION;
-		break;
-
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
-		collapsed = msm_pm_power_collapse_standalone(true);
-		if (collapsed)
-			exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-		else
-			exit_stat
-			    = MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
-		break;
-
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
-		if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
-			clock_debug_print_enabled();
-
-		collapsed = msm_pm_power_collapse(true);
-		timer_halted = true;
-
-		if (collapsed)
-			exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
-		else
-			exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
-
-		msm_pm_timer_exit_idle(timer_halted);
-		break;
-
-	case MSM_PM_SLEEP_MODE_NOT_SELECTED:
-		goto cpuidle_enter_bail;
-		break;
-
-	default:
-		__WARN();
-		goto cpuidle_enter_bail;
-		break;
-	}
-
-	if (pm_sleep_ops.exit_sleep)
-		pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits, true,
-				notify_rpm, collapsed);
-
-	time = ktime_to_ns(ktime_get()) - time;
-	msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode, collapsed);
-	if (exit_stat >= 0)
-		msm_pm_add_stat(exit_stat, time);
-	do_div(time, 1000);
-	dev->last_residency = (int) time;
-	return sleep_mode;
-
-cpuidle_enter_bail:
-	dev->last_residency = 0;
-	if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
-		msm_pm_timer_exit_idle(timer_halted);
-	sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
-	return sleep_mode;
-}
-
-int msm_pm_wait_cpu_shutdown(unsigned int cpu)
-{
-	int timeout = 0;
-
-	if (!msm_pm_slp_sts)
-		return 0;
-	if (!msm_pm_slp_sts[cpu].base_addr)
-		return 0;
-	while (1) {
-		/*
-		 * Check for the SPM of the core being hotplugged to set
-		 * its sleep state.The SPM sleep state indicates that the
-		 * core has been power collapsed.
-		 */
-		int acc_sts = __raw_readl(msm_pm_slp_sts[cpu].base_addr);
-
-		if (acc_sts & msm_pm_slp_sts[cpu].mask)
-			return 0;
-		udelay(100);
-		WARN(++timeout == 20, "CPU%u didn't collape within 2ms\n",
-					cpu);
-	}
-
-	return -EBUSY;
-}
-
-void msm_pm_cpu_enter_lowpower(unsigned int cpu)
-{
-	int i;
-	bool allow[MSM_PM_SLEEP_MODE_NR];
-
-	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
-		struct msm_pm_platform_data *mode;
-
-		mode = &msm_pm_sleep_modes[MSM_PM_MODE(cpu, i)];
-		allow[i] = mode->suspend_supported && mode->suspend_enabled;
-	}
-
-	if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
-		pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
-
-	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
-		msm_pm_power_collapse(false);
-	else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
-		msm_pm_power_collapse_standalone(false);
-	else if (allow[MSM_PM_SLEEP_MODE_RETENTION])
-		msm_pm_retention();
-	else
-		msm_pm_swfi();
-}
-
-static void msm_pm_ack_retention_disable(void *data)
-{
-	/*
-	 * This is a NULL function to ensure that the core has woken up
-	 * and is safe to disable retention.
-	 */
-}
-/**
- * msm_pm_enable_retention() - Disable/Enable retention on all cores
- * @enable: Enable/Disable retention
- *
- */
-void msm_pm_enable_retention(bool enable)
-{
-	if (enable == msm_pm_ldo_retention_enabled)
-		return;
-
-	msm_pm_ldo_retention_enabled = enable;
-	/*
-	 * If retention is being disabled, wakeup all online core to ensure
-	 * that it isn't executing retention. Offlined cores need not be woken
-	 * up as they enter the deepest sleep mode, namely RPM assited power
-	 * collapse
-	 */
-	if (!enable) {
-		preempt_disable();
-		smp_call_function_many(cpu_online_mask,
-				msm_pm_ack_retention_disable,
-				NULL, true);
-		preempt_enable();
-
-
-	}
-}
-EXPORT_SYMBOL(msm_pm_enable_retention);
-
-static int64_t suspend_time, suspend_period;
-static int collapsed;
-static int suspend_power_collapsed;
-
-static int msm_pm_enter(suspend_state_t state)
-{
-	bool allow[MSM_PM_SLEEP_MODE_NR];
-	int i;
-	struct msm_pm_time_params time_param;
-
-	time_param.latency_us = -1;
-	time_param.sleep_us = -1;
-	time_param.next_event_us = 0;
-
-	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-		pr_info("%s\n", __func__);
-
-	if (smp_processor_id()) {
-		__WARN();
-		goto enter_exit;
-	}
-
-
-	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
-		struct msm_pm_platform_data *mode;
-
-		mode = &msm_pm_sleep_modes[MSM_PM_MODE(0, i)];
-		allow[i] = mode->suspend_supported && mode->suspend_enabled;
-	}
-
-	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
-		void *rs_limits = NULL;
-		int ret = -ENODEV;
-		uint32_t power;
-		uint32_t msm_pm_max_sleep_time = 0;
-
-		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-			pr_info("%s: power collapse\n", __func__);
-
-		clock_debug_print_enabled();
-
-		if (msm_pm_sleep_time_override > 0) {
-			int64_t ns = NSEC_PER_SEC *
-				(int64_t) msm_pm_sleep_time_override;
-			do_div(ns, NSEC_PER_SEC / SCLK_HZ);
-			msm_pm_max_sleep_time = (uint32_t) ns;
-		}
-
-		if (pm_sleep_ops.lowest_limits)
-			rs_limits = pm_sleep_ops.lowest_limits(false,
-		MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
-
-		if (rs_limits) {
-			if (pm_sleep_ops.enter_sleep)
-				ret = pm_sleep_ops.enter_sleep(
-						msm_pm_max_sleep_time,
-						rs_limits, false, true);
-			if (!ret) {
-				collapsed = msm_pm_power_collapse(false);
-				if (pm_sleep_ops.exit_sleep) {
-					pm_sleep_ops.exit_sleep(rs_limits,
-						false, true, collapsed);
-				}
-			}
-		} else {
-			pr_err("%s: cannot find the lowest power limit\n",
-				__func__);
-		}
-		suspend_power_collapsed = true;
-	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
-		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-			pr_info("%s: standalone power collapse\n", __func__);
-		msm_pm_power_collapse_standalone(false);
-	} else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
-		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-			pr_info("%s: retention\n", __func__);
-		msm_pm_retention();
-	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
-		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-			pr_info("%s: swfi\n", __func__);
-		msm_pm_swfi();
-	}
-
-enter_exit:
-	if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
-		pr_info("%s: return\n", __func__);
-
-	return 0;
-}
-
-void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
-{
-	if (ops)
-		pm_sleep_ops = *ops;
-}
-
-static int msm_suspend_prepare(void)
-{
-	suspend_time = msm_pm_timer_enter_suspend(&suspend_period);
-	msm_mpm_suspend_prepare();
-	return 0;
-}
-
-static void msm_suspend_wake(void)
-{
-	msm_mpm_suspend_wake();
-	if (suspend_power_collapsed) {
-		suspend_time = msm_pm_timer_exit_suspend(suspend_time,
-				suspend_period);
-		if (collapsed)
-			msm_pm_add_stat(MSM_PM_STAT_SUSPEND, suspend_time);
-		else
-			msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND,
-					suspend_time);
-		suspend_power_collapsed = false;
-	}
-}
-
-static const struct platform_suspend_ops msm_pm_ops = {
-	.enter = msm_pm_enter,
-	.valid = suspend_valid_only_mem,
-	.prepare_late = msm_suspend_prepare,
-	.wake = msm_suspend_wake,
-};
-
-static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
-{
-	int rc = 0;
-	static struct msm_bus_scale_pdata *msm_pm_bus_pdata;
-	static uint32_t msm_pm_bus_client;
-
-	msm_pm_bus_pdata = msm_bus_cl_get_pdata(pdev);
-
-	if (msm_pm_bus_pdata) {
-		msm_pm_bus_client =
-			msm_bus_scale_register_client(msm_pm_bus_pdata);
-
-		if (!msm_pm_bus_client) {
-			pr_err("%s: Failed to register SNOC client",
-							__func__);
-			rc = -ENXIO;
-			goto snoc_cl_probe_done;
-		}
-
-		rc = msm_bus_scale_client_update_request(msm_pm_bus_client, 1);
-
-		if (rc)
-			pr_err("%s: Error setting bus rate", __func__);
-	}
-
-snoc_cl_probe_done:
-	return rc;
-}
-
-static int __devinit msm_cpu_status_probe(struct platform_device *pdev)
-{
-	struct msm_pm_sleep_status_data *pdata;
-	char *key;
-	u32 cpu;
-
-	if (!pdev)
-		return -EFAULT;
-
-	msm_pm_slp_sts =
-		kzalloc(sizeof(*msm_pm_slp_sts) * num_possible_cpus(),
-				GFP_KERNEL);
-
-	if (!msm_pm_slp_sts)
-		return -ENOMEM;
-
-	if (pdev->dev.of_node) {
-		struct resource *res;
-		u32 offset;
-		int rc;
-		u32 mask;
-
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-		if (!res)
-			goto fail_free_mem;
-
-		key = "qcom,cpu-alias-addr";
-		rc = of_property_read_u32(pdev->dev.of_node, key, &offset);
-
-		if (rc)
-			goto fail_free_mem;
-
-		key = "qcom,sleep-status-mask";
-		rc = of_property_read_u32(pdev->dev.of_node, key,
-					&mask);
-		if (rc)
-			goto fail_free_mem;
-
-		for_each_possible_cpu(cpu) {
-			msm_pm_slp_sts[cpu].base_addr =
-				ioremap(res->start + cpu * offset,
-					resource_size(res));
-			msm_pm_slp_sts[cpu].mask = mask;
-
-			if (!msm_pm_slp_sts[cpu].base_addr)
-				goto failed_of_node;
-		}
-
-	} else {
-		pdata = pdev->dev.platform_data;
-		if (!pdev->dev.platform_data)
-			goto fail_free_mem;
-
-		for_each_possible_cpu(cpu) {
-			msm_pm_slp_sts[cpu].base_addr =
-				pdata->base_addr + cpu * pdata->cpu_offset;
-			msm_pm_slp_sts[cpu].mask = pdata->mask;
-		}
-	}
-
-	return 0;
-
-failed_of_node:
-	pr_info("%s(): Failed to key=%s\n", __func__, key);
-	for_each_possible_cpu(cpu) {
-		if (msm_pm_slp_sts[cpu].base_addr)
-			iounmap(msm_pm_slp_sts[cpu].base_addr);
-	}
-fail_free_mem:
-	kfree(msm_pm_slp_sts);
-	return -EINVAL;
-
-};
-
-static struct of_device_id msm_slp_sts_match_tbl[] = {
-	{.compatible = "qcom,cpu-sleep-status"},
-	{},
-};
-
-static struct platform_driver msm_cpu_status_driver = {
-	.probe = msm_cpu_status_probe,
-	.driver = {
-		.name = "cpu_slp_status",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_slp_sts_match_tbl,
-	},
-};
-
-static struct of_device_id msm_snoc_clnt_match_tbl[] = {
-	{.compatible = "qcom,pm-snoc-client"},
-	{},
-};
-
-static struct platform_driver msm_cpu_pm_snoc_client_driver = {
-	.probe = msm_pm_snoc_client_probe,
-	.driver = {
-		.name = "pm_snoc_client",
-		.owner = THIS_MODULE,
-		.of_match_table = msm_snoc_clnt_match_tbl,
-	},
-};
-
-#ifdef CONFIG_ARM_LPAE
-static int msm_pm_idmap_add_pmd(pud_t *pud, unsigned long addr,
-				unsigned long end, unsigned long prot)
-{
-	pmd_t *pmd;
-	unsigned long next;
-
-	if (pud_none_or_clear_bad(pud) || (pud_val(*pud) & L_PGD_SWAPPER)) {
-		pmd = pmd_alloc_one(&init_mm, addr);
-		if (!pmd)
-			return -ENOMEM;
-
-		pud_populate(&init_mm, pud, pmd);
-		pmd += pmd_index(addr);
-	} else {
-		pmd = pmd_offset(pud, addr);
-	}
-
-	do {
-		next = pmd_addr_end(addr, end);
-		*pmd = __pmd((addr & PMD_MASK) | prot);
-		flush_pmd_entry(pmd);
-	} while (pmd++, addr = next, addr != end);
-
-	return 0;
-}
-#else   /* !CONFIG_ARM_LPAE */
-static int msm_pm_idmap_add_pmd(pud_t *pud, unsigned long addr,
-				unsigned long end, unsigned long prot)
-{
-	pmd_t *pmd = pmd_offset(pud, addr);
-
-	addr = (addr & PMD_MASK) | prot;
-	pmd[0] = __pmd(addr);
-	addr += SECTION_SIZE;
-	pmd[1] = __pmd(addr);
-	flush_pmd_entry(pmd);
-
-	return 0;
-}
-#endif  /* CONFIG_ARM_LPAE */
-
-static int msm_pm_idmap_add_pud(pgd_t *pgd, unsigned long addr,
-					unsigned long end,
-					unsigned long prot)
-{
-	pud_t *pud = pud_offset(pgd, addr);
-	unsigned long next;
-	int ret;
-
-	do {
-		next = pud_addr_end(addr, end);
-		ret = msm_pm_idmap_add_pmd(pud, addr, next, prot);
-		if (ret)
-			return ret;
-	} while (pud++, addr = next, addr != end);
-
-	return 0;
-}
-
-static int msm_pm_add_idmap(pgd_t *pgd, unsigned long addr,
-						unsigned long end,
-						unsigned long prot)
-{
-	unsigned long next;
-	int ret;
-
-	pgd += pgd_index(addr);
-	do {
-		next = pgd_addr_end(addr, end);
-		ret = msm_pm_idmap_add_pud(pgd, addr, next, prot);
-		if (ret)
-			return ret;
-	} while (pgd++, addr = next, addr != end);
-
-	return 0;
-}
-
-static int msm_pm_setup_pagetable(void)
-{
-	pgd_t *pc_pgd;
-	unsigned long exit_phys;
-	unsigned long end;
-	int ret;
-
-	/* Page table for cores to come back up safely. */
-	pc_pgd = pgd_alloc(&init_mm);
-	if (!pc_pgd)
-		return -ENOMEM;
-
-	exit_phys = virt_to_phys(msm_pm_collapse_exit);
-
-	/*
-	 * Make the (hopefully) reasonable assumption that the code size of
-	 * msm_pm_collapse_exit won't be more than a section in size
-	 */
-	end = exit_phys + SECTION_SIZE;
-
-	ret = msm_pm_add_idmap(pc_pgd, exit_phys, end,
-			PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF);
-
-	if (ret)
-		return ret;
-
-	msm_pm_pc_pgd = virt_to_phys(pc_pgd);
-	clean_caches((unsigned long)&msm_pm_pc_pgd, sizeof(msm_pm_pc_pgd),
-		     virt_to_phys(&msm_pm_pc_pgd));
-
-	return 0;
-}
-
-static int __init msm_pm_setup_saved_state(void)
-{
-	int ret;
-	dma_addr_t temp_phys;
-
-	ret = msm_pm_setup_pagetable();
-	if (ret)
-		return ret;
-
-	msm_saved_state = dma_zalloc_coherent(NULL, CPU_SAVED_STATE_SIZE *
-						num_possible_cpus(),
-						&temp_phys, 0);
-
-	if (!msm_saved_state)
-		return -ENOMEM;
-
-	/*
-	 * Explicitly cast here since msm_saved_state_phys is defined
-	 * in assembly and we want to avoid any kind of truncation
-	 * or endian problems.
-	 */
-	msm_saved_state_phys = (unsigned long)temp_phys;
-
-	return 0;
-}
-arch_initcall(msm_pm_setup_saved_state);
-
-static void setup_broadcast_timer(void *arg)
-{
-	int cpu = smp_processor_id();
-
-	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
-}
-
-static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
-		unsigned long action, void *hcpu)
-{
-	int cpu = (unsigned long)hcpu;
-
-	switch (action & ~CPU_TASKS_FROZEN) {
-	case CPU_ONLINE:
-		smp_call_function_single(cpu, setup_broadcast_timer, NULL, 1);
-		break;
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block setup_broadcast_notifier = {
-	.notifier_call = setup_broadcast_cpuhp_notify,
-};
-
-static int __init msm_pm_init(void)
-{
-	enum msm_pm_time_stats_id enable_stats[] = {
-		MSM_PM_STAT_IDLE_WFI,
-		MSM_PM_STAT_RETENTION,
-		MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
-		MSM_PM_STAT_IDLE_POWER_COLLAPSE,
-		MSM_PM_STAT_SUSPEND,
-	};
-	msm_pm_mode_sysfs_add();
-	msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
-	suspend_set_ops(&msm_pm_ops);
-	hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	msm_cpuidle_init();
-
-	if (msm_pm_pc_reset_timer) {
-		on_each_cpu(setup_broadcast_timer, NULL, 1);
-		register_cpu_notifier(&setup_broadcast_notifier);
-	}
-
-	return 0;
-}
-
-static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
-{
-	msm_pm_disable_l2_fn = NULL;
-	msm_pm_enable_l2_fn = NULL;
-	msm_pm_flush_l2_fn = outer_flush_all;
-
-	if (pc_mode == MSM_PM_PC_NOTZ_L2_EXT) {
-		msm_pm_disable_l2_fn = outer_disable;
-		msm_pm_enable_l2_fn = outer_resume;
-	}
-}
-
-struct msm_pc_debug_counters_buffer {
-	void __iomem *reg;
-	u32 len;
-	char buf[MAX_BUF_SIZE];
-};
-
-static inline u32 msm_pc_debug_counters_read_register(
-		void __iomem *reg, int index , int offset)
-{
-	return readl_relaxed(reg + (index * 4 + offset) * 4);
-}
-
-static char *counter_name[] = {
-		"PC Entry Counter",
-		"Warmboot Entry Counter",
-		"PC Bailout Counter"
-};
-
-static int msm_pc_debug_counters_copy(
-		struct msm_pc_debug_counters_buffer *data)
-{
-	int j;
-	u32 stat;
-	unsigned int cpu;
-
-	for_each_possible_cpu(cpu) {
-		data->len += scnprintf(data->buf + data->len,
-				sizeof(data->buf)-data->len,
-				"CPU%d\n", cpu);
-
-			for (j = 0; j < NUM_OF_COUNTERS; j++) {
-				stat = msm_pc_debug_counters_read_register(
-						data->reg, cpu, j);
-				data->len += scnprintf(data->buf + data->len,
-					sizeof(data->buf)-data->len,
-					"\t%s : %d\n", counter_name[j],
-					stat);
-		}
-
-	}
-
-	return data->len;
-}
-
-static int msm_pc_debug_counters_file_read(struct file *file,
-		char __user *bufu, size_t count, loff_t *ppos)
-{
-	struct msm_pc_debug_counters_buffer *data;
-
-	data = file->private_data;
-
-	if (!data)
-		return -EINVAL;
-
-	if (!bufu)
-		return -EINVAL;
-
-	if (!access_ok(VERIFY_WRITE, bufu, count))
-		return -EFAULT;
-
-	if (*ppos >= data->len && data->len == 0)
-		data->len = msm_pc_debug_counters_copy(data);
-
-	return simple_read_from_buffer(bufu, count, ppos,
-			data->buf, data->len);
-}
-
-static int msm_pc_debug_counters_file_open(struct inode *inode,
-		struct file *file)
-{
-	struct msm_pc_debug_counters_buffer *buf;
-	void __iomem *msm_pc_debug_counters_reg;
-
-	msm_pc_debug_counters_reg = inode->i_private;
-
-	if (!msm_pc_debug_counters_reg)
-		return -EINVAL;
-
-	file->private_data = kzalloc(
-		sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
-
-	if (!file->private_data) {
-		pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
-		__func__, sizeof(struct msm_pc_debug_counters_buffer));
-
-		return -ENOMEM;
-	}
-
-	buf = file->private_data;
-	buf->reg = msm_pc_debug_counters_reg;
-
-	return 0;
-}
-
-static int msm_pc_debug_counters_file_close(struct inode *inode,
-		struct file *file)
-{
-	kfree(file->private_data);
-	return 0;
-}
-
-static const struct file_operations msm_pc_debug_counters_fops = {
-	.open = msm_pc_debug_counters_file_open,
-	.read = msm_pc_debug_counters_file_read,
-	.release = msm_pc_debug_counters_file_close,
-	.llseek = no_llseek,
-};
-
-static int msm_pm_clk_init(struct platform_device *pdev)
-{
-	bool synced_clocks;
-	u32 cpu;
-	char clk_name[] = "cpu??_clk";
-	bool cpu_as_clocks;
-	char *key;
-
-	key = "qcom,cpus-as-clocks";
-	cpu_as_clocks = of_property_read_bool(pdev->dev.of_node, key);
-
-	if (!cpu_as_clocks) {
-		use_acpuclk_apis = true;
-		return 0;
-	}
-
-	key = "qcom,synced-clocks";
-	synced_clocks = of_property_read_bool(pdev->dev.of_node, key);
-
-	for_each_possible_cpu(cpu) {
-		struct clk *clk;
-		snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
-		clk = devm_clk_get(&pdev->dev, clk_name);
-		if (IS_ERR(clk)) {
-			if (cpu && synced_clocks)
-				return 0;
-			else
-				return PTR_ERR(clk);
-		}
-		per_cpu(cpu_clks, cpu) = clk;
-	}
-
-	if (synced_clocks)
-		return 0;
-
-	l2_clk = devm_clk_get(&pdev->dev, "l2_clk");
-
-	return PTR_RET(l2_clk);
-}
-
-static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
-{
-	char *key = NULL;
-	struct dentry *dent = NULL;
-	struct resource *res = NULL;
-	int i ;
-	struct msm_pm_init_data_type pdata_local;
-	int ret = 0;
-
-	memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res) {
-		msm_pc_debug_counters_phys = res->start;
-		WARN_ON(resource_size(res) < SZ_64);
-		msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
-					resource_size(res));
-		if (msm_pc_debug_counters)
-			for (i = 0; i < resource_size(res)/4; i++)
-				__raw_writel(0, msm_pc_debug_counters + i * 4);
-
-	}
-
-	if (!msm_pc_debug_counters) {
-		msm_pc_debug_counters = 0;
-		msm_pc_debug_counters_phys = 0;
-	} else {
-		dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
-				msm_pc_debug_counters,
-				&msm_pc_debug_counters_fops);
-		if (!dent)
-			pr_err("%s: ERROR debugfs_create_file failed\n",
-					__func__);
-	}
-
-	if (!pdev->dev.of_node) {
-		struct msm_pm_init_data_type *d = pdev->dev.platform_data;
-
-		if (!d)
-			goto pm_8x60_probe_done;
-
-		memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
-
-	} else {
-		ret = msm_pm_clk_init(pdev);
-		if (ret) {
-			pr_info("msm_pm_clk_init returned error\n");
-			return ret;
-		}
-
-		key = "qcom,pc-mode";
-		ret = msm_pm_get_pc_mode(pdev->dev.of_node,
-				key,
-				&pdata_local.pc_mode);
-		if (ret) {
-			pr_debug("%s: Error reading key %s",
-					__func__, key);
-			return -EINVAL;
-		}
-
-		key = "qcom,use-sync-timer";
-		pdata_local.use_sync_timer =
-			of_property_read_bool(pdev->dev.of_node, key);
-
-		key = "qcom,saw-turns-off-pll";
-		msm_no_ramp_down_pc = of_property_read_bool(pdev->dev.of_node,
-					key);
-
-		key = "qcom,pc-resets-timer";
-		msm_pm_pc_reset_timer = of_property_read_bool(
-				pdev->dev.of_node, key);
-	}
-
-	if (pdata_local.cp15_data.reg_data &&
-		pdata_local.cp15_data.reg_saved_state_size > 0) {
-		cp15_data.reg_data = kzalloc(sizeof(uint32_t) *
-				pdata_local.cp15_data.reg_saved_state_size,
-				GFP_KERNEL);
-		if (!cp15_data.reg_data)
-			return -ENOMEM;
-
-		cp15_data.reg_val = kzalloc(sizeof(uint32_t) *
-				pdata_local.cp15_data.reg_saved_state_size,
-				GFP_KERNEL);
-		if (cp15_data.reg_val)
-			return -ENOMEM;
-
-		memcpy(cp15_data.reg_data, pdata_local.cp15_data.reg_data,
-			pdata_local.cp15_data.reg_saved_state_size *
-			sizeof(uint32_t));
-	}
-
-	msm_pm_set_flush_fn(pdata_local.pc_mode);
-	msm_pm_use_sync_timer = pdata_local.use_sync_timer;
-	msm_pm_retention_calls_tz = pdata_local.retention_calls_tz;
-
-pm_8x60_probe_done:
-	msm_pm_init();
-	if (pdev->dev.of_node)
-		of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
-
-	return ret;
-}
-
-static struct of_device_id msm_pm_8x60_table[] = {
-		{.compatible = "qcom,pm-8x60"},
-		{},
-};
-
-static struct platform_driver msm_pm_8x60_driver = {
-		.probe = msm_pm_8x60_probe,
-		.driver = {
-			.name = "pm-8x60",
-			.owner = THIS_MODULE,
-			.of_match_table = msm_pm_8x60_table,
-		},
-};
-
-static int __init msm_pm_8x60_init(void)
-{
-	int rc;
-
-	rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
-
-	if (rc) {
-		pr_err("%s(): failed to register driver %s\n", __func__,
-				msm_cpu_pm_snoc_client_driver.driver.name);
-		return rc;
-	}
-
-	return platform_driver_register(&msm_pm_8x60_driver);
-}
-device_initcall(msm_pm_8x60_init);
-
-void __init msm_pm_sleep_status_init(void)
-{
-	platform_driver_register(&msm_cpu_status_driver);
-}
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index f41c569..04f4237 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -43,7 +43,7 @@
 	},
 
 	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
-		.idle_supported = 0,
+		.idle_supported = 1,
 		.suspend_supported = 1,
 		.idle_enabled = 0,
 		.suspend_enabled = 1,
@@ -71,7 +71,7 @@
 	},
 
 	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
-		.idle_supported = 0,
+		.idle_supported = 1,
 		.suspend_supported = 1,
 		.idle_enabled = 0,
 		.suspend_enabled = 1,
@@ -99,7 +99,7 @@
 	},
 
 	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
-		.idle_supported = 0,
+		.idle_supported = 1,
 		.suspend_supported = 1,
 		.idle_enabled = 0,
 		.suspend_enabled = 1,
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index f2fc80b..a20b36e 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -27,33 +27,20 @@
 #define msm_secondary_startup NULL
 #endif
 
-DECLARE_PER_CPU(int,  power_collapsed);
-
-struct msm_pm_irq_calls {
-	unsigned int (*irq_pending)(void);
-	int (*idle_sleep_allowed)(void);
-	void (*enter_sleep1)(bool modem_wake, int from_idle, uint32_t
-								*irq_mask);
-	int (*enter_sleep2)(bool modem_wake, int from_idle);
-	void (*exit_sleep1)(uint32_t irq_mask, uint32_t wakeup_reason,
-							uint32_t pending_irqs);
-	void (*exit_sleep2)(uint32_t irq_mask, uint32_t wakeup_reason,
-							uint32_t pending_irqs);
-	void (*exit_sleep3)(uint32_t irq_mask, uint32_t wakeup_reason,
-							uint32_t pending_irqs);
+enum msm_pm_sleep_mode {
+	MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
+	MSM_PM_SLEEP_MODE_RETENTION,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+	MSM_PM_SLEEP_MODE_NR,
+	MSM_PM_SLEEP_MODE_NOT_SELECTED,
 };
 
-enum msm_pm_sleep_mode {
-	MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT = 0,
-	MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT = 1,
-	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE = 2,
-	MSM_PM_SLEEP_MODE_POWER_COLLAPSE = 3,
-	MSM_PM_SLEEP_MODE_APPS_SLEEP = 4,
-	MSM_PM_SLEEP_MODE_RETENTION = MSM_PM_SLEEP_MODE_APPS_SLEEP,
-	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND = 5,
-	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN = 6,
-	MSM_PM_SLEEP_MODE_NR = 7,
-	MSM_PM_SLEEP_MODE_NOT_SELECTED,
+enum msm_pm_l2_scm_flag {
+	MSM_SCM_L2_ON = 0,
+	MSM_SCM_L2_OFF = 1,
+	MSM_SCM_L2_RET = 2,
+	MSM_SCM_L2_GDHS = 3,
 };
 
 #define MSM_PM_MODE(cpu, mode_nr)  ((cpu) * MSM_PM_SLEEP_MODE_NR + (mode_nr))
@@ -84,16 +71,6 @@
 
 extern struct msm_pm_platform_data msm_pm_sleep_modes[];
 
-struct msm_pm_sleep_ops {
-	void *(*lowest_limits)(bool from_idle,
-			enum msm_pm_sleep_mode sleep_mode,
-			struct msm_pm_time_params *time_param, uint32_t *power);
-	int (*enter_sleep)(uint32_t sclk_count, void *limits,
-			bool from_idle, bool notify_rpm);
-	void (*exit_sleep)(void *limits, bool from_idle,
-			bool notify_rpm, bool collapsed);
-};
-
 enum msm_pm_pc_mode_type {
 	MSM_PM_PC_TZ_L2_INT,   /*Power collapse terminates in TZ;
 					integrated L2 cache controller */
@@ -103,20 +80,8 @@
 					external L2 cache controller */
 };
 
-struct msm_pm_cp15_save_data {
-	bool save_cp15;
-	uint32_t active_vdd;
-	uint32_t qsb_pc_vdd;
-	uint32_t reg_saved_state_size;
-	uint32_t *reg_data;
-	uint32_t *reg_val;
-};
-
 struct msm_pm_init_data_type {
 	enum msm_pm_pc_mode_type pc_mode;
-	bool retention_calls_tz;
-	struct msm_pm_cp15_save_data cp15_data;
-	bool use_sync_timer;
 };
 
 struct msm_pm_cpr_ops {
@@ -127,21 +92,37 @@
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
 enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
 			struct cpuidle_driver *drv, int index);
-void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
 void msm_pm_cpu_enter_lowpower(unsigned int cpu);
 void __init msm_pm_set_tz_retention_flag(unsigned int flag);
 void msm_pm_enable_retention(bool enable);
 
-#ifdef CONFIG_MSM_PM8X60
+#if defined(CONFIG_MSM_PM)
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
-void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
 int msm_pm_wait_cpu_shutdown(unsigned int cpu);
+int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);
 void __init msm_pm_sleep_status_init(void);
+void msm_pm_set_l2_flush_flag(enum msm_pm_l2_scm_flag flag);
+bool msm_cpu_pm_check_mode(unsigned int cpu, enum msm_pm_sleep_mode mode,
+		bool from_idle);
+int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode, bool from_idle);
 #else
 static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
-static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
 static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
+static inline int msm_cpu_pm_enter_sleep(enum msm_pm_sleep_mode mode,
+		bool from_idle)
+{
+	return -ENODEV;
+}
 static inline void msm_pm_sleep_status_init(void) {};
+static inline void msm_pm_set_l2_flush_flag(unsigned int flag)
+{
+	/* empty */
+}
+bool msm_cpu_pm_check_mode(unsigned int cpu, enum msm_pm_sleep_mode mode,
+		bool from_idle)
+{
+	return false;
+}
 #endif
 #ifdef CONFIG_HOTPLUG_CPU
 int msm_platform_secondary_init(unsigned int cpu);
@@ -174,6 +155,5 @@
 #endif
 
 void msm_pm_set_cpr_ops(struct msm_pm_cpr_ops *ops);
-extern void *msm_pc_debug_counters;
 extern unsigned long msm_pc_debug_counters_phys;
 #endif  /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index 16de77e..1f4fdab 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -42,10 +42,11 @@
  * msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
  *
  * @bool - flag to enable print contents of sleep buffer.
+ * @cpumask - cpumask of next wakeup cpu
  *
  * return 0 on success errno on failure.
  */
-int msm_rpm_enter_sleep(bool print);
+int msm_rpm_enter_sleep(bool print, const struct cpumask *cpumask);
 
 /**
  * msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index ccab6e2..54576a9 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -1287,14 +1287,14 @@
  * During power collapse, the rpm driver disables the SMD interrupts to make
  * sure that the interrupt doesn't wakes us from sleep.
  */
-int msm_rpm_enter_sleep(bool print)
+int msm_rpm_enter_sleep(bool print, const struct cpumask *cpumask)
 {
 	if (standalone)
 		return 0;
 
 	msm_rpm_flush_requests(print);
 
-	return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
+	return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true, cpumask);
 }
 EXPORT_SYMBOL(msm_rpm_enter_sleep);
 
@@ -1307,7 +1307,7 @@
 	if (standalone)
 		return;
 
-	smd_mask_receive_interrupt(msm_rpm_data.ch_info, false);
+	smd_mask_receive_interrupt(msm_rpm_data.ch_info, false, NULL);
 }
 EXPORT_SYMBOL(msm_rpm_exit_sleep);
 
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index cb9697d..09b3113 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -2247,13 +2247,15 @@
  * particular channel.
  * @ch:      open channel handle to use for the edge
  * @mask:    1 = mask interrupts; 0 = unmask interrupts
+ * @cpumask  cpumask for the next cpu scheduled to be woken up
  * @returns: 0 for success; < 0 for failure
  *
  * Note that this enables/disables all interrupts from the remote subsystem for
  * all channels.  As such, it should be used with care and only for specific
  * use cases such as power-collapse sequencing.
  */
-int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask)
+int smd_mask_receive_interrupt(smd_channel_t *ch, bool mask,
+		const struct cpumask *cpumask)
 {
 	struct irq_chip *irq_chip;
 	struct irq_data *irq_data;
@@ -2282,6 +2284,8 @@
 		SMD_POWER_INFO("SMD Masking interrupts from %s\n",
 				edge_to_pids[ch->type].subsys_name);
 		irq_chip->irq_mask(irq_data);
+		if (cpumask)
+			irq_chip->irq_set_affinity(irq_data, cpumask, true);
 	} else {
 		SMD_POWER_INFO("SMD Unmasking interrupts from %s\n",
 				edge_to_pids[ch->type].subsys_name);
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 1769402..2946689 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.h
@@ -28,43 +28,6 @@
 	MSM_SPM_L2_MODE_POWER_COLLAPSE,
 };
 
-#if defined(CONFIG_MSM_SPM_V1)
-
-enum {
-	MSM_SPM_REG_SAW_AVS_CTL,
-	MSM_SPM_REG_SAW_CFG,
-	MSM_SPM_REG_SAW_SPM_CTL,
-	MSM_SPM_REG_SAW_SPM_SLP_TMR_DLY,
-	MSM_SPM_REG_SAW_SPM_WAKE_TMR_DLY,
-	MSM_SPM_REG_SAW_SLP_CLK_EN,
-	MSM_SPM_REG_SAW_SLP_HSFS_PRECLMP_EN,
-	MSM_SPM_REG_SAW_SLP_HSFS_POSTCLMP_EN,
-	MSM_SPM_REG_SAW_SLP_CLMP_EN,
-	MSM_SPM_REG_SAW_SLP_RST_EN,
-	MSM_SPM_REG_SAW_SPM_MPM_CFG,
-	MSM_SPM_REG_NR_INITIALIZE,
-
-	MSM_SPM_REG_SAW_VCTL = MSM_SPM_REG_NR_INITIALIZE,
-	MSM_SPM_REG_SAW_STS,
-	MSM_SPM_REG_SAW_SPM_PMIC_CTL,
-	MSM_SPM_REG_NR
-};
-
-struct msm_spm_platform_data {
-	void __iomem *reg_base_addr;
-	uint32_t reg_init_values[MSM_SPM_REG_NR_INITIALIZE];
-
-	uint8_t awake_vlevel;
-	uint8_t retention_vlevel;
-	uint8_t collapse_vlevel;
-	uint8_t retention_mid_vlevel;
-	uint8_t collapse_mid_vlevel;
-
-	uint32_t vctl_timeout_us;
-};
-
-#elif defined(CONFIG_MSM_SPM_V2)
-
 enum {
 	MSM_SPM_REG_SAW2_CFG,
 	MSM_SPM_REG_SAW2_AVS_CTL,
@@ -122,9 +85,8 @@
 	uint32_t num_modes;
 	struct msm_spm_seq_entry *modes;
 };
-#endif
 
-#if defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2)
+#if defined(CONFIG_MSM_SPM_V2)
 
 /* Public functions */
 
@@ -187,7 +149,7 @@
 	return -ENOSYS;
 }
 #endif /* defined(CONFIG_MSM_L2_SPM) */
-#else /* defined(CONFIG_MSM_SPM_V1) || defined(CONFIG_MSM_SPM_V2) */
+#else /* defined(CONFIG_MSM_SPM_V2) */
 static inline int msm_spm_set_low_power_mode(unsigned int mode, bool notify_rpm)
 {
 	return -ENOSYS;
@@ -218,5 +180,5 @@
 	return -ENOSYS;
 }
 
-#endif  /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
+#endif  /* defined (CONFIG_MSM_SPM_V2) */
 #endif  /* __ARCH_ARM_MACH_MSM_SPM_H */
diff --git a/arch/arm/mach-msm/test-lpm.c b/arch/arm/mach-msm/test-lpm.c
index 031b2dc..790c909 100644
--- a/arch/arm/mach-msm/test-lpm.c
+++ b/arch/arm/mach-msm/test-lpm.c
@@ -121,9 +121,6 @@
 	case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
 		strlcat(nm, "WFI ", BUF_SIZE);
 		break;
-	case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
-		strlcat(nm, "WFI voltage Rampdown ", BUF_SIZE);
-		break;
 	case MSM_PM_SLEEP_MODE_RETENTION:
 		strlcat(nm, "Retention ", BUF_SIZE);
 		break;
@@ -133,9 +130,6 @@
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
 		strlcat(nm, "Idle Power collapse ", BUF_SIZE);
 		break;
-	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
-		strlcat(nm, "Suspend Power collapse ", BUF_SIZE);
-		break;
 	default:
 		strlcat(nm, "Invalid Mode ", BUF_SIZE);
 		break;
diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S
index 0720163..e505bef 100644
--- a/arch/arm/mm/cache-fa.S
+++ b/arch/arm/mm/cache-fa.S
@@ -240,6 +240,9 @@
 	mov	pc, lr
 ENDPROC(fa_dma_unmap_area)
 
+	.globl	fa_flush_kern_cache_louis
+	.equ	fa_flush_kern_cache_louis, fa_flush_kern_cache_all
+
 	__INITDATA
 
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S
index c2301f2..d99c00c 100644
--- a/arch/arm/mm/cache-v3.S
+++ b/arch/arm/mm/cache-v3.S
@@ -127,6 +127,9 @@
 ENDPROC(v3_dma_unmap_area)
 ENDPROC(v3_dma_map_area)
 
+	.globl	v3_flush_kern_cache_louis
+	.equ	v3_flush_kern_cache_louis, v3_flush_kern_cache_all
+
 	__INITDATA
 
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
index fd9bb7a..548b892a 100644
--- a/arch/arm/mm/cache-v4.S
+++ b/arch/arm/mm/cache-v4.S
@@ -139,6 +139,9 @@
 ENDPROC(v4_dma_unmap_area)
 ENDPROC(v4_dma_map_area)
 
+	.globl	v4_flush_kern_cache_louis
+	.equ	v4_flush_kern_cache_louis, v4_flush_kern_cache_all
+
 	__INITDATA
 
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S
index 4f2c141..63b7e49 100644
--- a/arch/arm/mm/cache-v4wb.S
+++ b/arch/arm/mm/cache-v4wb.S
@@ -251,6 +251,9 @@
 	mov	pc, lr
 ENDPROC(v4wb_dma_unmap_area)
 
+	.globl	v4wb_flush_kern_cache_louis
+	.equ	v4wb_flush_kern_cache_louis, v4wb_flush_kern_cache_all
+
 	__INITDATA
 
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S
index 4d7b467..198d424 100644
--- a/arch/arm/mm/cache-v4wt.S
+++ b/arch/arm/mm/cache-v4wt.S
@@ -195,6 +195,9 @@
 ENDPROC(v4wt_dma_unmap_area)
 ENDPROC(v4wt_dma_map_area)
 
+	.globl	v4wt_flush_kern_cache_louis
+	.equ	v4wt_flush_kern_cache_louis, v4wt_flush_kern_cache_all
+
 	__INITDATA
 
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 2edb6f6..6a5674d 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -345,6 +345,9 @@
 	mov	pc, lr
 ENDPROC(v6_dma_unmap_area)
 
+	.globl	v6_flush_kern_cache_louis
+	.equ	v6_flush_kern_cache_louis, v6_flush_kern_cache_all
+
 	__INITDATA
 
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index a655d3d..df79627 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -32,6 +32,24 @@
 	mov	pc, lr
 ENDPROC(v7_flush_icache_all)
 
+ /*
+ *     v7_flush_dcache_louis()
+ *
+ *     Flush the D-cache up to the Level of Unification Inner Shareable
+ *
+ *     Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
+ */
+
+ENTRY(v7_flush_dcache_louis)
+	dmb					@ ensure ordering with previous memory accesses
+	mrc	p15, 1, r0, c0, c0, 1		@ read clidr, r0 = clidr
+	ands	r3, r0, #0xe00000		@ extract LoUIS from clidr
+	mov	r3, r3, lsr #20			@ r3 = LoUIS * 2
+	moveq	pc, lr				@ return if level == 0
+	mov	r10, #0				@ r10 (starting level) = 0
+	b	loop1				@ start flushing cache levels
+ENDPROC(v7_flush_dcache_louis)
+
 /*
  *	v7_flush_dcache_all()
  *
@@ -119,6 +137,24 @@
 	mov	pc, lr
 ENDPROC(v7_flush_kern_cache_all)
 
+ /*
+ *     v7_flush_kern_cache_louis(void)
+ *
+ *     Flush the data cache up to Level of Unification Inner Shareable.
+ *     Invalidate the I-cache to the point of unification.
+ */
+ENTRY(v7_flush_kern_cache_louis)
+ ARM(	stmfd	sp!, {r4-r5, r7, r9-r11, lr}	)
+ THUMB(	stmfd	sp!, {r4-r7, r9-r11, lr}	)
+	bl	v7_flush_dcache_louis
+	mov	r0, #0
+	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)	@ invalidate I-cache inner shareable
+	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)	@ I+BTB cache invalidate
+ ARM(	ldmfd	sp!, {r4-r5, r7, r9-r11, lr}	)
+ THUMB(	ldmfd	sp!, {r4-r7, r9-r11, lr}	)
+	mov	pc, lr
+ENDPROC(v7_flush_kern_cache_louis)
+
 /*
  *	v7_flush_cache_all()
  *
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 2349513..c11e32e 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -367,6 +367,9 @@
 	mov	pc, lr
 ENDPROC(arm1020_dma_unmap_area)
 
+	.globl	arm1020_flush_kern_cache_louis
+	.equ	arm1020_flush_kern_cache_louis, arm1020_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm1020
 
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index c244b06..9624a35 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -353,6 +353,9 @@
 	mov	pc, lr
 ENDPROC(arm1020e_dma_unmap_area)
 
+	.globl	arm1020e_flush_kern_cache_louis
+	.equ	arm1020e_flush_kern_cache_louis, arm1020e_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm1020e
 
diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S
index 38fe22e..f2b45ee 100644
--- a/arch/arm/mm/proc-arm1022.S
+++ b/arch/arm/mm/proc-arm1022.S
@@ -342,6 +342,9 @@
 	mov	pc, lr
 ENDPROC(arm1022_dma_unmap_area)
 
+	.globl	arm1022_flush_kern_cache_louis
+	.equ	arm1022_flush_kern_cache_louis, arm1022_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm1022
 
diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S
index 3eb9c3c..95934d2 100644
--- a/arch/arm/mm/proc-arm1026.S
+++ b/arch/arm/mm/proc-arm1026.S
@@ -336,6 +336,9 @@
 	mov	pc, lr
 ENDPROC(arm1026_dma_unmap_area)
 
+	.globl	arm1026_flush_kern_cache_louis
+	.equ	arm1026_flush_kern_cache_louis, arm1026_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm1026
 
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index cb941ae..ed3acd4 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -318,6 +318,9 @@
 	mov	pc, lr
 ENDPROC(arm920_dma_unmap_area)
 
+	.globl	arm920_flush_kern_cache_louis
+	.equ	arm920_flush_kern_cache_louis, arm920_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm920
 #endif
diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S
index 4ec0e07..142bace 100644
--- a/arch/arm/mm/proc-arm922.S
+++ b/arch/arm/mm/proc-arm922.S
@@ -320,6 +320,9 @@
 	mov	pc, lr
 ENDPROC(arm922_dma_unmap_area)
 
+	.globl	arm922_flush_kern_cache_louis
+	.equ	arm922_flush_kern_cache_louis, arm922_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm922
 #endif
diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S
index 9dccd9a..3028390 100644
--- a/arch/arm/mm/proc-arm925.S
+++ b/arch/arm/mm/proc-arm925.S
@@ -375,6 +375,9 @@
 	mov	pc, lr
 ENDPROC(arm925_dma_unmap_area)
 
+	.globl	arm925_flush_kern_cache_louis
+	.equ	arm925_flush_kern_cache_louis, arm925_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm925
 
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 820259b..1f99b46 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -338,6 +338,9 @@
 	mov	pc, lr
 ENDPROC(arm926_dma_unmap_area)
 
+	.globl	arm926_flush_kern_cache_louis
+	.equ	arm926_flush_kern_cache_louis, arm926_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm926
 
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
index 9fdc0a1..e5af959 100644
--- a/arch/arm/mm/proc-arm940.S
+++ b/arch/arm/mm/proc-arm940.S
@@ -267,6 +267,9 @@
 	mov	pc, lr
 ENDPROC(arm940_dma_unmap_area)
 
+	.globl	arm940_flush_kern_cache_louis
+	.equ	arm940_flush_kern_cache_louis, arm940_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm940
 
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
index f684cfe..3599b37 100644
--- a/arch/arm/mm/proc-arm946.S
+++ b/arch/arm/mm/proc-arm946.S
@@ -309,6 +309,9 @@
 	mov	pc, lr
 ENDPROC(arm946_dma_unmap_area)
 
+	.globl	arm946_flush_kern_cache_louis
+	.equ	arm946_flush_kern_cache_louis, arm946_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions arm946
 
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index ba3c500..26a9984 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -414,6 +414,9 @@
 	mov	pc, lr
 ENDPROC(feroceon_dma_unmap_area)
 
+	.globl	feroceon_flush_kern_cache_louis
+	.equ	feroceon_flush_kern_cache_louis, feroceon_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions feroceon
 
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 5829bb3..2ea177a 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -299,6 +299,7 @@
 ENTRY(\name\()_cache_fns)
 	.long	\name\()_flush_icache_all
 	.long	\name\()_flush_kern_cache_all
+	.long   \name\()_flush_kern_cache_louis
 	.long	\name\()_flush_user_cache_all
 	.long	\name\()_flush_user_cache_range
 	.long	\name\()_coherent_kern_range
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index cdfedc5..224d0f5 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -302,6 +302,9 @@
 	mov	pc, lr
 ENDPROC(mohawk_dma_unmap_area)
 
+	.globl	mohawk_flush_kern_cache_louis
+	.equ	mohawk_flush_kern_cache_louis, mohawk_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions mohawk
 
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index b0d5786..eb93d64 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -337,6 +337,9 @@
 	mov	pc, lr
 ENDPROC(xsc3_dma_unmap_area)
 
+	.globl	xsc3_flush_kern_cache_louis
+	.equ	xsc3_flush_kern_cache_louis, xsc3_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions xsc3
 
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 4ffebaa..b5ea31d 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -410,6 +410,9 @@
 	mov	pc, lr
 ENDPROC(xscale_dma_unmap_area)
 
+	.globl	xscale_flush_kern_cache_louis
+	.equ	xscale_flush_kern_cache_louis, xscale_flush_kern_cache_all
+
 	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 	define_cache_functions xscale
 
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index e2864ec..02d76fc 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -650,14 +650,13 @@
           different function.
 
 config MSM_ADSPRPC
-        tristate "Qualcomm ADSP RPC driver"
-        depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
-        default m
-        help
-          Provides a communication mechanism that allows for clients to
-          make remote method invocations across processor boundary to
-          applications DSP processor. Say M if you want to enable this
-          module.
+	tristate "Qualcomm ADSP RPC driver"
+	depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
+	help
+	  Provides a communication mechanism that allows for clients to
+	  make remote method invocations across processor boundary to
+	  applications DSP processor. Say M if you want to enable this
+	  module.
 
 config MMC_GENERIC_CSDIO
 	tristate "Generic sdio driver"
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 3aa86463..dde7051 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -33,6 +33,7 @@
 #include <linux/device.h>
 #include <linux/of.h>
 #include <linux/iommu.h>
+#include <linux/kref.h>
 
 #ifndef ION_ADSPRPC_HEAP_ID
 #define ION_ADSPRPC_HEAP_ID ION_AUDIO_HEAP_ID
@@ -152,9 +153,11 @@
 	struct class *class;
 	struct device *dev;
 	struct fastrpc_smmu smmu;
+	struct mutex smd_mutex;
 	dev_t dev_no;
 	spinlock_t wrlock;
 	spinlock_t hlock;
+	struct kref kref;
 	struct hlist_head htbl[RPC_HASH_SZ];
 };
 
@@ -666,6 +669,7 @@
 		spin_lock_init(&me->hlock);
 		spin_lock_init(&me->wrlock);
 		init_completion(&me->work);
+		mutex_init(&me->smd_mutex);
 		for (i = 0; i < RPC_HASH_SZ; ++i)
 			INIT_HLIST_HEAD(&me->htbl[i]);
 		VERIFY(err, 0 == context_list_ctor(&me->clst, SZ_4K));
@@ -692,23 +696,10 @@
 			if (me->smmu.domain_id >= 0)
 				me->smmu.enabled = enabled;
 		}
-		VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
-						SMD_APPS_QDSP, &me->chan,
-						me, smd_event_handler));
-		if (err)
-			goto smd_bail;
-		VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
-							RPC_TIMEOUT));
-		if (err)
-			goto completion_bail;
 	}
 
 	return 0;
 
-completion_bail:
-	smd_close(me->chan);
-smd_bail:
-	ion_client_destroy(me->iclient);
 ion_bail:
 	context_list_dtor(&me->clst);
 context_list_bail:
@@ -1093,9 +1084,22 @@
 	return;
 }
 
+static void fastrpc_channel_close(struct kref *kref)
+{
+	struct fastrpc_apps *me = &gfa;
+
+	smd_close(me->chan);
+	me->chan = 0;
+	mutex_unlock(&me->smd_mutex);
+	pr_info("'closed /dev/%s c %d 0'\n", DEVICE_NAME,
+						MAJOR(me->dev_no));
+}
+
 static int fastrpc_device_release(struct inode *inode, struct file *file)
 {
 	struct file_data *fdata = (struct file_data *)file->private_data;
+	struct fastrpc_apps *me = &gfa;
+
 	(void)fastrpc_release_current_dsp_process();
 	cleanup_current_dev();
 	if (fdata) {
@@ -1108,6 +1112,8 @@
 			kfree(map);
 		}
 		kfree(fdata);
+		kref_put_mutex(&me->kref, fastrpc_channel_close,
+				&me->smd_mutex);
 	}
 	return 0;
 }
@@ -1115,6 +1121,25 @@
 static int fastrpc_device_open(struct inode *inode, struct file *filp)
 {
 	int err = 0;
+	struct fastrpc_apps *me = &gfa;
+
+	mutex_lock(&me->smd_mutex);
+	if (kref_get_unless_zero(&me->kref) == 0) {
+		VERIFY(err, 0 == smd_named_open_on_edge(FASTRPC_SMD_GUID,
+						SMD_APPS_QDSP, &me->chan,
+						me, smd_event_handler));
+		if (err)
+			goto smd_bail;
+		VERIFY(err, 0 != wait_for_completion_timeout(&me->work,
+							RPC_TIMEOUT));
+		if (err)
+			goto completion_bail;
+		kref_init(&me->kref);
+		pr_info("'opened /dev/%s c %d 0'\n", DEVICE_NAME,
+						MAJOR(me->dev_no));
+	}
+	mutex_unlock(&me->smd_mutex);
+
 	filp->private_data = 0;
 	if (0 != try_module_get(THIS_MODULE)) {
 		struct file_data *fdata = 0;
@@ -1136,10 +1161,19 @@
 		if (err) {
 			cleanup_current_dev();
 			kfree(fdata);
+			kref_put_mutex(&me->kref, fastrpc_channel_close,
+					&me->smd_mutex);
 		}
 		module_put(THIS_MODULE);
 	}
 	return err;
+
+completion_bail:
+	smd_close(me->chan);
+	me->chan = 0;
+smd_bail:
+	mutex_unlock(&me->smd_mutex);
+	return err;
 }
 
 
@@ -1257,7 +1291,6 @@
 	VERIFY(err, !IS_ERR(me->dev));
 	if (err)
 		goto device_create_bail;
-	pr_info("'created /dev/%s c %d 0'\n", DEVICE_NAME, MAJOR(me->dev_no));
 
 	return 0;
 
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index e81cfda..d048a91 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -23,6 +23,7 @@
 #include "cpuidle.h"
 
 DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
+DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev);
 
 DEFINE_MUTEX(cpuidle_lock);
 LIST_HEAD(cpuidle_detected_devices);
@@ -484,6 +485,77 @@
 
 EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
 
+/*
+ * cpuidle_unregister: unregister a driver and the devices. This function
+ * can be used only if the driver has been previously registered through
+ * the cpuidle_register function.
+ *
+ * @drv: a valid pointer to a struct cpuidle_driver
+ */
+void cpuidle_unregister(struct cpuidle_driver *drv)
+{
+	int cpu;
+	struct cpuidle_device *device;
+
+	for_each_possible_cpu(cpu) {
+		device = &per_cpu(cpuidle_dev, cpu);
+		cpuidle_unregister_device(device);
+	}
+
+	cpuidle_unregister_driver(drv);
+}
+EXPORT_SYMBOL_GPL(cpuidle_unregister);
+
+/**
+ * cpuidle_register: registers the driver and the cpu devices with the
+ * coupled_cpus passed as parameter. This function is used for all common
+ * initialization pattern there are in the arch specific drivers. The
+ * devices is globally defined in this file.
+ *
+ * @drv         : a valid pointer to a struct cpuidle_driver
+ * @coupled_cpus: a cpumask for the coupled states
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int cpuidle_register(struct cpuidle_driver *drv,
+		     const struct cpumask *const coupled_cpus)
+{
+	int ret, cpu;
+	struct cpuidle_device *device;
+
+	ret = cpuidle_register_driver(drv);
+	if (ret) {
+		pr_err("failed to register cpuidle driver\n");
+		return ret;
+	}
+
+	for_each_possible_cpu(cpu) {
+		device = &per_cpu(cpuidle_dev, cpu);
+		device->cpu = cpu;
+
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+		/*
+		 * On multiplatform for ARM, the coupled idle states could
+		 * enabled in the kernel even if the cpuidle driver does not
+		 * use it. Note, coupled_cpus is a struct copy.
+		 */
+		if (coupled_cpus)
+			device->coupled_cpus = *coupled_cpus;
+#endif
+		ret = cpuidle_register_device(device);
+		if (!ret)
+			continue;
+
+		pr_err("Failed to register cpuidle device for cpu%d\n", cpu);
+
+		cpuidle_unregister(drv);
+		break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cpuidle_register);
+
 #ifdef CONFIG_SMP
 
 static void smp_callback(void *v)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index a8da26d..f5529cd 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -620,7 +620,10 @@
 		msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x1E0);
 		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
 	} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
-		msm_camera_io_w_mb(0x2, vfe_dev->vfe_base + 0x1E0);
+		msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x1E0);
+		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
+		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
+		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
 		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
 	}
 }
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 9047c40..50a25bd 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -866,7 +866,10 @@
 		msm_camera_io_w_mb(0x0, vfe_dev->vfe_base + 0x2F4);
 		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
 	} else if (update_state == DISABLE_CAMIF_IMMEDIATELY) {
-		msm_camera_io_w_mb(0x2, vfe_dev->vfe_base + 0x2F4);
+		msm_camera_io_w_mb(0x6, vfe_dev->vfe_base + 0x2F4);
+		vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev);
+		vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev);
+		vfe_dev->hw_info->vfe_ops.core_ops.init_hw_reg(vfe_dev);
 		vfe_dev->axi_data.src_info[VFE_PIX_0].active = 0;
 	}
 }
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 4f3094a..c0be135 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -318,7 +318,8 @@
 				stream_info->state == PAUSED ||
 				stream_info->state == RESUME_PENDING ||
 				stream_info->state == RESUMING) &&
-				stream_cfg_cmd->cmd == STOP_STREAM) {
+				(stream_cfg_cmd->cmd == STOP_STREAM ||
+				stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) {
 				stream_info->state = ACTIVE;
 			} else {
 				pr_err("%s: Invalid stream state: %d\n",
@@ -654,7 +655,9 @@
 		}
 	}
 
-	if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF) {
+	if (vfe_dev->axi_data.pipeline_update == DISABLE_CAMIF ||
+		(vfe_dev->axi_data.pipeline_update ==
+		DISABLE_CAMIF_IMMEDIATELY)) {
 		vfe_dev->hw_info->vfe_ops.stats_ops.
 			enable_module(vfe_dev, 0xFF, 0);
 		vfe_dev->axi_data.pipeline_update = NO_UPDATE;
@@ -865,6 +868,10 @@
 			(cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
 			stream_cfg_cmd->cmd == STOP_STREAM)
 			return DISABLE_CAMIF;
+		else if (cur_pix_stream_cnt &&
+			(cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
+			stream_cfg_cmd->cmd == STOP_IMMEDIATELY)
+			return DISABLE_CAMIF_IMMEDIATELY;
 	}
 	return NO_UPDATE;
 }
@@ -1170,6 +1177,9 @@
 	if (camif_update == DISABLE_CAMIF)
 		vfe_dev->hw_info->vfe_ops.core_ops.
 			update_camif_state(vfe_dev, DISABLE_CAMIF);
+	else if (camif_update == DISABLE_CAMIF_IMMEDIATELY)
+		vfe_dev->hw_info->vfe_ops.core_ops.
+			update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY);
 	msm_isp_update_camif_output_count(vfe_dev, stream_cfg_cmd);
 
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 071fffc..0bc18fb 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -874,6 +874,11 @@
 		return -EINVAL;
 	}
 
+	if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
+		pr_err("Invalid req/resp buffer, exiting\n");
+		return -EINVAL;
+	}
+
 	if (((uint32_t)req_ptr->cmd_req_buf <
 			data_ptr->client.user_virt_sb_base)
 			|| ((uint32_t)req_ptr->cmd_req_buf >=
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 043f9bc..99e17a6 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -757,7 +757,8 @@
 
 	r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src);
 
-	if (!strcmp(pdata->clk_src, "GPCLK"))
+	if ((!strcmp(pdata->clk_src, "GPCLK")) ||
+	    (!strcmp(pdata->clk_src, "GPCLK2")))
 		pdata->clk_src_gpio = of_get_named_gpio(np,
 				"qcom,clk-en-gpio", 0);
 
@@ -874,6 +875,14 @@
 		} else {
 			goto err_dis_gpio;
 		}
+	} else if (!strcmp(platform_data->clk_src, "GPCLK2")) {
+		if (gpio_is_valid(platform_data->clk_src_gpio)) {
+			nfc_clk  = clk_get(&client->dev, "core_clk_pvt");
+			if (nfc_clk == NULL)
+				goto err_dis_gpio;
+		} else {
+			goto err_dis_gpio;
+		}
 	} else {
 		nfc_clk = NULL;
 	}
@@ -974,7 +983,8 @@
 	r = gpio_direction_input(platform_data->dis_gpio);
 	if (r)
 		dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
-	if (!strcmp(platform_data->clk_src, "GPCLK")) {
+	if ((!strcmp(platform_data->clk_src, "GPCLK")) ||
+            (!strcmp(platform_data->clk_src, "GPCLK2"))) {
 		r = gpio_direction_input(platform_data->clk_src_gpio);
 		if (r)
 			dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 4251968..1ad0054 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -40,6 +40,7 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/swap.h>
+#include <linux/fs.h>
 
 #ifdef CONFIG_HIGHMEM
 #define _ZONE ZONE_HIGHMEM
@@ -246,8 +247,14 @@
 	}
 
 	other_free = global_page_state(NR_FREE_PAGES);
-	other_file = global_page_state(NR_FILE_PAGES) -
-						global_page_state(NR_SHMEM);
+
+	if (global_page_state(NR_SHMEM) + total_swapcache_pages <
+		global_page_state(NR_FILE_PAGES))
+		other_file = global_page_state(NR_FILE_PAGES) -
+						global_page_state(NR_SHMEM) -
+						total_swapcache_pages;
+	else
+		other_file = 0;
 
 	tune_lmk_param(&other_free, &other_file, sc);
 
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 523b937..41a6803 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -430,7 +430,12 @@
 	return next;
 }
 
-/* Encode <page, obj_idx> as a single handle value */
+/*
+ * Encode <page, obj_idx> as a single handle value.
+ * On hardware platforms with physical memory starting at 0x0 the pfn
+ * could be 0 so we ensure that the handle will never be 0 by adjusting the
+ * encoded obj_idx value before encoding.
+ */
 static void *obj_location_to_handle(struct page *page, unsigned long obj_idx)
 {
 	unsigned long handle;
@@ -441,17 +446,21 @@
 	}
 
 	handle = page_to_pfn(page) << OBJ_INDEX_BITS;
-	handle |= (obj_idx & OBJ_INDEX_MASK);
+	handle |= ((obj_idx + 1) & OBJ_INDEX_MASK);
 
 	return (void *)handle;
 }
 
-/* Decode <page, obj_idx> pair from the given object handle */
+/*
+ * Decode <page, obj_idx> pair from the given object handle. We adjust the
+ * decoded obj_idx back to its original value since it was adjusted in
+ * obj_location_to_handle().
+ */
 static void obj_handle_to_location(unsigned long handle, struct page **page,
 				unsigned long *obj_idx)
 {
 	*page = pfn_to_page(handle >> OBJ_INDEX_BITS);
-	*obj_idx = handle & OBJ_INDEX_MASK;
+	*obj_idx = (handle & OBJ_INDEX_MASK) - 1;
 }
 
 static unsigned long obj_idx_to_offset(struct page *page,
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 7d57f64..452e63a 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -1070,6 +1070,27 @@
 	return dsi_pan_node;
 }
 
+static int msm_dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable)
+{
+	u32 bitclk_rate = 0, byteclk_rate = 0, pclk_rate = 0, dsiclk_rate = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	if (enable) {
+		msm_dsi_ahb_ctrl(1);
+		msm_dsi_cal_clk_rate(pdata, &bitclk_rate, &dsiclk_rate,
+					&byteclk_rate, &pclk_rate);
+		msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, dsiclk_rate,
+					byteclk_rate, pclk_rate);
+		msm_dsi_clk_enable();
+	} else {
+		msm_dsi_clk_set_rate(DSI_ESC_CLK_RATE, 0, 0, 0);
+		msm_dsi_clk_disable();
+		msm_dsi_ahb_ctrl(0);
+	}
+	return 0;
+}
+
 static int __devinit msm_dsi_probe(struct platform_device *pdev)
 {
 	struct dsi_interface intf;
@@ -1188,6 +1209,7 @@
 	intf.on = msm_dsi_on;
 	intf.off = msm_dsi_off;
 	intf.cont_on = msm_dsi_cont_on;
+	intf.clk_ctrl = msm_dsi_clk_ctrl;
 	intf.op_mode_config = msm_dsi_op_mode_config;
 	intf.tx = msm_dsi_cmds_tx;
 	intf.rx = msm_dsi_cmds_rx;
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 65cca0e..f3d0ad4 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -104,6 +104,18 @@
 	return rc;
 }
 
+static int dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable)
+{
+	int rc = 0;
+
+	pr_debug("%s:\n", __func__);
+
+	if (dsi_intf.clk_ctrl)
+		rc = dsi_intf.clk_ctrl(pdata, enable);
+
+	return rc;
+}
+
 static int dsi_event_handler(struct mdss_panel_data *pdata,
 				int event, void *arg)
 {
@@ -130,6 +142,9 @@
 	case MDSS_EVENT_CONT_SPLASH_BEGIN:
 		rc = dsi_splash_on(pdata);
 		break;
+	case MDSS_EVENT_PANEL_CLK_CTRL:
+		rc = dsi_clk_ctrl(pdata, (int)arg);
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index e15f640..cb007e3 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -27,6 +27,7 @@
 	int (*on)(struct mdss_panel_data *pdata);
 	int (*off)(struct mdss_panel_data *pdata);
 	int (*cont_on)(struct mdss_panel_data *pdata);
+	int (*clk_ctrl)(struct mdss_panel_data *pdata, int enable);
 	void (*op_mode_config)(int mode, struct mdss_panel_data *pdata);
 	int (*tx)(struct mdss_panel_data *pdata,
 		struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index c4986ef..3999db9 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -38,7 +38,7 @@
 #include <linux/major.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
-
+#include <linux/iopoll.h>
 #include <mach/board.h>
 #include <mach/clk.h>
 #include <mach/hardware.h>
@@ -55,6 +55,10 @@
 #include "mdp3_ppp.h"
 #include "mdss_debug.h"
 
+#define MISR_POLL_SLEEP                 2000
+#define MISR_POLL_TIMEOUT               32000
+#define MDP3_REG_CAPTURED_DSI_PCLK_MASK 1
+
 #define MDP_CORE_HW_VERSION	0x03040310
 struct mdp3_hw_resource *mdp3_res;
 
@@ -1086,6 +1090,7 @@
 static int mdp3_parse_dt(struct platform_device *pdev)
 {
 	struct resource *res;
+	struct property *prop = NULL;
 	int rc;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
@@ -1120,9 +1125,44 @@
 		return rc;
 	}
 
+	prop = of_find_property(pdev->dev.of_node, "batfet-supply", NULL);
+	mdp3_res->batfet_required = prop ? true : false;
+
 	return 0;
 }
 
+void mdp3_batfet_ctrl(int enable)
+{
+	int rc;
+	if (!mdp3_res->batfet_required)
+		return;
+
+	if (!mdp3_res->batfet) {
+		if (enable) {
+			mdp3_res->batfet =
+				devm_regulator_get(&mdp3_res->pdev->dev,
+				"batfet");
+			if (IS_ERR_OR_NULL(mdp3_res->batfet)) {
+				pr_debug("unable to get batfet reg. rc=%d\n",
+					PTR_RET(mdp3_res->batfet));
+				mdp3_res->batfet = NULL;
+				return;
+			}
+		} else {
+			pr_debug("Batfet regulator disable w/o enable\n");
+			return;
+		}
+	}
+
+	if (enable)
+		rc = regulator_enable(mdp3_res->batfet);
+	else
+		rc = regulator_disable(mdp3_res->batfet);
+
+	if (rc < 0)
+		pr_err("%s: reg enable/disable failed", __func__);
+}
+
 static void mdp3_iommu_heap_unmap_iommu(struct mdp3_iommu_meta *meta)
 {
 	unsigned int domain_num;
@@ -1754,6 +1794,11 @@
 	return mdp3_res->domains[MDP3_DMA_IOMMU_DOMAIN].domain_idx;
 }
 
+int mdp3_get_cont_spash_en(void)
+{
+	return mdp3_res->cont_splash_en;
+}
+
 int mdp3_continuous_splash_copy(struct mdss_panel_data *pdata)
 {
 	unsigned long splash_phys, phys;
@@ -1823,6 +1868,9 @@
 
 	pr_debug("mdp3__continuous_splash_on\n");
 
+	mdp3_clk_set_rate(MDP3_CLK_VSYNC, MDP_VSYNC_CLK_RATE,
+			MDP3_CLIENT_DMA_P);
+
 	rc = mdp3_clk_prepare();
 	if (rc) {
 		pr_err("fail to prepare clk\n");
@@ -1866,6 +1914,9 @@
 		mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_VIDEO].active = 1;
 	else
 		mdp3_res->intf[MDP3_DMA_OUTPUT_SEL_DSI_CMD].active = 1;
+
+	mdp3_batfet_ctrl(true);
+	mdp3_res->cont_splash_en = 1;
 	return 0;
 
 splash_on_err:
@@ -2001,6 +2052,105 @@
 	return rc;
 }
 
+int mdp3_misr_get(struct mdp_misr *misr_resp)
+{
+	int result = 0, ret = -1;
+	int crc = 0;
+	pr_debug("%s CRC Capture on DSI\n", __func__);
+	switch (misr_resp->block_id) {
+	case DISPLAY_MISR_DSI0:
+		MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, 0);
+		/* Sleep for one vsync after DSI video engine is disabled */
+		msleep(20);
+		/* Enable DSI_VIDEO_0 MISR Block */
+		MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x20);
+		/* Reset MISR Block */
+		MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 1);
+		/* Clear MISR capture done bit */
+		MDP3_REG_WRITE(MDP3_REG_CAPTURED_DSI_PCLK, 0);
+		/* Enable MDP DSI interface */
+		MDP3_REG_WRITE(MDP3_REG_DSI_VIDEO_EN, 1);
+		ret = readl_poll_timeout(mdp3_res->mdp_base +
+			MDP3_REG_CAPTURED_DSI_PCLK, result,
+			result & MDP3_REG_CAPTURED_DSI_PCLK_MASK,
+			MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+			MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0);
+		if (ret == 0) {
+			/* Disable DSI MISR interface */
+			MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x0);
+			crc = MDP3_REG_READ(MDP3_REG_MISR_CAPT_VAL_DSI_PCLK);
+			pr_debug("CRC Val %d\n", crc);
+		} else {
+			pr_err("CRC Read Timed Out\n");
+		}
+		break;
+
+	case DISPLAY_MISR_DSI_CMD:
+		/* Select DSI PCLK Domain */
+		MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 0x004);
+		/* Select Block id DSI_CMD */
+		MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x10);
+		/* Reset MISR Block */
+		MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 1);
+		/* Drive Data on Test Bus */
+		MDP3_REG_WRITE(MDP3_REG_EXPORT_MISR_DSI_PCLK, 0);
+		/* Kikk off DMA_P */
+		MDP3_REG_WRITE(MDP3_REG_DMA_P_START, 0x11);
+		/* Wait for DMA_P Done */
+		ret = readl_poll_timeout(mdp3_res->mdp_base +
+			MDP3_REG_INTR_STATUS, result,
+			result & MDP3_INTR_DMA_P_DONE_BIT,
+			MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+		if (ret == 0) {
+			crc = MDP3_REG_READ(MDP3_REG_MISR_CURR_VAL_DSI_PCLK);
+			pr_debug("CRC Val %d\n", crc);
+		} else {
+			pr_err("CRC Read Timed Out\n");
+		}
+		break;
+
+	default:
+		pr_err("%s CRC Capture not supported\n", __func__);
+		ret = -EINVAL;
+		break;
+	}
+
+	misr_resp->crc_value[0] = crc;
+	pr_debug("%s, CRC Capture on DSI Param Block = 0x%x, CRC 0x%x\n",
+			__func__, misr_resp->block_id, misr_resp->crc_value[0]);
+	return ret;
+}
+
+int mdp3_misr_set(struct mdp_misr *misr_req)
+{
+	int ret = 0;
+	pr_debug("%s Parameters Block = %d Cframe Count = %d CRC = %d\n",
+			__func__, misr_req->block_id, misr_req->frame_count,
+			misr_req->crc_value[0]);
+
+	switch (misr_req->block_id) {
+	case DISPLAY_MISR_DSI0:
+		pr_debug("In the case DISPLAY_MISR_DSI0\n");
+		MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 1);
+		MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x20);
+		MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 0x1);
+		break;
+
+	case DISPLAY_MISR_DSI_CMD:
+		pr_debug("In the case DISPLAY_MISR_DSI_CMD\n");
+		MDP3_REG_WRITE(MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS, 1);
+		MDP3_REG_WRITE(MDP3_REG_MODE_DSI_PCLK, 0x10);
+		MDP3_REG_WRITE(MDP3_REG_MISR_RESET_DSI_PCLK, 0x1);
+		break;
+
+	default:
+		pr_err("%s CRC Capture not supported\n", __func__);
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int mdp3_probe(struct platform_device *pdev)
 {
 	int rc;
@@ -2118,11 +2268,13 @@
 
 static  int mdp3_suspend_sub(struct mdp3_hw_resource *mdata)
 {
+	mdp3_batfet_ctrl(false);
 	return 0;
 }
 
 static  int mdp3_resume_sub(struct mdp3_hw_resource *mdata)
 {
+	mdp3_batfet_ctrl(true);
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index e0dd021..28997ec 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -25,6 +25,8 @@
 #include "mdp3_dma.h"
 #include "mdss_fb.h"
 
+#define MDP_VSYNC_CLK_RATE	19200000
+
 enum  {
 	MDP3_CLK_AHB,
 	MDP3_CLK_CORE,
@@ -154,6 +156,10 @@
 	u32 splash_mem_size;
 
 	int clk_prepare_count;
+	int cont_splash_en;
+
+	bool batfet_required;
+	struct regulator *batfet;
 };
 
 struct mdp3_img_data {
@@ -191,8 +197,13 @@
 int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
 void mdp3_release_splash_memory(void);
 int mdp3_create_sysfs_link(struct device *dev);
+int mdp3_get_cont_spash_en(void);
 int mdp3_get_mdp_dsi_clk(void);
 int mdp3_put_mdp_dsi_clk(void);
+void mdp3_batfet_ctrl(int enable);
+
+int mdp3_misr_set(struct mdp_misr *misr_req);
+int mdp3_misr_get(struct mdp_misr *misr_resp);
 
 #define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
 #define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index de4e9a1..6219737 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -26,12 +26,15 @@
 #include "mdp3_ppp.h"
 
 #define MDP_CORE_CLK_RATE	100000000
-#define MDP_VSYNC_CLK_RATE	19200000
+#define VSYNC_EXPIRE_TICK	4
 
 static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd);
 static int mdp3_overlay_unset(struct msm_fb_data_type *mfd, int ndx);
 static int mdp3_histogram_stop(struct mdp3_session_data *session,
 					u32 block);
+static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable);
+static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable);
+static int mdp3_ctrl_get_intf_type(struct msm_fb_data_type *mfd);
 
 static void mdp3_bufq_init(struct mdp3_buffer_queue *bufq)
 {
@@ -88,6 +91,29 @@
 	return bufq->count;
 }
 
+static void mdp3_dispatch_clk_off(struct work_struct *work)
+{
+	struct mdp3_session_data *session;
+
+	pr_debug("%s\n", __func__);
+	session = container_of(work, struct mdp3_session_data,
+				clk_off_work);
+	if (!session)
+		return;
+
+	mutex_lock(&session->lock);
+	if (session->vsync_enabled ||
+			atomic_read(&session->vsync_countdown) != 0) {
+		mutex_unlock(&session->lock);
+		pr_debug("Ignoring clk shut down\n");
+		return;
+	}
+
+	mdp3_ctrl_vsync_enable(session->mfd, 0);
+	mdp3_ctrl_clk_enable(session->mfd, 0);
+	mutex_unlock(&session->lock);
+}
+
 void vsync_notify_handler(void *arg)
 {
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
@@ -95,6 +121,22 @@
 	sysfs_notify_dirent(session->vsync_event_sd);
 }
 
+void vsync_count_down(void *arg)
+{
+	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
+	/* We are counting down to turn off clocks */
+	atomic_dec(&session->vsync_countdown);
+	if (atomic_read(&session->vsync_countdown) == 0)
+		schedule_work(&session->clk_off_work);
+}
+
+void mdp3_ctrl_reset_countdown(struct mdp3_session_data *session,
+		struct msm_fb_data_type *mfd)
+{
+	if (mdp3_ctrl_get_intf_type(mfd) == MDP3_DMA_OUTPUT_SEL_DSI_CMD)
+		atomic_set(&session->vsync_countdown, VSYNC_EXPIRE_TICK);
+}
+
 static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
 {
 	struct mdp3_session_data *mdp3_session;
@@ -115,26 +157,44 @@
 		vsync_client.handler = vsync_notify_handler;
 		vsync_client.arg = mdp3_session;
 		arg = &vsync_client;
+	} else if (atomic_read(&mdp3_session->vsync_countdown)) {
+		/*
+		 * Now that vsync is no longer needed we will
+		 * shutdown dsi clocks as soon as cnt down == 0
+		 * for cmd mode panels
+		 */
+		vsync_client.handler = vsync_count_down;
+		vsync_client.arg = mdp3_session;
+		arg = &vsync_client;
+		enable = 1;
 	}
 
-	mutex_lock(&mdp3_session->lock);
 	mdp3_clk_enable(1, 0);
 	mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
 	mdp3_clk_enable(0, 0);
-	if (enable && mdp3_session->status == 1 && !mdp3_session->intf->active)
+
+	/*
+	 * Need to fake vsync whenever dsi interface is not
+	 * active or when dsi clocks are currently off
+	 */
+	if (enable && mdp3_session->status == 1
+			&& mdp3_session->vsync_before_commit) {
 		mod_timer(&mdp3_session->vsync_timer,
 			jiffies + msecs_to_jiffies(mdp3_session->vsync_period));
-	 else if (!enable)
+	} else if (enable && !mdp3_session->clk_on) {
+		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+		mdp3_ctrl_clk_enable(mfd, 1);
+	} else if (!enable) {
 		del_timer(&mdp3_session->vsync_timer);
+	}
 
-	mutex_unlock(&mdp3_session->lock);
 	return 0;
 }
 
 void mdp3_vsync_timer_func(unsigned long arg)
 {
 	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
-	if (session->status == 1 && !session->intf->active) {
+	if (session->status == 1 && session->vsync_before_commit) {
 		pr_debug("mdp3_vsync_timer_func trigger\n");
 		vsync_notify_handler(session);
 		mod_timer(&session->vsync_timer,
@@ -211,6 +271,33 @@
 	.attrs = vsync_fs_attrs,
 };
 
+static int mdp3_ctrl_clk_enable(struct msm_fb_data_type *mfd, int enable)
+{
+	struct mdp3_session_data *session;
+	struct mdss_panel_data *panel;
+	int rc = 0;
+
+	pr_debug("mdp3_ctrl_clk_enable %d\n", enable);
+
+	session = mfd->mdp.private1;
+	panel = session->panel;
+
+	if (!panel->event_handler)
+		return 0;
+
+	if ((enable && session->clk_on == 0) ||
+				(!enable && session->clk_on == 1)) {
+		rc = panel->event_handler(panel,
+			MDSS_EVENT_PANEL_CLK_CTRL, (void *)enable);
+		rc |= mdp3_clk_enable(enable, 1);
+	} else {
+		pr_debug("enable = %d, clk_on=%d\n", enable, session->clk_on);
+	}
+
+	session->clk_on = enable;
+	return rc;
+}
+
 static int mdp3_ctrl_res_req_bus(struct msm_fb_data_type *mfd, int status)
 {
 	int rc = 0;
@@ -439,6 +526,8 @@
 		goto on_error;
 	}
 
+	mdp3_batfet_ctrl(true);
+
 	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
 	if (rc) {
 		pr_err("fail to attach MDP DMA SMMU\n");
@@ -487,6 +576,7 @@
 		goto on_error;
 	}
 
+	mdp3_session->clk_on = 1;
 	pr_debug("mdp3_ctrl_on dma start\n");
 	if (mfd->fbi->screen_base) {
 		rc = mdp3_session->dma->start(mdp3_session->dma,
@@ -531,7 +621,7 @@
 		goto off_error;
 	}
 
-	mdp3_clk_enable(1, 0);
+	mdp3_ctrl_clk_enable(mfd, 1);
 
 	mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
 
@@ -539,7 +629,6 @@
 	if (rc)
 		pr_debug("fail to stop the MDP3 dma\n");
 
-	mdp3_clk_enable(0, 0);
 
 	if (panel->event_handler)
 		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
@@ -549,15 +638,19 @@
 	mdp3_irq_deregister();
 
 	pr_debug("mdp3_ctrl_off stop clock\n");
-	rc = mdp3_ctrl_res_req_clk(mfd, 0);
-	if (rc)
-		pr_err("mdp clock resource release failed\n");
+	if (mdp3_session->clk_on) {
+		rc = mdp3_clk_enable(0, 1);
+		if (rc)
+			pr_err("mdp clock resource release failed\n");
 
-	pr_debug("mdp3_ctrl_off stop dsi controller\n");
-	if (panel->event_handler)
-		rc = panel->event_handler(panel, MDSS_EVENT_BLANK, NULL);
-	if (rc)
-		pr_err("fail to turn off the panel\n");
+		pr_debug("mdp3_ctrl_off stop dsi controller\n");
+		if (panel->event_handler)
+			rc = panel->event_handler(panel,
+				MDSS_EVENT_BLANK, NULL);
+		if (rc)
+			pr_err("fail to turn off the panel\n");
+	}
+	mdp3_clk_unprepare();
 
 	pr_debug("mdp3_ctrl_off release bus\n");
 	rc = mdp3_ctrl_res_req_bus(mfd, 0);
@@ -568,6 +661,10 @@
 	if (rc)
 		pr_err("fail to dettach MDP DMA SMMU\n");
 
+	mdp3_batfet_ctrl(false);
+	mdp3_session->vsync_enabled = 0;
+	atomic_set(&mdp3_session->vsync_countdown, 0);
+	mdp3_session->clk_on = 0;
 off_error:
 	mdp3_session->status = 0;
 	mdp3_bufq_deinit(&mdp3_session->bufq_out);
@@ -861,11 +958,11 @@
 
 	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
 	if (data) {
-		mdp3_clk_enable(1, 0);
+		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+		mdp3_ctrl_clk_enable(mfd, 1);
 		mdp3_session->dma->update(mdp3_session->dma,
 			(void *)data->addr,
 			mdp3_session->intf);
-		mdp3_clk_enable(0, 0);
 		mdp3_bufq_push(&mdp3_session->bufq_out, data);
 	}
 
@@ -879,6 +976,8 @@
 		msleep(1000 / panel_info->mipi.frame_rate);
 		mdp3_session->first_commit = false;
 	}
+
+	mdp3_session->vsync_before_commit = 0;
 	if (reset_done && (panel && panel->set_backlight))
 		panel->set_backlight(panel, panel->panel_info.bl_max);
 
@@ -930,16 +1029,18 @@
 		goto pan_error;
 	}
 
-	mdp3_clk_enable(1, 0);
 	if (mfd->fbi->screen_base) {
+		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
+		mdp3_ctrl_clk_enable(mfd, 1);
 		mdp3_session->dma->update(mdp3_session->dma,
 				(void *)mfd->iova + offset,
 				mdp3_session->intf);
 	} else {
 		pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
+		mdp3_clk_enable(1, 0);
 		mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+		mdp3_clk_enable(0, 0);
 	}
-	mdp3_clk_enable(0, 0);
 
 	if (mdp3_session->first_commit) {
 		/*wait for one frame time to ensure frame is sent to panel*/
@@ -947,10 +1048,28 @@
 		mdp3_session->first_commit = false;
 	}
 
+	mdp3_session->vsync_before_commit = 0;
+
 pan_error:
 	mutex_unlock(&mdp3_session->lock);
 }
 
+static int mdp3_set_metadata(struct msm_fb_data_type *mfd,
+				struct msmfb_metadata *metadata_ptr)
+{
+	int ret = 0;
+	switch (metadata_ptr->op) {
+	case metadata_op_crc:
+		ret = mdp3_misr_set(&metadata_ptr->data.misr_request);
+		break;
+	default:
+		pr_warn("Unsupported request to MDP SET META IOCTL.\n");
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
 static int mdp3_get_metadata(struct msm_fb_data_type *mfd,
 				struct msmfb_metadata *metadata)
 {
@@ -966,8 +1085,11 @@
 		metadata->data.caps.vig_pipes = 0;
 		metadata->data.caps.dma_pipes = 1;
 		break;
+	case metadata_op_crc:
+		ret = mdp3_misr_get(&metadata->data.misr_request);
+		break;
 	default:
-		pr_warn("Unsupported request to MDP META IOCTL.\n");
+		pr_warn("Unsupported request to MDP GET  META IOCTL.\n");
 		ret = -EINVAL;
 		break;
 	}
@@ -1084,8 +1206,7 @@
 	session->histo_status = 1;
 
 histogram_start_err:
-	if (ret)
-		mdp3_clk_enable(0, 0);
+	mdp3_clk_enable(0, 0);
 	mutex_unlock(&session->histo_lock);
 	return ret;
 }
@@ -1108,6 +1229,7 @@
 		goto histogram_stop_err;
 	}
 
+	mdp3_clk_enable(1, 0);
 	ret = session->dma->histo_op(session->dma, MDP3_DMA_HISTO_OP_CANCEL);
 	mdp3_clk_enable(0, 0);
 	if (ret)
@@ -1126,11 +1248,17 @@
 	int ret;
 	struct mdp3_dma_histogram_data *mdp3_histo;
 
+	pr_debug("%s\n", __func__);
 	if (!session->dma->get_histo) {
 		pr_err("mdp3_histogram_collect not supported\n");
 		return -EINVAL;
 	}
 
+	if (!session->clk_on) {
+		pr_debug("mdp/dsi clock off currently\n");
+		return -EPERM;
+	}
+
 	mutex_lock(&session->histo_lock);
 
 	if (!session->histo_status) {
@@ -1141,7 +1269,9 @@
 
 	mutex_unlock(&session->histo_lock);
 
+	mdp3_clk_enable(1, 0);
 	ret = session->dma->get_histo(session->dma);
+	mdp3_clk_enable(0, 0);
 	if (ret) {
 		pr_debug("mdp3_histogram_collect error = %d\n", ret);
 		return ret;
@@ -1414,7 +1544,10 @@
 	case MSMFB_VSYNC_CTRL:
 	case MSMFB_OVERLAY_VSYNC_CTRL:
 		if (!copy_from_user(&val, argp, sizeof(val))) {
+			mutex_lock(&mdp3_session->lock);
+			mdp3_session->vsync_enabled = val;
 			rc = mdp3_ctrl_vsync_enable(mfd, val);
+			mutex_unlock(&mdp3_session->lock);
 		} else {
 			pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n");
 			rc = -EFAULT;
@@ -1428,11 +1561,19 @@
 		break;
 	case MSMFB_METADATA_GET:
 		rc = copy_from_user(&metadata, argp, sizeof(metadata));
-		if (rc)
-			return rc;
-		rc = mdp3_get_metadata(mfd, &metadata);
+		if (!rc)
+			rc = mdp3_get_metadata(mfd, &metadata);
 		if (!rc)
 			rc = copy_to_user(argp, &metadata, sizeof(metadata));
+		if (rc)
+			pr_err("mdp3_get_metadata failed (%d)\n", rc);
+		break;
+	case MSMFB_METADATA_SET:
+		rc = copy_from_user(&metadata, argp, sizeof(metadata));
+		if (!rc)
+			rc = mdp3_set_metadata(mfd, &metadata);
+		if (rc)
+			pr_err("mdp3_set_metadata failed (%d)\n", rc);
 		break;
 	case MSMFB_OVERLAY_GET:
 		rc = copy_from_user(req, argp, sizeof(*req));
@@ -1503,6 +1644,8 @@
 	}
 	memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
 	mutex_init(&mdp3_session->lock);
+	INIT_WORK(&mdp3_session->clk_off_work, mdp3_dispatch_clk_off);
+	atomic_set(&mdp3_session->vsync_countdown, 0);
 	mutex_init(&mdp3_session->histo_lock);
 	mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
 	if (!mdp3_session->dma) {
@@ -1570,6 +1713,10 @@
 		mdp3_ctrl_off(mfd);
 	}
 
+	if (mdp3_get_cont_spash_en())
+		mdp3_session->clk_on = 1;
+
+	mdp3_session->vsync_before_commit = true;
 init_done:
 	if (IS_ERR_VALUE(rc))
 		kfree(mdp3_session);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 66ed3d5..f2484ef 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -48,11 +48,17 @@
 	struct mdp_overlay req_overlay;
 	struct mdp3_buffer_queue bufq_in;
 	struct mdp3_buffer_queue bufq_out;
+	struct work_struct clk_off_work;
 	int histo_status;
 	struct mutex histo_lock;
 	int lut_sel;
 	int cc_vect_sel;
+	bool vsync_before_commit;
 	bool first_commit;
+	int clk_on;
+
+	int vsync_enabled;
+	atomic_t vsync_countdown; /* Used to count down  */
 };
 
 int mdp3_ctrl_init(struct msm_fb_data_type *mfd);
diff --git a/drivers/video/msm/mdss/mdp3_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
index 8846ec5..b457c10 100644
--- a/drivers/video/msm/mdss/mdp3_hwio.h
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -55,6 +55,7 @@
 
 #define MDP3_REG_HW_VERSION				0x0070
 #define MDP3_REG_SW_RESET				0x0074
+#define MDP3_REG_SEL_CLK_OR_HCLK_TEST_BUS		0x007C
 
 /*EBI*/
 #define MDP3_REG_EBI2_LCD0				0x003c
@@ -117,6 +118,46 @@
 #define MDP3_REG_DMA_S_IBUF_Y_STRIDE			0xA000C
 #define MDP3_REG_DMA_S_OUT_XY				0xA0010
 
+/*MISR*/
+#define MDP3_REG_MODE_CLK				0x000D0000
+#define MDP3_REG_MISR_RESET_CLK			0x000D0004
+#define MDP3_REG_EXPORT_MISR_CLK			0x000D0008
+#define MDP3_REG_MISR_CURR_VAL_CLK			0x000D000C
+#define MDP3_REG_MODE_HCLK				0x000D0100
+#define MDP3_REG_MISR_RESET_HCLK			0x000D0104
+#define MDP3_REG_EXPORT_MISR_HCLK			0x000D0108
+#define MDP3_REG_MISR_CURR_VAL_HCLK			0x000D010C
+#define MDP3_REG_MODE_DCLK				0x000D0200
+#define MDP3_REG_MISR_RESET_DCLK			0x000D0204
+#define MDP3_REG_EXPORT_MISR_DCLK			0x000D0208
+#define MDP3_REG_MISR_CURR_VAL_DCLK			0x000D020C
+#define MDP3_REG_CAPTURED_DCLK				0x000D0210
+#define MDP3_REG_MISR_CAPT_VAL_DCLK			0x000D0214
+#define MDP3_REG_MODE_TVCLK				0x000D0300
+#define MDP3_REG_MISR_RESET_TVCLK			0x000D0304
+#define MDP3_REG_EXPORT_MISR_TVCLK			0x000D0308
+#define MDP3_REG_MISR_CURR_VAL_TVCLK			0x000D030C
+#define MDP3_REG_CAPTURED_TVCLK			0x000D0310
+#define MDP3_REG_MISR_CAPT_VAL_TVCLK			0x000D0314
+
+/* Select DSI operation type(CMD/VIDEO) */
+#define MDP3_REG_MODE_DSI_PCLK				0x000D0400
+#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_CMD		0x10
+#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_VIDEO1	0x20
+#define MDP3_REG_MODE_DSI_PCLK_BLOCK_DSI_VIDEO2	0x30
+/* RESET DSI MISR STATE */
+#define MDP3_REG_MISR_RESET_DSI_PCLK			0x000D0404
+
+/* For reading MISR State(1) and driving data on test bus(0) */
+#define MDP3_REG_EXPORT_MISR_DSI_PCLK			0x000D0408
+/* Read MISR signature */
+#define MDP3_REG_MISR_CURR_VAL_DSI_PCLK		0x000D040C
+
+/* MISR status Bit0 (1) Capture Done */
+#define MDP3_REG_CAPTURED_DSI_PCLK			0x000D0410
+#define MDP3_REG_MISR_CAPT_VAL_DSI_PCLK		0x000D0414
+#define MDP3_REG_MISR_TESTBUS_CAPT_VAL			0x000D0600
+
 /*interface*/
 #define MDP3_REG_LCDC_EN				0xE0000
 #define MDP3_REG_LCDC_HSYNC_CTL				0xE0004
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index 61c4acd..448a6b1 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -66,6 +66,19 @@
 	void (*debug_enable_clock)(int on);
 };
 
+#define MDSS_IRQ_SUSPEND	-1
+#define MDSS_IRQ_RESUME		1
+#define MDSS_IRQ_REQ		0
+
+struct mdss_intr {
+	/* requested intr */
+	u32 req;
+	/* currently enabled intr */
+	u32 curr;
+	int state;
+	spinlock_t lock;
+};
+
 struct mdss_data_type {
 	u32 mdp_rev;
 	struct clk *mdp_clk[MDSS_MAX_CLK];
@@ -130,10 +143,14 @@
 	u32 nintf;
 
 	u32 pp_bus_hdl;
+	struct mdss_mdp_ad *ad_off;
 	struct mdss_ad_info *ad_cfgs;
 	u32 nad_cfgs;
+	u32 nmax_concurrent_ad_hw;
 	struct workqueue_struct *ad_calc_wq;
 
+	struct mdss_intr hist_intr;
+
 	struct ion_client *iclient;
 	int iommu_attached;
 	struct mdss_iommu_map_type *iommu_map;
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index f933c8e..0d0240f 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -23,12 +23,13 @@
 
 #include "mdss.h"
 #include "mdss_mdp.h"
+#include "mdss_mdp_hwio.h"
 #include "mdss_debug.h"
 
 #define DEFAULT_BASE_REG_CNT 0x100
 #define GROUP_BYTES 4
 #define ROW_BYTES 16
-
+#define MAX_VSYNC_COUNT 0xFFFFFFF
 struct mdss_debug_data {
 	struct dentry *root;
 	struct list_head base_list;
@@ -409,28 +410,63 @@
 	return 0;
 }
 
+int vsync_count;
 static struct mdss_mdp_misr_map {
 	u32 ctrl_reg;
 	u32 value_reg;
 	u32 crc_op_mode;
 	u32 crc_index;
-	u32 crc_value[MISR_CRC_BATCH_SIZE];
+	bool use_ping;
+	bool is_ping_full;
+	bool is_pong_full;
+	struct mutex crc_lock;
+	u32 crc_ping[MISR_CRC_BATCH_SIZE];
+	u32 crc_pong[MISR_CRC_BATCH_SIZE];
 } mdss_mdp_misr_table[DISPLAY_MISR_MAX] = {
 	[DISPLAY_MISR_DSI0] = {
 		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI0,
 		.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
+		.crc_op_mode = 0,
+		.crc_index = 0,
+		.use_ping = true,
+		.is_ping_full = false,
+		.is_pong_full = false,
 	},
 	[DISPLAY_MISR_DSI1] = {
 		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI1,
 		.value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
+		.crc_op_mode = 0,
+		.crc_index = 0,
+		.use_ping = true,
+		.is_ping_full = false,
+		.is_pong_full = false,
 	},
 	[DISPLAY_MISR_EDP] = {
 		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_EDP,
 		.value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
+		.crc_op_mode = 0,
+		.crc_index = 0,
+		.use_ping = true,
+		.is_ping_full = false,
+		.is_pong_full = false,
 	},
 	[DISPLAY_MISR_HDMI] = {
 		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_HDMI,
 		.value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
+		.crc_op_mode = 0,
+		.crc_index = 0,
+		.use_ping = true,
+		.is_ping_full = false,
+		.is_pong_full = false,
+	},
+	[DISPLAY_MISR_MDP] = {
+		.ctrl_reg = MDSS_MDP_LP_MISR_CTRL_MDP,
+		.value_reg = MDSS_MDP_LP_MISR_SIGN_MDP,
+		.crc_op_mode = 0,
+		.crc_index = 0,
+		.use_ping = true,
+		.is_ping_full = false,
+		.is_pong_full = false,
 	},
 };
 
@@ -438,7 +474,7 @@
 {
 	struct mdss_mdp_misr_map *map;
 
-	if (block_id > DISPLAY_MISR_LCDC) {
+	if (block_id > DISPLAY_MISR_MDP) {
 		pr_err("MISR Block id (%d) out of range\n", block_id);
 		return NULL;
 	}
@@ -452,23 +488,51 @@
 	return map;
 }
 
-int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req)
+int mdss_misr_set(struct mdss_data_type *mdata,
+			struct mdp_misr *req,
+			struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_misr_map *map;
-	u32 config = 0;
-
+	struct mdss_mdp_mixer *mixer;
+	u32 config = 0, val = 0;
+	u32 mixer_num = 0;
+	bool is_valid_wb_mixer = true;
 	map = mdss_misr_get_map(req->block_id);
 	if (!map) {
 		pr_err("Invalid MISR Block=%d\n", req->block_id);
 		return -EINVAL;
 	}
-
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (req->block_id == DISPLAY_MISR_MDP) {
+		mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+		mixer_num = mixer->num;
+		pr_debug("SET MDP MISR BLK to MDSS_MDP_LP_MISR_SEL_LMIX%d_GC\n",
+			req->block_id);
+		switch (mixer_num) {
+		case MDSS_MDP_INTF_LAYERMIXER0:
+			pr_debug("Use Layer Mixer 0 for WB CRC\n");
+			val = MDSS_MDP_LP_MISR_SEL_LMIX0_GC;
+			break;
+		case MDSS_MDP_INTF_LAYERMIXER1:
+			pr_debug("Use Layer Mixer 1 for WB CRC\n");
+			val = MDSS_MDP_LP_MISR_SEL_LMIX1_GC;
+			break;
+		case MDSS_MDP_INTF_LAYERMIXER2:
+			pr_debug("Use Layer Mixer 2 for WB CRC\n");
+			val = MDSS_MDP_LP_MISR_SEL_LMIX2_GC;
+			break;
+		default:
+			pr_err("Invalid Layer Mixer %d selected for WB CRC\n",
+				mixer_num);
+			is_valid_wb_mixer = false;
+			break;
+		}
+		if (is_valid_wb_mixer)
+			writel_relaxed(val,
+				mdata->mdp_base + MDSS_MDP_LP_MISR_SEL);
+	}
+	vsync_count = 0;
 	map->crc_op_mode = req->crc_op_mode;
-	memset(map->crc_value, 0, sizeof(map->crc_value));
-
-	pr_debug("MISR Config (BlockId %d) (Frame Count = %d)\n",
-		req->block_id, req->frame_count);
-
 	config = (MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK & req->frame_count) |
 			(MDSS_MDP_LP_MISR_CTRL_ENABLE);
 
@@ -476,24 +540,32 @@
 			mdata->mdp_base + map->ctrl_reg);
 	/* ensure clear is done */
 	wmb();
-	if (MISR_OP_BM == map->crc_op_mode) {
-		writel_relaxed(MISR_CRC_BATCH_CFG,
-			mdata->mdp_base + map->ctrl_reg);
-	} else {
-		writel_relaxed(config,
-			mdata->mdp_base + map->ctrl_reg);
 
-		config = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
-		pr_debug("MISR_CTRL = 0x%x", config);
+	memset(map->crc_ping, 0, sizeof(map->crc_ping));
+	memset(map->crc_pong, 0, sizeof(map->crc_pong));
+	map->crc_index = 0;
+	map->use_ping = true;
+	map->is_ping_full = false;
+	map->is_pong_full = false;
+
+	if (MISR_OP_BM != map->crc_op_mode) {
+
+		writel_relaxed(config,
+				mdata->mdp_base + map->ctrl_reg);
+		pr_debug("MISR_CTRL = 0x%x",
+				readl_relaxed(mdata->mdp_base + map->ctrl_reg));
 	}
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	return 0;
 }
 
-int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp)
+int mdss_misr_get(struct mdss_data_type *mdata,
+			struct mdp_misr *resp,
+			struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_misr_map *map;
 	u32 status;
-	int ret = 0;
+	int ret = -1;
 	int i;
 
 	map = mdss_misr_get_map(resp->block_id);
@@ -501,35 +573,60 @@
 		pr_err("Invalid MISR Block=%d\n", resp->block_id);
 		return -EINVAL;
 	}
-
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	switch (map->crc_op_mode) {
 	case MISR_OP_SFM:
 	case MISR_OP_MFM:
 		ret = readl_poll_timeout(mdata->mdp_base + map->ctrl_reg,
 				status, status & MDSS_MDP_LP_MISR_CTRL_STATUS,
 				MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
-
-		pr_debug("Status of Get MISR_CTRL = 0x%x", status);
 		if (ret == 0) {
-			resp->crc_value[0] =
-				readl_relaxed(mdata->mdp_base + map->value_reg);
+			resp->crc_value[0] = readl_relaxed(mdata->mdp_base +
+				map->value_reg);
 			pr_debug("CRC %d=0x%x\n", resp->block_id,
-					resp->crc_value[0]);
+				resp->crc_value[0]);
+			writel_relaxed(0, mdata->mdp_base + map->ctrl_reg);
 		} else {
-			pr_warn("MISR %d busy with status 0x%x\n",
-					resp->block_id, status);
+			mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+			ret = readl_poll_timeout(mdata->mdp_base +
+					map->ctrl_reg, status,
+					status & MDSS_MDP_LP_MISR_CTRL_STATUS,
+					MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+			if (ret == 0) {
+				resp->crc_value[0] =
+					readl_relaxed(mdata->mdp_base +
+					map->value_reg);
+			}
+			writel_relaxed(0, mdata->mdp_base + map->ctrl_reg);
 		}
 		break;
 	case MISR_OP_BM:
-		for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
-			resp->crc_value[i] = map->crc_value[i];
-		map->crc_index = 0;
+		if (map->is_ping_full) {
+			for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
+				resp->crc_value[i] = map->crc_ping[i];
+			memset(map->crc_ping, 0, sizeof(map->crc_ping));
+			map->is_ping_full = false;
+			ret = 0;
+		} else if (map->is_pong_full) {
+			for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
+				resp->crc_value[i] = map->crc_pong[i];
+			memset(map->crc_pong, 0, sizeof(map->crc_pong));
+			map->is_pong_full = false;
+			ret = 0;
+		} else {
+			pr_debug("mdss_mdp_misr_crc_get PING BUF %s\n",
+				map->is_ping_full ? "FULL" : "EMPTRY");
+			pr_debug("mdss_mdp_misr_crc_get PONG BUF %s\n",
+				map->is_pong_full ? "FULL" : "EMPTRY");
+		}
+		resp->crc_op_mode = map->crc_op_mode;
 		break;
 	default:
 		ret = -ENOSYS;
 		break;
 	}
 
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	return ret;
 }
 
@@ -537,22 +634,71 @@
 void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
 {
 	struct mdss_mdp_misr_map *map;
-	u32 status, config;
+	u32 status = 0;
+	u32 crc = 0x0BAD0BAD;
+	bool crc_stored = false;
 
 	map = mdss_misr_get_map(block_id);
 	if (!map || (map->crc_op_mode != MISR_OP_BM))
 		return;
 
-	config = MISR_CRC_BATCH_CFG;
-
 	status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
-	if (status & MDSS_MDP_LP_MISR_CTRL_STATUS) {
-		map->crc_value[map->crc_index] =
-			readl_relaxed(mdata->mdp_base + map->value_reg);
-		map->crc_index++;
-		if (map->crc_index == MISR_CRC_BATCH_SIZE)
-			map->crc_index = 0;
-		config |= MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR;
+	if (MDSS_MDP_LP_MISR_CTRL_STATUS & status) {
+		crc = readl_relaxed(mdata->mdp_base + map->value_reg);
+		if (map->use_ping) {
+			if (map->is_ping_full) {
+				pr_err("PING Buffer FULL\n");
+			} else {
+				map->crc_ping[map->crc_index] = crc;
+				crc_stored = true;
+			}
+		} else {
+			if (map->is_pong_full) {
+				pr_err("PONG Buffer FULL\n");
+			} else {
+				map->crc_pong[map->crc_index] = crc;
+				crc_stored = true;
+			}
+		}
+
+		if (crc_stored) {
+			map->crc_index = (map->crc_index + 1);
+			if (map->crc_index == MISR_CRC_BATCH_SIZE) {
+				map->crc_index = 0;
+				if (true == map->use_ping) {
+					map->is_ping_full = true;
+					map->use_ping = false;
+				} else {
+					map->is_pong_full = true;
+					map->use_ping = true;
+				}
+				pr_debug("USE BUFF %s\n", map->use_ping ?
+					"PING" : "PONG");
+				pr_debug("mdss_misr_crc_collect PING BUF %s\n",
+					map->is_ping_full ? "FULL" : "EMPTRY");
+				pr_debug("mdss_misr_crc_collect PONG BUF %s\n",
+					map->is_pong_full ? "FULL" : "EMPTRY");
+			}
+		} else {
+			pr_err("CRC(%d) Not saved\n", crc);
+		}
+
+		writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
+				mdata->mdp_base + map->ctrl_reg);
+		writel_relaxed(MISR_CRC_BATCH_CFG,
+				mdata->mdp_base + map->ctrl_reg);
+	} else if (0 == status) {
+		writel_relaxed(MISR_CRC_BATCH_CFG,
+				mdata->mdp_base + map->ctrl_reg);
+		pr_debug("$$ Batch CRC Start $$\n");
 	}
-	writel_relaxed(config, mdata->mdp_base + map->ctrl_reg);
+	pr_debug("$$ Vsync Count = %d, CRC=0x%x Indx = %d$$\n",
+		vsync_count, crc, map->crc_index);
+
+	if (MAX_VSYNC_COUNT == vsync_count) {
+		pr_err("RESET vsync_count(%d)\n", vsync_count);
+		vsync_count = 0;
+	} else {
+		vsync_count += 1;
+	}
 }
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
index 29eb16c..984caab 100644
--- a/drivers/video/msm/mdss/mdss_debug.h
+++ b/drivers/video/msm/mdss/mdss_debug.h
@@ -16,30 +16,35 @@
 
 #include "mdss.h"
 
-#define MISR_POLL_SLEEP			2000
-#define MISR_POLL_TIMEOUT		32000
-#define MISR_CRC_BATCH_SIZE		32
-#define MISR_CRC_BATCH_CFG		0x101
+#define MISR_POLL_SLEEP		2000
+#define MISR_POLL_TIMEOUT	32000
+#define MISR_CRC_BATCH_CFG	0x101
 
 #ifdef CONFIG_DEBUG_FS
 int mdss_debugfs_init(struct mdss_data_type *mdata);
 int mdss_debugfs_remove(struct mdss_data_type *mdata);
 int mdss_debug_register_base(const char *name, void __iomem *base,
 				    size_t max_offset);
-int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req);
-int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp);
+int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req,
+			struct mdss_mdp_ctl *ctl);
+int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp,
+			struct mdss_mdp_ctl *ctl);
 void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
 #else
 static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
 static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
 { return 0; }
 static inline int mdss_debug_register_base(const char *name, void __iomem *base,
-			     size_t max_offset) { return 0; }
-static inline int mdss_misr_crc_set(struct mdss_data_type *mdata,
-		      struct mdp_misr *reg) { return 0; }
-static inline int mdss_misr_crc_get(struct mdss_data_type *mdata,
-		      struct mdp_misr *resp) { return 0; }
+					size_t max_offset) { return 0; }
+static inline int mdss_misr_set(struct mdss_data_type *mdata,
+					struct mdp_misr *req,
+					struct mdss_mdp_ctl *ctl)
+{ return 0; }
+static inline int mdss_misr_get(struct mdss_data_type *mdata,
+					struct mdp_misr *resp,
+					struct mdss_mdp_ctl *ctl)
+{ return 0; }
 static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
-			   int block_id) { }
+						int block_id) { }
 #endif
 #endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 7202c62..947923a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -89,6 +89,17 @@
 	DSI_HS_MODE,
 };
 
+enum dsi_lane_map_type {
+	DSI_LANE_MAP_0123,
+	DSI_LANE_MAP_3012,
+	DSI_LANE_MAP_2301,
+	DSI_LANE_MAP_1230,
+	DSI_LANE_MAP_0321,
+	DSI_LANE_MAP_1032,
+	DSI_LANE_MAP_2103,
+	DSI_LANE_MAP_3210,
+};
+
 #define CTRL_STATE_UNKNOWN		0x00
 #define CTRL_STATE_PANEL_INIT		BIT(0)
 #define CTRL_STATE_MDP_ACTIVE		BIT(1)
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 8c04940..59e52b9 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -366,6 +366,49 @@
 	return 0;
 }
 
+static void mdss_dsi_parse_lane_swap(struct device_node *np, char *dlane_swap)
+{
+	const char *data;
+
+	*dlane_swap = DSI_LANE_MAP_0123;
+	data = of_get_property(np, "qcom,mdss-dsi-lane-map", NULL);
+	if (data) {
+		if (!strcmp(data, "lane_map_3012"))
+			*dlane_swap = DSI_LANE_MAP_3012;
+		else if (!strcmp(data, "lane_map_2301"))
+			*dlane_swap = DSI_LANE_MAP_2301;
+		else if (!strcmp(data, "lane_map_1230"))
+			*dlane_swap = DSI_LANE_MAP_1230;
+		else if (!strcmp(data, "lane_map_0321"))
+			*dlane_swap = DSI_LANE_MAP_0321;
+		else if (!strcmp(data, "lane_map_1032"))
+			*dlane_swap = DSI_LANE_MAP_1032;
+		else if (!strcmp(data, "lane_map_2103"))
+			*dlane_swap = DSI_LANE_MAP_2103;
+		else if (!strcmp(data, "lane_map_3210"))
+			*dlane_swap = DSI_LANE_MAP_3210;
+	}
+}
+
+static void mdss_dsi_parse_trigger(struct device_node *np, char *trigger,
+		char *trigger_key)
+{
+	const char *data;
+
+	*trigger = DSI_CMD_TRIGGER_SW;
+	data = of_get_property(np, trigger_key, NULL);
+	if (data) {
+		if (!strcmp(data, "none"))
+			*trigger = DSI_CMD_TRIGGER_NONE;
+		else if (!strcmp(data, "trigger_te"))
+			*trigger = DSI_CMD_TRIGGER_TE;
+		else if (!strcmp(data, "trigger_sw_seof"))
+			*trigger = DSI_CMD_TRIGGER_SW_SEOF;
+		else if (!strcmp(data, "trigger_sw_te"))
+			*trigger = DSI_CMD_TRIGGER_SW_TE;
+	}
+}
+
 
 static int mdss_dsi_parse_dcs_cmds(struct device_node *np,
 		struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key)
@@ -652,8 +695,10 @@
 	data = of_get_property(np, "qcom,mdss-dsi-panel-type", NULL);
 	if (data && !strncmp(data, "dsi_cmd_mode", 12))
 		pinfo->mipi.mode = DSI_CMD_MODE;
-	rc = of_property_read_u32(np, "qcom,mdss-dsi-pixel-packing", &tmp);
-	tmp = (!rc ? tmp : 0);
+	tmp = 0;
+	data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL);
+	if (data && !strcmp(data, "loose"))
+		tmp = 1;
 	rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
 		pinfo->mipi.mode, tmp,
 		&(pinfo->mipi.dst_format));
@@ -761,10 +806,14 @@
 		"qcom,mdss-dsi-bllp-power-mode");
 	pinfo->mipi.eof_bllp_power_stop = of_property_read_bool(
 		np, "qcom,mdss-dsi-bllp-eof-power-mode");
-	rc = of_property_read_u32(np,
-		"qcom,mdss-dsi-traffic-mode", &tmp);
-	pinfo->mipi.traffic_mode =
-			(!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE);
+	pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE;
+	data = of_get_property(np, "qcom,mdss-dsi-traffic-mode", NULL);
+	if (data) {
+		if (!strcmp(data, "non_burst_sync_event"))
+			pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT;
+		else if (!strcmp(data, "burst_mode"))
+			pinfo->mipi.traffic_mode = DSI_BURST_MODE;
+	}
 	rc = of_property_read_u32(np,
 		"qcom,mdss-dsi-te-dcs-command", &tmp);
 	pinfo->mipi.insert_dcs_cmd =
@@ -783,8 +832,20 @@
 			(!rc ? tmp : 1);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-virtual-channel-id", &tmp);
 	pinfo->mipi.vc = (!rc ? tmp : 0);
-	rc = of_property_read_u32(np, "qcom,mdss-dsi-color-order", &tmp);
-	pinfo->mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB);
+	pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB;
+	data = of_get_property(np, "mdss-dsi-color-order", NULL);
+	if (data) {
+		if (!strcmp(data, "rgb_swap_rbg"))
+			pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RBG;
+		else if (!strcmp(data, "rgb_swap_bgr"))
+			pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BGR;
+		else if (!strcmp(data, "rgb_swap_brg"))
+			pinfo->mipi.rgb_swap = DSI_RGB_SWAP_BRG;
+		else if (!strcmp(data, "rgb_swap_grb"))
+			pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GRB;
+		else if (!strcmp(data, "rgb_swap_gbr"))
+			pinfo->mipi.rgb_swap = DSI_RGB_SWAP_GBR;
+	}
 	pinfo->mipi.data_lane0 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-0-state");
 	pinfo->mipi.data_lane1 = of_property_read_bool(np,
@@ -794,9 +855,6 @@
 	pinfo->mipi.data_lane3 = of_property_read_bool(np,
 		"qcom,mdss-dsi-lane-3-state");
 
-	rc = of_property_read_u32(np, "qcom,mdss-dsi-lane-map", &tmp);
-	pinfo->mipi.dlane_swap = (!rc ? tmp : 0);
-
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-pre", &tmp);
 	pinfo->mipi.t_clk_pre = (!rc ? tmp : 0x24);
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-t-clk-post", &tmp);
@@ -805,26 +863,7 @@
 	rc = of_property_read_u32(np, "qcom,mdss-dsi-stream", &tmp);
 	pinfo->mipi.stream = (!rc ? tmp : 0);
 
-	rc = of_property_read_u32(np, "qcom,mdss-dsi-mdp-trigger", &tmp);
-	pinfo->mipi.mdp_trigger =
-			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (pinfo->mipi.mdp_trigger > 6) {
-		pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger",
-						 __func__, __LINE__);
-		pinfo->mipi.mdp_trigger =
-					DSI_CMD_TRIGGER_SW;
-	}
-
-	rc = of_property_read_u32(np, "qcom,mdss-dsi-dma-trigger", &tmp);
-	pinfo->mipi.dma_trigger =
-			(!rc ? tmp : DSI_CMD_TRIGGER_SW);
-	if (pinfo->mipi.dma_trigger > 6) {
-		pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger",
-						 __func__, __LINE__);
-		pinfo->mipi.dma_trigger =
-					DSI_CMD_TRIGGER_SW;
-	}
-	data = of_get_property(np, "qcom,mdss-dsi-panel-mode-gpio-state", &tmp);
+	data = of_get_property(np, "qcom,mdss-dsi-panel-mode-gpio-state", NULL);
 	if (data) {
 		if (!strcmp(data, "high"))
 			pinfo->mode_gpio_state = MODE_GPIO_HIGH;
@@ -854,6 +893,14 @@
 
 	mdss_dsi_parse_fbc_params(np, pinfo);
 
+	mdss_dsi_parse_trigger(np, &(pinfo->mipi.mdp_trigger),
+		"qcom,mdss-dsi-mdp-trigger");
+
+	mdss_dsi_parse_trigger(np, &(pinfo->mipi.dma_trigger),
+		"qcom,mdss-dsi-dma-trigger");
+
+	mdss_dsi_parse_lane_swap(np, &(pinfo->mipi.dlane_swap));
+
 	mdss_dsi_parse_reset_seq(np, pinfo->rst_seq, &(pinfo->rst_seq_len),
 		"qcom,mdss-dsi-reset-sequence");
 
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 96d8be0..5408bc3 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -92,7 +92,7 @@
 		unsigned long val, void *data);
 
 static int __mdss_fb_display_thread(void *data);
-static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
+static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
 static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
 					int event, void *arg);
 void mdss_fb_no_update_notify_timer_cb(unsigned long data)
@@ -297,6 +297,7 @@
 {
 	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
 
+	mfd->shutdown_pending = true;
 	lock_fb_info(mfd->fbi);
 	mdss_fb_release_all(mfd->fbi, true);
 	unlock_fb_info(mfd->fbi);
@@ -779,13 +780,18 @@
 	u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
 	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int ret = 0;
 
 	if (!start) {
 		pr_warn("No framebuffer memory is allocated.\n");
 		return -ENOMEM;
 	}
 
-	mdss_fb_pan_idle(mfd);
+	ret = mdss_fb_pan_idle(mfd);
+	if (ret) {
+		pr_err("Shutdown pending. Aborting operation\n");
+		return ret;
+	}
 
 	/* Set VM flags. */
 	start &= PAGE_MASK;
@@ -1120,8 +1126,6 @@
 		     mfd->index, fbi->var.xres, fbi->var.yres,
 		     fbi->fix.smem_len);
 
-	kthread_run(__mdss_fb_display_thread, mfd, "mdss_fb%d", mfd->index);
-
 	return 0;
 }
 
@@ -1132,6 +1136,11 @@
 	int result;
 	int pid = current->tgid;
 
+	if (mfd->shutdown_pending) {
+		pr_err("Shutdown pending. Aborting operation\n");
+		return -EPERM;
+	}
+
 	list_for_each_entry(pinfo, &mfd->proc_list, list) {
 		if (pinfo->pid == pid)
 			break;
@@ -1151,23 +1160,47 @@
 
 	result = pm_runtime_get_sync(info->dev);
 
-	if (result < 0)
+	if (result < 0) {
 		pr_err("pm_runtime: fail to wake up\n");
+		goto pm_error;
+	}
 
 	if (!mfd->ref_cnt) {
+		mfd->disp_thread = kthread_run(__mdss_fb_display_thread, mfd,
+				"mdss_fb%d", mfd->index);
+		if (IS_ERR(mfd->disp_thread)) {
+			pr_err("unable to start display thread %d\n",
+				mfd->index);
+			result = PTR_ERR(mfd->disp_thread);
+			goto thread_error;
+		}
+
 		result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
 					   mfd->op_enable);
 		if (result) {
-			pm_runtime_put(info->dev);
 			pr_err("can't turn on fb%d! rc=%d\n", mfd->index,
 				result);
-			return result;
+			goto blank_error;
 		}
 	}
 
 	pinfo->ref_cnt++;
 	mfd->ref_cnt++;
+
 	return 0;
+
+blank_error:
+	kthread_stop(mfd->disp_thread);
+
+thread_error:
+	if (pinfo && !pinfo->ref_cnt) {
+		list_del(&pinfo->list);
+		kfree(pinfo);
+	}
+	pm_runtime_put(info->dev);
+
+pm_error:
+	return result;
 }
 
 static int mdss_fb_release_all(struct fb_info *info, bool release_all)
@@ -1209,6 +1242,9 @@
 			pm_runtime_put(info->dev);
 		} while (release_all && pinfo->ref_cnt);
 
+		if (release_all)
+			kthread_stop(mfd->disp_thread);
+
 		if (pinfo->ref_cnt == 0) {
 			list_del(&pinfo->list);
 			kfree(pinfo);
@@ -1245,6 +1281,8 @@
 	}
 
 	if (!mfd->ref_cnt) {
+		kthread_stop(mfd->disp_thread);
+
 		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
 			mfd->op_enable);
 		if (ret) {
@@ -1421,21 +1459,28 @@
  * hardware configuration. After this function returns it is safe to perform
  * software updates for next frame.
  */
-static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
+static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
 {
-	int ret;
+	int ret = 0;
 
 	ret = wait_event_timeout(mfd->idle_wait_q,
-			!atomic_read(&mfd->commits_pending),
+			(!atomic_read(&mfd->commits_pending) ||
+			 mfd->shutdown_pending),
 			msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT));
 	if (!ret) {
 		pr_err("wait for idle timeout %d pending=%d\n",
 				ret, atomic_read(&mfd->commits_pending));
 
 		mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
+	} else if (mfd->shutdown_pending) {
+		pr_debug("Shutdown signalled\n");
+		return -EPERM;
 	}
+
+	return 0;
 }
 
+
 static int mdss_fb_pan_display_ex(struct fb_info *info,
 		struct mdp_display_commit *disp_commit)
 {
@@ -1453,7 +1498,11 @@
 	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
 		return -EINVAL;
 
-	mdss_fb_pan_idle(mfd);
+	ret = mdss_fb_pan_idle(mfd);
+	if (ret) {
+		pr_err("Shutdown pending. Aborting operation\n");
+		return ret;
+	}
 
 	mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
 	if (info->fix.xpanstep)
@@ -1585,14 +1634,20 @@
 
 	while (1) {
 		wait_event(mfd->commit_wait_q,
-				atomic_read(&mfd->commits_pending));
+				(atomic_read(&mfd->commits_pending) ||
+				 kthread_should_stop()));
+
+		if (kthread_should_stop())
+			break;
 
 		ret = __mdss_fb_perform_commit(mfd);
-
 		atomic_dec(&mfd->commits_pending);
 		wake_up_all(&mfd->idle_wait_q);
 	}
 
+	atomic_set(&mfd->commits_pending, 0);
+	wake_up_all(&mfd->idle_wait_q);
+
 	return ret;
 }
 
@@ -1715,8 +1770,14 @@
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
 	struct fb_var_screeninfo *var = &info->var;
 	int old_imgType;
+	int ret = 0;
 
-	mdss_fb_pan_idle(mfd);
+	ret = mdss_fb_pan_idle(mfd);
+	if (ret) {
+		pr_err("Shutdown pending. Aborting operation\n");
+		return ret;
+	}
+
 	old_imgType = mfd->fb_imgType;
 	switch (var->bits_per_pixel) {
 	case 16:
@@ -1763,7 +1824,7 @@
 		mfd->panel_reconfig = false;
 	}
 
-	return 0;
+	return ret;
 }
 
 int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
@@ -2004,8 +2065,15 @@
 	mfd = (struct msm_fb_data_type *)info->par;
 	mdss_fb_power_setting_idle(mfd);
 	if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
-			(cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT))
-		mdss_fb_pan_idle(mfd);
+			(cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) &&
+			(cmd != MSMFB_NOTIFY_UPDATE)) {
+		ret = mdss_fb_pan_idle(mfd);
+		if (ret) {
+			pr_debug("Shutdown pending. Aborting operation %x\n",
+				cmd);
+			return ret;
+		}
+	}
 
 	switch (cmd) {
 	case MSMFB_CURSOR:
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 80e6581..e245dd3 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -195,9 +195,11 @@
 	struct msm_sync_pt_data mdp_sync_pt_data;
 
 	/* for non-blocking */
+	struct task_struct *disp_thread;
 	atomic_t commits_pending;
 	wait_queue_head_t commit_wait_q;
 	wait_queue_head_t idle_wait_q;
+	bool shutdown_pending;
 
 	struct msm_fb_backup_type msm_fb_backup;
 	struct completion power_set_comp;
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 0afa501..222a1e5 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -994,6 +994,9 @@
 		/* swap */
 		writel_relaxed(1, offset + 16);
 	}
+
+	mdata->nmax_concurrent_ad_hw = (mdata->mdp_rev <= MDSS_MDP_HW_REV_102) ?
+									1 : 2;
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	pr_debug("MDP hw init done\n");
 
@@ -1018,6 +1021,11 @@
 	if (rc)
 		return rc;
 
+	mdata->hist_intr.req = 0;
+	mdata->hist_intr.curr = 0;
+	mdata->hist_intr.state = 0;
+	spin_lock_init(&mdata->hist_intr.lock);
+
 	mdata->iclient = msm_ion_client_create(-1, mdata->pdev->name);
 	if (IS_ERR_OR_NULL(mdata->iclient)) {
 		pr_err("msm_ion_client_create() return error (%p)\n",
@@ -1978,9 +1986,11 @@
 		mdata->ad_cfgs = NULL;
 		return 0;
 	}
+
 	if (mdata->nad_cfgs > mdata->nmixers_intf)
 		return -EINVAL;
 
+
 	mdata->has_wb_ad = of_property_read_bool(pdev->dev.of_node,
 		"qcom,mdss-has-wb-ad");
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 6646c0b..d69102a 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -275,10 +275,16 @@
 	spinlock_t hist_lock;
 };
 
-struct mdss_ad_info {
+struct mdss_mdp_ad {
 	char __iomem *base;
 	u8 num;
+};
+
+struct mdss_ad_info {
+	u8 num;
+	u8 calc_hw_num;
 	u32 sts;
+	u32 reg_sts;
 	u32 state;
 	u32 ad_data;
 	u32 ad_data_mode;
@@ -292,6 +298,7 @@
 	struct completion comp;
 	u32 last_str;
 	u32 last_bl;
+	u32 bl_data;
 	u32 calc_itr;
 	uint32_t bl_bright_shift;
 	uint32_t bl_lin[AD_BL_LIN_LEN];
@@ -546,6 +553,7 @@
 int mdss_hw_init(struct mdss_data_type *mdata);
 
 int mdss_mdp_pa_config(struct mdp_pa_cfg_data *config, u32 *copyback);
+int mdss_mdp_pa_v2_config(struct mdp_pa_v2_cfg_data *config, u32 *copyback);
 int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *cfg_ptr, u32 *copyback);
 int mdss_mdp_igc_lut_config(struct mdp_igc_lut_data *config, u32 *copyback,
 				u32 copy_from_kernel);
@@ -554,8 +562,10 @@
 int mdss_mdp_dither_config(struct mdp_dither_cfg_data *config, u32 *copyback);
 int mdss_mdp_gamut_config(struct mdp_gamut_cfg_data *config, u32 *copyback);
 
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req);
-int mdss_mdp_histogram_stop(u32 block);
+int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en);
+int mdss_mdp_hist_intr_setup(struct mdss_intr *intr, int state);
+int mdss_mdp_hist_start(struct mdp_histogram_start_req *req);
+int mdss_mdp_hist_stop(u32 block);
 int mdss_mdp_hist_collect(struct mdp_histogram_data *hist);
 void mdss_mdp_hist_intr_done(u32 isr);
 
@@ -563,7 +573,7 @@
 				struct mdss_ad_init_cfg *init_cfg);
 int mdss_mdp_ad_input(struct msm_fb_data_type *mfd,
 				struct mdss_ad_input *input, int wait);
-int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off);
+int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets);
 int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd,
 				struct mdss_calib_cfg *cfg);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 19ed857..9fd2c8b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1108,6 +1108,7 @@
 int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_ctl *sctl;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	int ret = 0;
 
 	if (ctl->power_on) {
@@ -1155,6 +1156,7 @@
 			mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
 		}
 	}
+	mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 error:
@@ -1167,6 +1169,7 @@
 {
 	struct mdss_mdp_ctl *sctl;
 	int ret = 0;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	u32 off;
 
 	if (!ctl->power_on) {
@@ -1182,6 +1185,8 @@
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
+	mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
+
 	if (ctl->stop_fnc)
 		ret = ctl->stop_fnc(ctl);
 	else
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 52ca42c..b6f94d0 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -20,6 +20,7 @@
 #define GC_LUT_SEGMENTS	16
 #define ENHIST_LUT_ENTRIES 256
 #define HIST_V_SIZE	256
+#define SIX_ZONE_LUT_ENTRIES 384
 
 #define MDSS_MDP_HW_REV_100		0x10000000
 #define MDSS_MDP_HW_REV_102		0x10020000
@@ -216,8 +217,20 @@
 #define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX		0x228
 #define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY		0x22C
 #define MDSS_MDP_REG_VIG_QSEED2_SHARP			0x230
+#define MDSS_MDP_REG_VIG_MEM_COL_BASE			0x288
 #define MDSS_MDP_REG_VIG_PA_BASE			0x310
 
+#define MDSS_MDP_VIG_OP_PA_SAT_ZERO_EXP_EN		BIT(2)
+#define MDSS_MDP_VIG_OP_PA_MEM_PROTECT_EN		BIT(3)
+#define MDSS_MDP_VIG_OP_PA_EN				BIT(4)
+#define MDSS_MDP_VIG_OP_PA_MEM_COL_SKIN_MASK		BIT(5)
+#define MDSS_MDP_VIG_OP_PA_MEM_COL_FOL_MASK		BIT(6)
+#define MDSS_MDP_VIG_OP_PA_MEM_COL_SKY_MASK		BIT(7)
+#define MDSS_MDP_VIG_OP_PA_HUE_MASK			BIT(25)
+#define MDSS_MDP_VIG_OP_PA_SAT_MASK			BIT(26)
+#define MDSS_MDP_VIG_OP_PA_VAL_MASK			BIT(27)
+#define MDSS_MDP_VIG_OP_PA_CONT_MASK			BIT(28)
+
 #define MDSS_MDP_REG_SCALE_CONFIG			0x204
 #define MDSS_MDP_REG_SCALE_PHASE_STEP_X			0x210
 #define MDSS_MDP_REG_SCALE_PHASE_STEP_Y			0x214
@@ -359,6 +372,8 @@
 #define MDSS_MDP_REG_WB_CSC_BASE			0x260
 #define MDSS_MDP_REG_WB_DST_ADDR_SW_STATUS		0x2B0
 
+#define MDSS_MDP_MAX_AD_AL	65535
+#define MDSS_MDP_MAX_AD_STR	255
 
 #define MDSS_MDP_REG_AD_BYPASS				0x000
 #define MDSS_MDP_REG_AD_CTRL_0				0x004
@@ -394,6 +409,11 @@
 #define MDSS_MDP_REG_AD_STR_OUT				0x14C
 #define MDSS_MDP_REG_AD_BL_OUT				0x154
 #define MDSS_MDP_REG_AD_CALC_DONE			0x158
+#define MDSS_MDP_REG_AD_FRAME_END			0x15C
+#define MDSS_MDP_REG_AD_PROCS_END			0x160
+#define MDSS_MDP_REG_AD_FRAME_START			0x164
+#define MDSS_MDP_REG_AD_PROCS_START			0x168
+#define MDSS_MDP_REG_AD_TILE_CTRL			0x16C
 
 enum mdss_mdp_dspp_index {
 	MDSS_MDP_DSPP0,
@@ -413,6 +433,28 @@
 #define MDSS_MDP_REG_DSPP_GAMUT_BASE			0x2DC
 #define MDSS_MDP_REG_DSPP_GC_BASE			0x2B0
 
+#define MDSS_MDP_DSPP_OP_IGC_LUT_EN			BIT(0)
+#define MDSS_MDP_DSPP_OP_PA_SAT_ZERO_EXP_EN		BIT(1)
+#define MDSS_MDP_DSPP_OP_PA_MEM_PROTECT_EN		BIT(2)
+#define MDSS_MDP_DSPP_OP_PCC_EN				BIT(4)
+#define MDSS_MDP_DSPP_OP_PA_MEM_COL_SKIN_MASK		BIT(5)
+#define MDSS_MDP_DSPP_OP_PA_MEM_COL_FOL_MASK		BIT(6)
+#define MDSS_MDP_DSPP_OP_PA_MEM_COL_SKY_MASK		BIT(7)
+#define MDSS_MDP_DSPP_OP_DST_DITHER_EN			BIT(8)
+#define MDSS_MDP_DSPP_OP_HIST_EN			BIT(16)
+#define MDSS_MDP_DSPP_OP_HIST_LUTV_EN			BIT(19)
+#define MDSS_MDP_DSPP_OP_PA_EN				BIT(20)
+#define MDSS_MDP_DSPP_OP_ARGC_LUT_EN			BIT(22)
+#define MDSS_MDP_DSPP_OP_GAMUT_EN			BIT(23)
+#define MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER		BIT(24)
+#define MDSS_MDP_DSPP_OP_PA_HUE_MASK			BIT(25)
+#define MDSS_MDP_DSPP_OP_PA_SAT_MASK			BIT(26)
+#define MDSS_MDP_DSPP_OP_PA_VAL_MASK			BIT(27)
+#define MDSS_MDP_DSPP_OP_PA_CONT_MASK			BIT(28)
+#define MDSS_MDP_DSPP_OP_PA_SIX_ZONE_HUE_MASK		BIT(29)
+#define MDSS_MDP_DSPP_OP_PA_SIX_ZONE_SAT_MASK		BIT(30)
+#define MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK		BIT(31)
+
 enum mdss_mpd_intf_index {
 	MDSS_MDP_NO_INTF,
 	MDSS_MDP_INTF0,
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index d3e18ac..1d302db 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -196,12 +196,14 @@
 static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
 {
 	unsigned long flags;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	mutex_lock(&ctx->clk_mtx);
 	if (!ctx->clk_enabled) {
 		ctx->clk_enabled = 1;
 		mdss_mdp_ctl_intf_event
 			(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)1);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME);
 	}
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	if (!ctx->rdptr_enabled)
@@ -214,6 +216,7 @@
 static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
 {
 	unsigned long flags;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 	int set_clk_off = 0;
 
 	mutex_lock(&ctx->clk_mtx);
@@ -224,6 +227,7 @@
 
 	if (ctx->clk_enabled && set_clk_off) {
 		ctx->clk_enabled = 0;
+		mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
 		mdss_mdp_ctl_intf_event
 			(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c677dff..e8be7e2 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -540,11 +540,10 @@
 					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(&hist);
+				mdss_mdp_hist_start(&hist);
 			} else if (pipe->pp_cfg.hist_cfg.ops &
 							MDP_PP_OPS_DISABLE) {
-				mdss_mdp_histogram_stop(
-					pipe->pp_cfg.hist_cfg.block);
+				mdss_mdp_hist_stop(pipe->pp_cfg.hist_cfg.block);
 			}
 		}
 		len = pipe->pp_cfg.hist_lut_cfg.len;
@@ -1953,6 +1952,11 @@
 					&copyback);
 		break;
 
+	case mdp_op_pa_v2_cfg:
+		ret = mdss_mdp_pa_v2_config(&mdp_pp.data.pa_v2_cfg_data,
+					&copyback);
+		break;
+
 	case mdp_op_pcc_cfg:
 		ret = mdss_mdp_pcc_config(&mdp_pp.data.pcc_cfg_data,
 					&copyback);
@@ -2059,7 +2063,7 @@
 		if (ret)
 			return ret;
 
-		ret = mdss_mdp_histogram_start(&hist_req);
+		ret = mdss_mdp_hist_start(&hist_req);
 		break;
 
 	case MSMFB_HISTOGRAM_STOP:
@@ -2067,7 +2071,7 @@
 		if (ret)
 			return ret;
 
-		ret = mdss_mdp_histogram_stop(block);
+		ret = mdss_mdp_hist_stop(block);
 		if (ret)
 			return ret;
 
@@ -2103,7 +2107,10 @@
 				struct msmfb_metadata *metadata)
 {
 	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	int ret = 0;
+	if (!ctl)
+		return  -EPERM;
 	switch (metadata->op) {
 	case metadata_op_vic:
 		if (mfd->panel_info)
@@ -2115,7 +2122,7 @@
 	case metadata_op_crc:
 		if (!mfd->panel_power_on)
 			return -EPERM;
-		ret = mdss_misr_crc_set(mdata, &metadata->data.misr_request);
+		ret = mdss_misr_set(mdata, &metadata->data.misr_request, ctl);
 		break;
 	case metadata_op_wb_format:
 		ret = mdss_mdp_wb_set_format(mfd,
@@ -2151,7 +2158,10 @@
 				struct msmfb_metadata *metadata)
 {
 	struct mdss_data_type *mdata = mfd_to_mdata(mfd);
+	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	int ret = 0;
+	if (!ctl)
+		return -EPERM;
 	switch (metadata->op) {
 	case metadata_op_frame_rate:
 		metadata->data.panel_frame_rate =
@@ -2163,7 +2173,7 @@
 	case metadata_op_crc:
 		if (!mfd->panel_power_on)
 			return -EPERM;
-		ret = mdss_misr_crc_get(mdata, &metadata->data.misr_request);
+		ret = mdss_misr_get(mdata, &metadata->data.misr_request, ctl);
 		break;
 	case metadata_op_wb_format:
 		ret = mdss_mdp_wb_get_format(mfd, &metadata->data.mixer_cfg);
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index dc7b8b3..8dc6c56 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -184,9 +184,27 @@
 #define PP_FLAGS_DIRTY_PGC	0x100
 #define PP_FLAGS_DIRTY_SHARP	0x200
 
+#define PP_SSPP		0
+#define PP_DSPP		1
+
 #define PP_STS_ENABLE	0x1
 #define PP_STS_GAMUT_FIRST	0x2
 
+#define PP_STS_PA_HUE_MASK		0x2
+#define PP_STS_PA_SAT_MASK		0x4
+#define PP_STS_PA_VAL_MASK		0x8
+#define PP_STS_PA_CONT_MASK		0x10
+#define PP_STS_PA_MEM_PROTECT_EN	0x20
+#define PP_STS_PA_MEM_COL_SKIN_MASK	0x40
+#define PP_STS_PA_MEM_COL_FOL_MASK	0x80
+#define PP_STS_PA_MEM_COL_SKY_MASK	0x100
+#define PP_STS_PA_SIX_ZONE_HUE_MASK	0x200
+#define PP_STS_PA_SIX_ZONE_SAT_MASK	0x400
+#define PP_STS_PA_SIX_ZONE_VAL_MASK	0x800
+#define PP_STS_PA_SAT_ZERO_EXP_EN	0x1000
+
+#define PP_AD_BAD_HW_NUM 255
+
 #define PP_AD_STATE_INIT	0x2
 #define PP_AD_STATE_CFG		0x4
 #define PP_AD_STATE_DATA	0x8
@@ -205,6 +223,7 @@
 #define PP_AD_STS_DIRTY_CFG	0x4
 #define PP_AD_STS_DIRTY_DATA	0x8
 #define PP_AD_STS_DIRTY_VSYNC	0x10
+#define PP_AD_STS_DIRTY_ENABLE	0x20
 
 #define PP_AD_STS_IS_DIRTY(sts) (((sts) & PP_AD_STS_DIRTY_INIT) ||\
 					((sts) & PP_AD_STS_DIRTY_CFG))
@@ -262,6 +281,9 @@
 		gc_lut_b[MDSS_BLOCK_DISP_NUM][GC_LUT_SEGMENTS];
 	u32 enhist_lut[MDSS_BLOCK_DISP_NUM][ENHIST_LUT_ENTRIES];
 	struct mdp_pa_cfg pa_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	struct mdp_pa_v2_data pa_v2_disp_cfg[MDSS_BLOCK_DISP_NUM];
+	u32 six_zone_lut_curve_p0[MDSS_BLOCK_DISP_NUM][SIX_ZONE_LUT_ENTRIES];
+	u32 six_zone_lut_curve_p1[MDSS_BLOCK_DISP_NUM][SIX_ZONE_LUT_ENTRIES];
 	struct mdp_pcc_cfg_data pcc_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_igc_lut_data igc_disp_cfg[MDSS_BLOCK_DISP_NUM];
 	struct mdp_pgc_lut_data argc_disp_cfg[MDSS_BLOCK_DISP_NUM];
@@ -279,51 +301,85 @@
 static DEFINE_MUTEX(mdss_pp_mutex);
 static struct mdss_pp_res_type *mdss_pp_res;
 
-static void pp_hist_read(char __iomem *v_base,
+static void pp_hist_read(char __iomem *v_addr,
 				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,
+static void pp_update_pcc_regs(char __iomem *addr,
 				struct mdp_pcc_cfg_data *cfg_ptr);
 static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
-				u32 offset, u32 blk_idx);
-static void pp_update_gc_one_lut(u32 offset,
+				char __iomem *addr, u32 blk_idx);
+static void pp_update_gc_one_lut(char __iomem *addr,
 				struct mdp_ar_gc_lut_data *lut_data,
 				uint8_t num_stages);
-static void pp_update_argc_lut(u32 offset,
+static void pp_update_argc_lut(char __iomem *addr,
 				struct mdp_pgc_lut_data *config);
 static void pp_update_hist_lut(char __iomem *base,
 				struct mdp_hist_lut_data *cfg);
 static int pp_gm_has_invalid_lut_size(struct mdp_gamut_cfg_data *config);
 static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
-				u32 base, struct pp_sts_type *pp_sts);
-static void pp_pa_config(unsigned long flags, u32 base,
+			char __iomem *base, struct pp_sts_type *pp_sts);
+static void pp_pa_config(unsigned long flags, char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_pa_cfg *pa_config);
-static void pp_pcc_config(unsigned long flags, u32 base,
+static void pp_pa_v2_config(unsigned long flags, char __iomem *addr,
+				struct pp_sts_type *pp_sts,
+				struct mdp_pa_v2_data *pa_v2_config,
+				int mdp_location);
+static void pp_pcc_config(unsigned long flags, char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_pcc_cfg_data *pcc_config);
-static void pp_igc_config(unsigned long flags, u32 base,
+static void pp_igc_config(unsigned long flags, char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_igc_lut_data *igc_config,
 				u32 pipe_num);
-static void pp_enhist_config(unsigned long flags, char __iomem *base,
+static void pp_enhist_config(unsigned long flags, char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_hist_lut_data *enhist_cfg);
-static void pp_sharp_config(char __iomem *offset,
+static void pp_dither_config(char __iomem *addr,
+				struct pp_sts_type *pp_sts,
+				struct mdp_dither_cfg_data *dither_cfg);
+static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
+				int mdp_rev);
+static void pp_sharp_config(char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_sharp_cfg *sharp_config);
+static void pp_update_pa_v2_vig_opmode(struct pp_sts_type *pp_sts,
+				u32 *opmode);
+static int pp_copy_pa_six_zone_lut(struct mdp_pa_v2_cfg_data *pa_v2_config,
+				u32 disp_num);
+static void pp_update_pa_v2_global_adj_regs(char __iomem *addr,
+				struct mdp_pa_v2_data *pa_config);
+static void pp_update_pa_v2_mem_col(char __iomem *addr,
+				struct mdp_pa_v2_data *pa_v2_config);
+static void pp_update_pa_v2_mem_col_regs(char __iomem *addr,
+				struct mdp_pa_mem_col_cfg *cfg);
+static void pp_update_pa_v2_six_zone_regs(char __iomem *addr,
+				struct mdp_pa_v2_data *pa_v2_config);
+static void pp_update_pa_v2_sts(struct pp_sts_type *pp_sts,
+				struct mdp_pa_v2_data *pa_v2_config);
+static int pp_read_pa_v2_regs(char __iomem *addr,
+				struct mdp_pa_v2_data *pa_v2_config,
+				u32 disp_num);
+static void pp_read_pa_mem_col_regs(char __iomem *addr,
+				struct mdp_pa_mem_col_cfg *mem_col_cfg);
 static int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
 static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
 					struct mdss_ad_info **ad);
 static int pp_update_ad_input(struct msm_fb_data_type *mfd);
 static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
-static void pp_ad_cfg_write(struct mdss_ad_info *ad);
-static void pp_ad_init_write(struct mdss_ad_info *ad);
-static void pp_ad_input_write(struct mdss_ad_info *ad, u32 bl_lvl);
+static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw,
+						struct mdss_ad_info *ad);
+static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw,
+			struct mdss_ad_info *ad, struct mdss_mdp_ctl *ctl);
+static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
+						struct mdss_ad_info *ad);
+static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode);
+static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
+						struct mdss_ad_info *ad);
 static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd);
-static void pp_ad_cfg_lut(char __iomem *offset, u32 *data);
+static void pp_ad_cfg_lut(char __iomem *addr, u32 *data);
 
 static u32 last_sts, last_state;
 
@@ -331,7 +387,7 @@
 				   struct mdp_csc_cfg *data)
 {
 	int i, ret = 0;
-	char __iomem *base, *off;
+	char __iomem *base, *addr;
 	u32 val = 0;
 	struct mdss_data_type *mdata;
 	struct mdss_mdp_pipe *pipe;
@@ -374,33 +430,33 @@
 		return ret;
 	}
 
-	off = base + CSC_MV_OFF;
+	addr = base + CSC_MV_OFF;
 	for (i = 0; i < 9; i++) {
 		if (i & 0x1) {
 			val |= data->csc_mv[i] << 16;
-			writel_relaxed(val, off);
-			off += sizeof(u32 *);
+			writel_relaxed(val, addr);
+			addr += sizeof(u32 *);
 		} else {
 			val = data->csc_mv[i];
 		}
 	}
-	writel_relaxed(val, off); /* COEFF_33 */
+	writel_relaxed(val, addr); /* COEFF_33 */
 
-	off = base + CSC_BV_OFF;
+	addr = base + CSC_BV_OFF;
 	for (i = 0; i < 3; i++) {
-		writel_relaxed(data->csc_pre_bv[i], off);
-		writel_relaxed(data->csc_post_bv[i], off + CSC_POST_OFF);
-		off += sizeof(u32 *);
+		writel_relaxed(data->csc_pre_bv[i], addr);
+		writel_relaxed(data->csc_post_bv[i], addr + CSC_POST_OFF);
+		addr += sizeof(u32 *);
 	}
 
-	off = base + CSC_LV_OFF;
+	addr = base + CSC_LV_OFF;
 	for (i = 0; i < 6; i += 2) {
 		val = (data->csc_pre_lv[i] << 8) | data->csc_pre_lv[i+1];
-		writel_relaxed(val, off);
+		writel_relaxed(val, addr);
 
 		val = (data->csc_post_lv[i] << 8) | data->csc_post_lv[i+1];
-		writel_relaxed(val, off + CSC_POST_OFF);
-		off += sizeof(u32 *);
+		writel_relaxed(val, addr + CSC_POST_OFF);
+		addr += sizeof(u32 *);
 	}
 
 	return ret;
@@ -423,29 +479,29 @@
 }
 
 static void pp_gamut_config(struct mdp_gamut_cfg_data *gamut_cfg,
-				u32 base, struct pp_sts_type *pp_sts)
+				char __iomem *base, struct pp_sts_type *pp_sts)
 {
-	u32 offset;
+	char __iomem *addr;
 	int i, j;
 	if (gamut_cfg->flags & MDP_PP_OPS_WRITE) {
-		offset = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
+		addr = base + MDSS_MDP_REG_DSPP_GAMUT_BASE;
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
 			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
-				MDSS_MDP_REG_WRITE(offset,
-					(u32)gamut_cfg->r_tbl[i][j]);
-			offset += 4;
+				writel_relaxed((u32)gamut_cfg->r_tbl[i][j],
+						addr);
+			addr += 4;
 		}
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
 			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
-				MDSS_MDP_REG_WRITE(offset,
-					(u32)gamut_cfg->g_tbl[i][j]);
-			offset += 4;
+				writel_relaxed((u32)gamut_cfg->g_tbl[i][j],
+						addr);
+			addr += 4;
 		}
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
 			for (j = 0; j < gamut_cfg->tbl_size[i]; j++)
-				MDSS_MDP_REG_WRITE(offset,
-					(u32)gamut_cfg->b_tbl[i][j]);
-			offset += 4;
+				writel_relaxed((u32)gamut_cfg->b_tbl[i][j],
+						addr);
+			addr += 4;
 		}
 		if (gamut_cfg->gamut_first)
 			pp_sts->gamut_sts |= PP_STS_GAMUT_FIRST;
@@ -457,19 +513,19 @@
 		pp_sts->gamut_sts |= PP_STS_ENABLE;
 }
 
-static void pp_pa_config(unsigned long flags, u32 base,
+static void pp_pa_config(unsigned long flags, char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_pa_cfg *pa_config)
 {
 	if (flags & PP_FLAGS_DIRTY_PA) {
 		if (pa_config->flags & MDP_PP_OPS_WRITE) {
-			MDSS_MDP_REG_WRITE(base, pa_config->hue_adj);
-			base += 4;
-			MDSS_MDP_REG_WRITE(base, pa_config->sat_adj);
-			base += 4;
-			MDSS_MDP_REG_WRITE(base, pa_config->val_adj);
-			base += 4;
-			MDSS_MDP_REG_WRITE(base, pa_config->cont_adj);
+			writel_relaxed(pa_config->hue_adj, addr);
+			addr += 4;
+			writel_relaxed(pa_config->sat_adj, addr);
+			addr += 4;
+			writel_relaxed(pa_config->val_adj, addr);
+			addr += 4;
+			writel_relaxed(pa_config->cont_adj, addr);
 		}
 		if (pa_config->flags & MDP_PP_OPS_DISABLE)
 			pp_sts->pa_sts &= ~PP_STS_ENABLE;
@@ -478,13 +534,160 @@
 	}
 }
 
-static void pp_pcc_config(unsigned long flags, u32 base,
+static void pp_pa_v2_config(unsigned long flags, char __iomem *addr,
+				struct pp_sts_type *pp_sts,
+				struct mdp_pa_v2_data *pa_v2_config,
+				int mdp_location)
+{
+	if ((flags & PP_FLAGS_DIRTY_PA) &&
+			(pa_v2_config->flags & MDP_PP_OPS_WRITE)) {
+		pp_update_pa_v2_global_adj_regs(addr,
+				pa_v2_config);
+		/* Update PA DSPP Regs */
+		if (mdp_location == PP_DSPP) {
+			addr += 0x10;
+			pp_update_pa_v2_six_zone_regs(addr, pa_v2_config);
+			addr += 0xC;
+			pp_update_pa_v2_mem_col(addr, pa_v2_config);
+		} else if (mdp_location == PP_SSPP) { /* Update PA SSPP Regs */
+			addr -= MDSS_MDP_REG_VIG_PA_BASE;
+			addr += MDSS_MDP_REG_VIG_MEM_COL_BASE;
+			pp_update_pa_v2_mem_col(addr, pa_v2_config);
+		}
+		pp_update_pa_v2_sts(pp_sts, pa_v2_config);
+	}
+}
+
+static void pp_update_pa_v2_global_adj_regs(char __iomem *addr,
+				struct mdp_pa_v2_data *pa_v2_config)
+{
+	if (pa_v2_config->flags & MDP_PP_PA_HUE_ENABLE)
+		writel_relaxed(pa_v2_config->global_hue_adj, addr);
+	addr += 4;
+	if (pa_v2_config->flags & MDP_PP_PA_SAT_ENABLE)
+		/* Sat Global Adjust reg includes Sat Threshold */
+		writel_relaxed(pa_v2_config->global_sat_adj, addr);
+	addr += 4;
+	if (pa_v2_config->flags & MDP_PP_PA_VAL_ENABLE)
+		writel_relaxed(pa_v2_config->global_val_adj, addr);
+	addr += 4;
+	if (pa_v2_config->flags & MDP_PP_PA_CONT_ENABLE)
+		writel_relaxed(pa_v2_config->global_cont_adj, addr);
+}
+
+static void pp_update_pa_v2_mem_col(char __iomem *addr,
+				struct mdp_pa_v2_data *pa_v2_config)
+{
+	/* Update skin zone memory color registers */
+	if (pa_v2_config->flags & MDP_PP_PA_SKIN_ENABLE)
+		pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->skin_cfg);
+	addr += 0x14;
+	/* Update sky zone memory color registers */
+	if (pa_v2_config->flags & MDP_PP_PA_SKY_ENABLE)
+		pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->sky_cfg);
+	addr += 0x14;
+	/* Update foliage zone memory color registers */
+	if (pa_v2_config->flags & MDP_PP_PA_FOL_ENABLE)
+		pp_update_pa_v2_mem_col_regs(addr, &pa_v2_config->fol_cfg);
+}
+
+static void pp_update_pa_v2_mem_col_regs(char __iomem *addr,
+				struct mdp_pa_mem_col_cfg *cfg)
+{
+	pr_debug("ADDR: 0x%x, P0: 0x%x\n", (u32)addr, cfg->color_adjust_p0);
+	writel_relaxed(cfg->color_adjust_p0, addr);
+	addr += 4;
+	pr_debug("ADDR: 0x%x, P1: 0x%x\n", (u32)addr, cfg->color_adjust_p1);
+	writel_relaxed(cfg->color_adjust_p1, addr);
+	addr += 4;
+	pr_debug("ADDR: 0x%x, HUE REGION: 0x%x\n", (u32)addr, cfg->hue_region);
+	writel_relaxed(cfg->hue_region, addr);
+	addr += 4;
+	pr_debug("ADDR: 0x%x, SAT REGION: 0x%x\n", (u32)addr, cfg->sat_region);
+	writel_relaxed(cfg->sat_region, addr);
+	addr += 4;
+	pr_debug("ADDR: 0x%x, VAL REGION: 0x%x\n", (u32)addr, cfg->val_region);
+	writel_relaxed(cfg->val_region, addr);
+}
+
+static void pp_update_pa_v2_six_zone_regs(char __iomem *addr,
+				struct mdp_pa_v2_data *pa_v2_config)
+{
+	int i;
+	u32 data;
+	/* Update six zone memory color registers */
+	if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
+		addr += 4;
+		writel_relaxed(pa_v2_config->six_zone_curve_p1[0], addr);
+		addr -= 4;
+		/* Index Update to trigger auto-incrementing LUT accesses */
+		data = (1 << 26);
+		writel_relaxed((pa_v2_config->six_zone_curve_p0[0] & 0xFFF) |
+				data, addr);
+
+		/* Remove Index Update */
+		for (i = 1; i < SIX_ZONE_LUT_ENTRIES; i++) {
+			addr += 4;
+			writel_relaxed(pa_v2_config->six_zone_curve_p1[i],
+					addr);
+			addr -= 4;
+			writel_relaxed(pa_v2_config->six_zone_curve_p0[i] &
+					0xFFF, addr);
+		}
+		addr += 8;
+		writel_relaxed(pa_v2_config->six_zone_thresh, addr);
+	}
+}
+
+static void pp_update_pa_v2_sts(struct pp_sts_type *pp_sts,
+				struct mdp_pa_v2_data *pa_v2_config)
+{
+	pp_sts->pa_sts = 0;
+	/* PA STS update */
+	if (pa_v2_config->flags & MDP_PP_OPS_ENABLE)
+		pp_sts->pa_sts |= PP_STS_ENABLE;
+	else
+		pp_sts->pa_sts &= ~PP_STS_ENABLE;
+
+	/* Global HSV STS update */
+	if (pa_v2_config->flags & MDP_PP_PA_HUE_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_HUE_MASK;
+	if (pa_v2_config->flags & MDP_PP_PA_SAT_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_SAT_MASK;
+	if (pa_v2_config->flags & MDP_PP_PA_VAL_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_VAL_MASK;
+	if (pa_v2_config->flags & MDP_PP_PA_CONT_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_CONT_MASK;
+	if (pa_v2_config->flags & MDP_PP_PA_MEM_PROTECT_EN)
+		pp_sts->pa_sts |= PP_STS_PA_MEM_PROTECT_EN;
+	if (pa_v2_config->flags & MDP_PP_PA_SAT_ZERO_EXP_EN)
+		pp_sts->pa_sts |= PP_STS_PA_SAT_ZERO_EXP_EN;
+
+	/* Memory Color STS update */
+	if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_SKIN_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_MEM_COL_SKIN_MASK;
+	if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_SKY_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_MEM_COL_SKY_MASK;
+	if (pa_v2_config->flags & MDP_PP_PA_MEM_COL_FOL_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_MEM_COL_FOL_MASK;
+
+	/* Six Zone STS update */
+	if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_HUE_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_HUE_MASK;
+	if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_SAT_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_SAT_MASK;
+	if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_VAL_MASK)
+		pp_sts->pa_sts |= PP_STS_PA_SIX_ZONE_VAL_MASK;
+
+}
+
+static void pp_pcc_config(unsigned long flags, char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_pcc_cfg_data *pcc_config)
 {
 	if (flags & PP_FLAGS_DIRTY_PCC) {
 		if (pcc_config->ops & MDP_PP_OPS_WRITE)
-			pp_update_pcc_regs(base, pcc_config);
+			pp_update_pcc_regs(addr, pcc_config);
 
 		if (pcc_config->ops & MDP_PP_OPS_DISABLE)
 			pp_sts->pcc_sts &= ~PP_STS_ENABLE;
@@ -493,7 +696,7 @@
 	}
 }
 
-static void pp_igc_config(unsigned long flags, u32 base,
+static void pp_igc_config(unsigned long flags, char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_igc_lut_data *igc_config,
 				u32 pipe_num)
@@ -501,7 +704,7 @@
 	u32 tbl_idx;
 	if (flags & PP_FLAGS_DIRTY_IGC) {
 		if (igc_config->ops & MDP_PP_OPS_WRITE)
-			pp_update_igc_lut(igc_config, base, pipe_num);
+			pp_update_igc_lut(igc_config, addr, pipe_num);
 
 		if (igc_config->ops & MDP_PP_IGC_FLAG_ROM0) {
 			pp_sts->pcc_sts |= PP_STS_ENABLE;
@@ -520,13 +723,13 @@
 	}
 }
 
-static void pp_enhist_config(unsigned long flags, char __iomem *base,
+static void pp_enhist_config(unsigned long flags, char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_hist_lut_data *enhist_cfg)
 {
 	if (flags & PP_FLAGS_DIRTY_ENHIST) {
 		if (enhist_cfg->ops & MDP_PP_OPS_WRITE)
-			pp_update_hist_lut(base, enhist_cfg);
+			pp_update_hist_lut(addr, enhist_cfg);
 
 		if (enhist_cfg->ops & MDP_PP_OPS_DISABLE)
 			pp_sts->enhist_sts &= ~PP_STS_ENABLE;
@@ -536,18 +739,18 @@
 }
 
 /*the below function doesn't do error checking on the input params*/
-static void pp_sharp_config(char __iomem *base,
+static void pp_sharp_config(char __iomem *addr,
 				struct pp_sts_type *pp_sts,
 				struct mdp_sharp_cfg *sharp_config)
 {
 	if (sharp_config->flags & MDP_PP_OPS_WRITE) {
-		writel_relaxed(sharp_config->strength, base);
-		base += 4;
-		writel_relaxed(sharp_config->edge_thr, base);
-		base += 4;
-		writel_relaxed(sharp_config->smooth_thr, base);
-		base += 4;
-		writel_relaxed(sharp_config->noise_thr, base);
+		writel_relaxed(sharp_config->strength, addr);
+		addr += 4;
+		writel_relaxed(sharp_config->edge_thr, addr);
+		addr += 4;
+		writel_relaxed(sharp_config->smooth_thr, addr);
+		addr += 4;
+		writel_relaxed(sharp_config->noise_thr, addr);
 	}
 	if (sharp_config->flags & MDP_PP_OPS_DISABLE)
 		pp_sts->sharp_sts &= ~PP_STS_ENABLE;
@@ -558,12 +761,14 @@
 
 static int pp_vig_pipe_setup(struct mdss_mdp_pipe *pipe, u32 *op)
 {
-	u32 opmode = 0, base = 0;
+	u32 opmode = 0;
 	unsigned long flags = 0;
 	char __iomem *offset;
+	struct mdss_data_type *mdata;
 
 	pr_debug("pnum=%x\n", pipe->num);
 
+	mdata = mdss_mdp_get_mdata();
 	if ((pipe->flags & MDP_OVERLAY_PP_CFG_EN) &&
 		(pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_CSC_CFG)) {
 			opmode |= !!(pipe->pp_cfg.csc_cfg.flags &
@@ -597,15 +802,30 @@
 	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) {
+		if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_CFG) &&
+				(mdata->mdp_rev < MDSS_MDP_HW_REV_103)) {
 			flags = PP_FLAGS_DIRTY_PA;
-			base = MDSS_MDP_REG_SSPP_OFFSET(pipe->num) +
-				MDSS_MDP_REG_VIG_PA_BASE;
-			pp_pa_config(flags, base, &pipe->pp_res.pp_sts,
-					&pipe->pp_cfg.pa_cfg);
+			pp_pa_config(flags,
+				pipe->base + MDSS_MDP_REG_VIG_PA_BASE,
+				&pipe->pp_res.pp_sts,
+				&pipe->pp_cfg.pa_cfg);
 
 			if (pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)
-				opmode |= (1 << 4); /* PA_EN */
+				opmode |= MDSS_MDP_VIG_OP_PA_EN;
+		}
+		if ((pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_PA_V2_CFG) &&
+			(mdata->mdp_rev >= MDSS_MDP_HW_REV_103)) {
+			flags = PP_FLAGS_DIRTY_PA;
+			pp_pa_v2_config(flags,
+				pipe->base + MDSS_MDP_REG_VIG_PA_BASE,
+				&pipe->pp_res.pp_sts,
+				&pipe->pp_cfg.pa_v2_cfg,
+				PP_SSPP);
+			pp_update_pa_v2_vig_opmode(&pipe->pp_res.pp_sts,
+						&opmode);
+
+			if (pipe->pp_res.pp_sts.pa_sts & PP_STS_ENABLE)
+				opmode |= MDSS_MDP_VIG_OP_PA_EN;
 		}
 
 		if (pipe->pp_cfg.config_ops & MDP_OVERLAY_PP_HIST_LUT_CFG) {
@@ -634,6 +854,29 @@
 	return 0;
 }
 
+static void pp_update_pa_v2_vig_opmode(struct pp_sts_type *pp_sts,
+				u32 *opmode)
+{
+	if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
+		*opmode |= MDSS_MDP_VIG_OP_PA_HUE_MASK;
+	if (pp_sts->pa_sts & PP_STS_PA_SAT_MASK)
+		*opmode |= MDSS_MDP_VIG_OP_PA_SAT_MASK;
+	if (pp_sts->pa_sts & PP_STS_PA_VAL_MASK)
+		*opmode |= MDSS_MDP_VIG_OP_PA_VAL_MASK;
+	if (pp_sts->pa_sts & PP_STS_PA_CONT_MASK)
+		*opmode |= MDSS_MDP_VIG_OP_PA_CONT_MASK;
+	if (pp_sts->pa_sts & PP_STS_PA_MEM_PROTECT_EN)
+		*opmode |= MDSS_MDP_VIG_OP_PA_MEM_PROTECT_EN;
+	if (pp_sts->pa_sts & PP_STS_PA_SAT_ZERO_EXP_EN)
+		*opmode |= MDSS_MDP_VIG_OP_PA_SAT_ZERO_EXP_EN;
+	if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKIN_MASK)
+		*opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_SKIN_MASK;
+	if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKY_MASK)
+		*opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_SKY_MASK;
+	if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_FOL_MASK)
+		*opmode |= MDSS_MDP_VIG_OP_PA_MEM_COL_FOL_MASK;
+}
+
 static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
 {
 	u32 scale_config = 0;
@@ -880,8 +1123,9 @@
 {
 	int ret = 0;
 	unsigned long flags = 0;
-	u32 pipe_base;
+	char __iomem *pipe_base;
 	u32 pipe_num;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
 	if (pipe == NULL)
 		return -EINVAL;
@@ -893,15 +1137,15 @@
 	 */
 	switch (pipe->type) {
 	case MDSS_MDP_PIPE_TYPE_VIG:
-		pipe_base = MDSS_MDP_REG_IGC_VIG_BASE;
+		pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_VIG_BASE;
 		pipe_num = pipe->num - MDSS_MDP_SSPP_VIG0;
 		break;
 	case MDSS_MDP_PIPE_TYPE_RGB:
-		pipe_base = MDSS_MDP_REG_IGC_RGB_BASE;
+		pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_RGB_BASE;
 		pipe_num = pipe->num - MDSS_MDP_SSPP_RGB0;
 		break;
 	case MDSS_MDP_PIPE_TYPE_DMA:
-		pipe_base = MDSS_MDP_REG_IGC_DMA_BASE;
+		pipe_base = mdata->mdp_base + MDSS_MDP_REG_IGC_DMA_BASE;
 		pipe_num = pipe->num - MDSS_MDP_SSPP_DMA0;
 		break;
 	default:
@@ -923,10 +1167,11 @@
 static int pp_mixer_setup(u32 disp_num,
 		struct mdss_mdp_mixer *mixer)
 {
-	u32 flags, offset, dspp_num, opmode = 0;
+	u32 flags, dspp_num, opmode = 0;
 	struct mdp_pgc_lut_data *pgc_config;
 	struct pp_sts_type *pp_sts;
 	struct mdss_mdp_ctl *ctl;
+	char __iomem *addr;
 	dspp_num = mixer->num;
 
 	if (!mixer || !mixer->ctl)
@@ -947,9 +1192,9 @@
 	if (flags & PP_FLAGS_DIRTY_ARGC) {
 		pgc_config = &mdss_pp_res->argc_disp_cfg[disp_num];
 		if (pgc_config->flags & MDP_PP_OPS_WRITE) {
-			offset = MDSS_MDP_REG_LM_OFFSET(disp_num) +
+			addr = mixer->base +
 				MDSS_MDP_REG_LM_GC_LUT_BASE;
-			pp_update_argc_lut(offset, pgc_config);
+			pp_update_argc_lut(addr, pgc_config);
 		}
 		if (pgc_config->flags & MDP_PP_OPS_DISABLE)
 			pp_sts->argc_sts &= ~PP_STS_ENABLE;
@@ -960,15 +1205,28 @@
 	/* update LM opmode if LM needs flush */
 	if ((pp_sts->argc_sts & PP_STS_ENABLE) &&
 		(ctl->flush_bits & (BIT(6) << dspp_num))) {
-		offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
-			MDSS_MDP_REG_LM_OP_MODE;
-		opmode = MDSS_MDP_REG_READ(offset);
+		addr = mixer->base + MDSS_MDP_REG_LM_OP_MODE;
+		opmode = readl_relaxed(addr);
 		opmode |= (1 << 0); /* GC_LUT_EN */
-		MDSS_MDP_REG_WRITE(offset, opmode);
+		writel_relaxed(opmode, addr);
 	}
 	return 0;
 }
 
+static char __iomem *mdss_mdp_get_mixer_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->base;
+}
+
 static char __iomem *mdss_mdp_get_dspp_addr_off(u32 dspp_num)
 {
 	struct mdss_data_type *mdata;
@@ -1040,16 +1298,97 @@
 	return ret;
 }
 
+static void pp_dither_config(char __iomem *addr,
+			struct pp_sts_type *pp_sts,
+			struct mdp_dither_cfg_data *dither_cfg)
+{
+	u32 data;
+	int i;
+
+	if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
+		data = dither_depth_map[dither_cfg->g_y_depth];
+		data |= dither_depth_map[dither_cfg->b_cb_depth] << 2;
+		data |= dither_depth_map[dither_cfg->r_cr_depth] << 4;
+		writel_relaxed(data, addr);
+		addr += 0x14;
+		for (i = 0; i < 16; i += 4) {
+			data = dither_matrix[i] |
+				(dither_matrix[i + 1] << 4) |
+				(dither_matrix[i + 2] << 8) |
+				(dither_matrix[i + 3] << 12);
+			writel_relaxed(data, addr);
+			addr += 4;
+		}
+	}
+	if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
+		pp_sts->dither_sts &= ~PP_STS_ENABLE;
+	else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
+		pp_sts->dither_sts |= PP_STS_ENABLE;
+}
+
+static void pp_dspp_opmode_config(struct pp_sts_type *pp_sts, u32 *opmode,
+			int mdp_rev)
+{
+	if (pp_sts->pa_sts & PP_STS_ENABLE)
+		*opmode |= MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
+	if (mdp_rev >= MDSS_MDP_HW_REV_103) {
+		if (pp_sts->pa_sts & PP_STS_PA_HUE_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_HUE_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_SAT_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_SAT_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_VAL_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_VAL_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_CONT_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_CONT_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_MEM_PROTECT_EN)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_MEM_PROTECT_EN;
+		if (pp_sts->pa_sts & PP_STS_PA_SAT_ZERO_EXP_EN)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_SAT_ZERO_EXP_EN;
+		if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKIN_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_SKIN_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_FOL_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_FOL_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_MEM_COL_SKY_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_MEM_COL_SKY_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_HUE_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_HUE_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_SAT_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_SAT_MASK;
+		if (pp_sts->pa_sts & PP_STS_PA_SIX_ZONE_VAL_MASK)
+			*opmode |= MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK;
+	}
+	if (pp_sts->pcc_sts & PP_STS_ENABLE)
+		*opmode |= MDSS_MDP_DSPP_OP_PCC_EN; /* PCC_EN */
+
+	if (pp_sts->igc_sts & PP_STS_ENABLE) {
+		*opmode |= MDSS_MDP_DSPP_OP_IGC_LUT_EN | /* IGC_LUT_EN */
+			      (pp_sts->igc_tbl_idx << 1);
+	}
+	if (pp_sts->enhist_sts & PP_STS_ENABLE) {
+		*opmode |= MDSS_MDP_DSPP_OP_HIST_LUTV_EN | /* HIST_LUT_EN */
+				  MDSS_MDP_DSPP_OP_PA_EN; /* PA_EN */
+	}
+	if (pp_sts->dither_sts & PP_STS_ENABLE)
+		*opmode |= MDSS_MDP_DSPP_OP_DST_DITHER_EN; /* DITHER_EN */
+	if (pp_sts->gamut_sts & PP_STS_ENABLE) {
+		*opmode |= MDSS_MDP_DSPP_OP_GAMUT_EN; /* GAMUT_EN */
+		if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
+			*opmode |= MDSS_MDP_DSPP_OP_GAMUT_PCC_ORDER;
+	}
+	if (pp_sts->pgc_sts & PP_STS_ENABLE)
+		*opmode |= MDSS_MDP_DSPP_OP_ARGC_LUT_EN;
+}
+
 static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
 {
-	u32 flags, base, offset, dspp_num, opmode = 0;
-	struct mdp_dither_cfg_data *dither_cfg;
+	u32 ad_flags, flags, dspp_num, opmode = 0, ad_bypass;
 	struct mdp_pgc_lut_data *pgc_config;
 	struct pp_sts_type *pp_sts;
-	u32 data;
-	char __iomem *basel;
-	int i, ret = 0;
+	char __iomem *base, *addr;
+	int ret = 0;
 	struct mdss_data_type *mdata;
+	struct mdss_ad_info *ad = NULL;
+	struct mdss_mdp_ad *ad_hw = NULL;
 	struct mdss_mdp_ctl *ctl;
 	u32 mixer_cnt;
 	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -1063,8 +1402,7 @@
 	if ((mixer->type != MDSS_MDP_MIXER_TYPE_INTF) ||
 		(dspp_num >= MDSS_MDP_MAX_DSPP))
 		return -EINVAL;
-	base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num);
-	basel = mdss_mdp_get_dspp_addr_off(dspp_num);
+	base = mdss_mdp_get_dspp_addr_off(dspp_num);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
@@ -1078,107 +1416,90 @@
 		flags = 0;
 
 	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
-	if (dspp_num < mdata->nad_cfgs && (mixer_cnt != 2)) {
-		ret = mdss_mdp_ad_setup(ctl->mfd);
-		if (ret < 0)
-			pr_warn("ad_setup(dspp%d) returns %d", dspp_num, ret);
+	if (dspp_num < mdata->nad_cfgs && disp_num < mdata->nad_cfgs &&
+				(mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
+		ad = &mdata->ad_cfgs[disp_num];
+		ad_flags = ad->reg_sts;
+		ad_hw = &mdata->ad_off[dspp_num];
+	} else {
+		ad_flags = 0;
 	}
+
 	/* call calibration specific processing here */
 	if (ctl->mfd->calib_mode)
 		goto flush_exit;
 
 	/* nothing to update */
-	if ((!flags) && (!(opmode)) && (ret <= 0))
+	if ((!flags) && (!(opmode)) && (!ad_flags))
 		goto dspp_exit;
-	ret = 0;
 
 	pp_sts = &mdss_pp_res->pp_disp_sts[disp_num];
 
-	pp_pa_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
-					&mdss_pp_res->pa_disp_cfg[disp_num]);
+	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
+		pp_pa_v2_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
+				&mdss_pp_res->pa_v2_disp_cfg[disp_num],
+				PP_DSPP);
+	} else
+		pp_pa_config(flags, base + MDSS_MDP_REG_DSPP_PA_BASE, pp_sts,
+				&mdss_pp_res->pa_disp_cfg[disp_num]);
 
 	pp_pcc_config(flags, base + MDSS_MDP_REG_DSPP_PCC_BASE, pp_sts,
 					&mdss_pp_res->pcc_disp_cfg[disp_num]);
 
-	pp_igc_config(flags, MDSS_MDP_REG_IGC_DSPP_BASE, pp_sts,
-				&mdss_pp_res->igc_disp_cfg[disp_num], dspp_num);
+	pp_igc_config(flags, mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE,
+				pp_sts, &mdss_pp_res->igc_disp_cfg[disp_num],
+				dspp_num);
 
-	pp_enhist_config(flags, basel + MDSS_MDP_REG_DSPP_HIST_LUT_BASE,
+	pp_enhist_config(flags, base + 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)
-		opmode |= (1 << 20); /* PA_EN */
-
-	if (pp_sts->pcc_sts & PP_STS_ENABLE)
-		opmode |= (1 << 4); /* PCC_EN */
-
-	if (pp_sts->igc_sts & PP_STS_ENABLE) {
-		opmode |= (1 << 0) | /* IGC_LUT_EN */
-			      (pp_sts->igc_tbl_idx << 1);
-	}
-
-	if (pp_sts->enhist_sts & PP_STS_ENABLE) {
-		opmode |= (1 << 19) | /* HIST_LUT_EN */
-				  (1 << 20); /* PA_EN */
-		if (!(pp_sts->pa_sts & PP_STS_ENABLE)) {
-			/* Program default value */
-			offset = base + MDSS_MDP_REG_DSPP_PA_BASE;
-			MDSS_MDP_REG_WRITE(offset, 0);
-			MDSS_MDP_REG_WRITE(offset + 4, 0);
-			MDSS_MDP_REG_WRITE(offset + 8, 0);
-			MDSS_MDP_REG_WRITE(offset + 12, 0);
-		}
+	if (pp_sts->enhist_sts & PP_STS_ENABLE &&
+			!(pp_sts->pa_sts & PP_STS_ENABLE)) {
+		/* Program default value */
+		addr = base + MDSS_MDP_REG_DSPP_PA_BASE;
+		writel_relaxed(0, addr);
+		writel_relaxed(0, addr + 4);
+		writel_relaxed(0, addr + 8);
+		writel_relaxed(0, addr + 12);
 	}
 	if (flags & PP_FLAGS_DIRTY_DITHER) {
-		dither_cfg = &mdss_pp_res->dither_disp_cfg[disp_num];
-		if (dither_cfg->flags & MDP_PP_OPS_WRITE) {
-			offset = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
-			MDSS_MDP_REG_WRITE(offset,
-			  dither_depth_map[dither_cfg->g_y_depth] |
-			  (dither_depth_map[dither_cfg->b_cb_depth] << 2) |
-			  (dither_depth_map[dither_cfg->r_cr_depth] << 4));
-			offset += 0x14;
-			for (i = 0; i << 16; i += 4) {
-				data = dither_matrix[i] |
-					(dither_matrix[i + 1] << 4) |
-					(dither_matrix[i + 2] << 8) |
-					(dither_matrix[i + 3] << 12);
-				MDSS_MDP_REG_WRITE(offset, data);
-				offset += 4;
-			}
-		}
-		if (dither_cfg->flags & MDP_PP_OPS_DISABLE)
-			pp_sts->dither_sts &= ~PP_STS_ENABLE;
-		else if (dither_cfg->flags & MDP_PP_OPS_ENABLE)
-			pp_sts->dither_sts |= PP_STS_ENABLE;
+		addr = base + MDSS_MDP_REG_DSPP_DITHER_DEPTH;
+		pp_dither_config(addr, pp_sts,
+				&mdss_pp_res->dither_disp_cfg[disp_num]);
 	}
-	if (pp_sts->dither_sts & PP_STS_ENABLE)
-		opmode |= (1 << 8); /* DITHER_EN */
 	if (flags & PP_FLAGS_DIRTY_GAMUT)
 		pp_gamut_config(&mdss_pp_res->gamut_disp_cfg[disp_num], base,
 				pp_sts);
-	if (pp_sts->gamut_sts & PP_STS_ENABLE) {
-		opmode |= (1 << 23); /* GAMUT_EN */
-		if (pp_sts->gamut_sts & PP_STS_GAMUT_FIRST)
-			opmode |= (1 << 24); /* GAMUT_ORDER */
-	}
 
 	if (flags & PP_FLAGS_DIRTY_PGC) {
 		pgc_config = &mdss_pp_res->pgc_disp_cfg[disp_num];
 		if (pgc_config->flags & MDP_PP_OPS_WRITE) {
-			offset = base + MDSS_MDP_REG_DSPP_GC_BASE;
-			pp_update_argc_lut(offset, pgc_config);
+			addr = base + MDSS_MDP_REG_DSPP_GC_BASE;
+			pp_update_argc_lut(addr, pgc_config);
 		}
 		if (pgc_config->flags & MDP_PP_OPS_DISABLE)
 			pp_sts->pgc_sts &= ~PP_STS_ENABLE;
 		else if (pgc_config->flags & MDP_PP_OPS_ENABLE)
 			pp_sts->pgc_sts |= PP_STS_ENABLE;
 	}
-	if (pp_sts->pgc_sts & PP_STS_ENABLE)
-		opmode |= (1 << 22);
 
+	if (ad_hw) {
+		mutex_lock(&ad->lock);
+		ad_flags = ad->reg_sts;
+		if (ad_flags & PP_AD_STS_DIRTY_DATA)
+			pp_ad_input_write(ad_hw, ad);
+		if (ad_flags & PP_AD_STS_DIRTY_INIT)
+			pp_ad_init_write(ad_hw, ad, ctl);
+		if (ad_flags & PP_AD_STS_DIRTY_CFG)
+			pp_ad_cfg_write(ad_hw, ad);
+		pp_ad_bypass_config(ad, &ad_bypass);
+		writel_relaxed(ad_bypass, ad_hw->base);
+		mutex_unlock(&ad->lock);
+	}
+
+	pp_dspp_opmode_config(pp_sts, &opmode, mdata->mdp_rev);
 flush_exit:
-	writel_relaxed(opmode, basel + MDSS_MDP_REG_DSPP_OP_MODE);
+	writel_relaxed(opmode, base + MDSS_MDP_REG_DSPP_OP_MODE);
 	ctl->flush_bits |= BIT(13 + dspp_num);
 	wmb();
 dspp_exit:
@@ -1209,13 +1530,37 @@
 /* call only when holding and mfd->lock */
 int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl)
 {
+	struct mdss_data_type *mdata = ctl->mdata;
+	int ret = 0;
+	u32 mixer_cnt;
+	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
 	u32 disp_num;
+	int i;
+	bool valid_mixers = true;
 	if ((!ctl->mfd) || (!mdss_pp_res))
 		return -EINVAL;
 
 	/* treat fb_num the same as block logical id*/
 	disp_num = ctl->mfd->index;
 
+	mixer_cnt = mdss_mdp_get_ctl_mixers(disp_num, mixer_id);
+	if (!mixer_cnt) {
+		valid_mixers = false;
+		ret = -EINVAL;
+		pr_warn("Configuring post processing without mixers, err = %d",
+									ret);
+		goto exit;
+	}
+	for (i = 0; i < mixer_cnt && valid_mixers; i++) {
+		if (mixer_id[i] > mdata->nad_cfgs)
+			valid_mixers = false;
+	}
+	if (valid_mixers && (mixer_cnt <= mdata->nmax_concurrent_ad_hw)) {
+		ret = mdss_mdp_ad_setup(ctl->mfd);
+		if (ret < 0)
+			pr_warn("ad_setup(disp%d) returns %d", disp_num, ret);
+	}
+
 	mutex_lock(&mdss_pp_mutex);
 	if (ctl->mixer_left) {
 		pp_mixer_setup(disp_num, ctl->mixer_left);
@@ -1226,11 +1571,14 @@
 		pp_dspp_setup(disp_num, ctl->mixer_right);
 	}
 	/* clear dirty flag */
-	if (disp_num < MDSS_BLOCK_DISP_NUM)
+	if (disp_num < MDSS_BLOCK_DISP_NUM) {
 		mdss_pp_res->pp_disp_flags[disp_num] = 0;
+		if (disp_num < mdata->nad_cfgs)
+			mdata->ad_cfgs[disp_num].reg_sts = 0;
+	}
 	mutex_unlock(&mdss_pp_mutex);
-
-	return 0;
+exit:
+	return ret;
 }
 
 /*
@@ -1253,17 +1601,19 @@
 		ad = &mdata->ad_cfgs[dspp_num];
 
 		if (PP_AD_STATE_CFG & ad->state)
-			pp_ad_cfg_write(ad);
+			pp_ad_cfg_write(&mdata->ad_off[dspp_num], ad);
 		if (PP_AD_STATE_INIT & ad->state)
-			pp_ad_init_write(ad);
-		if ((PP_AD_STATE_DATA & ad->state) && (ad->sts & PP_STS_ENABLE)) {
+			pp_ad_init_write(&mdata->ad_off[dspp_num], ad, ctl);
+		if ((PP_AD_STATE_DATA & ad->state) &&
+			(ad->sts & PP_STS_ENABLE)) {
 			bl = ad->bl_mfd->bl_level;
 			ad->last_bl = bl;
 			if (ad->state & PP_AD_STATE_BL_LIN) {
 				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
 				bl = bl << ad->bl_bright_shift;
 			}
-			pp_ad_input_write(ad, bl);
+			ad->bl_data = bl;
+			pp_ad_input_write(&mdata->ad_off[dspp_num], ad);
 		}
 		if ((PP_AD_STATE_VSYNC & ad->state) && ad->calc_itr)
 			ctl->add_vsync_handler(ctl, &ad->handle);
@@ -1273,10 +1623,17 @@
 
 	if (pp_sts.pa_sts & PP_STS_ENABLE) {
 		flags |= PP_FLAGS_DIRTY_PA;
-		if (!(mdss_pp_res->pa_disp_cfg[disp_num].flags
-					& MDP_PP_OPS_DISABLE))
-			mdss_pp_res->pa_disp_cfg[disp_num].flags |=
-				MDP_PP_OPS_WRITE;
+		if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
+			if (!(mdss_pp_res->pa_v2_disp_cfg[disp_num].flags
+						& MDP_PP_OPS_DISABLE))
+				mdss_pp_res->pa_v2_disp_cfg[disp_num].flags |=
+					MDP_PP_OPS_WRITE;
+		} else {
+			if (!(mdss_pp_res->pa_disp_cfg[disp_num].flags
+						& MDP_PP_OPS_DISABLE))
+				mdss_pp_res->pa_disp_cfg[disp_num].flags |=
+					MDP_PP_OPS_WRITE;
+		}
 	}
 	if (pp_sts.pcc_sts & PP_STS_ENABLE) {
 		flags |= PP_FLAGS_DIRTY_PCC;
@@ -1419,10 +1776,15 @@
 			u32 *copyback)
 {
 	int ret = 0;
-	u32 pa_offset, disp_num, dspp_num = 0;
+	u32 disp_num, dspp_num = 0;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+	char __iomem *pa_addr;
+
+	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103)
+		return -EINVAL;
 
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
-		(config->block >= MDP_BLOCK_MAX))
+			(config->block >= MDP_BLOCK_MAX))
 		return -EINVAL;
 
 	mutex_lock(&mdss_pp_mutex);
@@ -1431,20 +1793,20 @@
 	if (config->pa_data.flags & MDP_PP_OPS_READ) {
 		ret = pp_get_dspp_num(disp_num, &dspp_num);
 		if (ret) {
-			pr_err("%s, no dspp connects to disp %d",
-				__func__, disp_num);
+			pr_err("no dspp connects to disp %d",
+					disp_num);
 			goto pa_config_exit;
 		}
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-		pa_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
-			  MDSS_MDP_REG_DSPP_PA_BASE;
-		config->pa_data.hue_adj = MDSS_MDP_REG_READ(pa_offset);
-		pa_offset += 4;
-		config->pa_data.sat_adj = MDSS_MDP_REG_READ(pa_offset);
-		pa_offset += 4;
-		config->pa_data.val_adj = MDSS_MDP_REG_READ(pa_offset);
-		pa_offset += 4;
-		config->pa_data.cont_adj = MDSS_MDP_REG_READ(pa_offset);
+		pa_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
+			MDSS_MDP_REG_DSPP_PA_BASE;
+		config->pa_data.hue_adj = readl_relaxed(pa_addr);
+		pa_addr += 4;
+		config->pa_data.sat_adj = readl_relaxed(pa_addr);
+		pa_addr += 4;
+		config->pa_data.val_adj = readl_relaxed(pa_addr);
+		pa_addr += 4;
+		config->pa_data.cont_adj = readl_relaxed(pa_addr);
 		*copyback = 1;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	} else {
@@ -1457,137 +1819,299 @@
 	return ret;
 }
 
-static void pp_read_pcc_regs(u32 offset,
-				struct mdp_pcc_cfg_data *cfg_ptr)
+int mdss_mdp_pa_v2_config(struct mdp_pa_v2_cfg_data *config,
+			u32 *copyback)
 {
-	cfg_ptr->r.c = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.c = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.c = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
+	int ret = 0;
+	u32 disp_num, dspp_num = 0;
+	char __iomem *pa_addr;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
-	cfg_ptr->r.r = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.r = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.r = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
+	if (mdata->mdp_rev < MDSS_MDP_HW_REV_103)
+		return -EINVAL;
 
-	cfg_ptr->r.g = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.g = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.g = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
+	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
+		(config->block >= MDP_BLOCK_MAX))
+		return -EINVAL;
 
-	cfg_ptr->r.b = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.b = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.b = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
+	mutex_lock(&mdss_pp_mutex);
+	disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
 
-	cfg_ptr->r.rr = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.rr = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.rr = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
+	if (config->pa_v2_data.flags & MDP_PP_OPS_READ) {
+		ret = pp_get_dspp_num(disp_num, &dspp_num);
+		if (ret) {
+			pr_err("no dspp connects to disp %d",
+				disp_num);
+			goto pa_config_exit;
+		}
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		pa_addr = mdss_mdp_get_dspp_addr_off(dspp_num);
+		if (IS_ERR(pa_addr)) {
+			ret = PTR_ERR(pa_addr);
+			goto pa_config_exit;
+		} else
+			pa_addr += MDSS_MDP_REG_DSPP_PA_BASE;
+		ret = pp_read_pa_v2_regs(pa_addr,
+				&config->pa_v2_data,
+				disp_num);
+		if (ret)
+			goto pa_config_exit;
+		*copyback = 1;
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	} else {
+		if (config->pa_v2_data.flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
+			ret = pp_copy_pa_six_zone_lut(config, disp_num);
+			if (ret)
+				goto pa_config_exit;
+		}
+		mdss_pp_res->pa_v2_disp_cfg[disp_num] =
+			config->pa_v2_data;
+		mdss_pp_res->pa_v2_disp_cfg[disp_num].six_zone_curve_p0 =
+			&mdss_pp_res->six_zone_lut_curve_p0[disp_num][0];
+		mdss_pp_res->pa_v2_disp_cfg[disp_num].six_zone_curve_p1 =
+			&mdss_pp_res->six_zone_lut_curve_p1[disp_num][0];
+		mdss_pp_res->pp_disp_flags[disp_num] |= PP_FLAGS_DIRTY_PA;
+	}
 
-	cfg_ptr->r.rg = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.rg = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.rg = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
-
-	cfg_ptr->r.rb = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.rb = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.rb = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
-
-	cfg_ptr->r.gg = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.gg = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.gg = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
-
-	cfg_ptr->r.gb = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.gb = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.gb = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
-
-	cfg_ptr->r.bb = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.bb = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.bb = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
-
-	cfg_ptr->r.rgb_0 = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.rgb_0 = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.rgb_0 = MDSS_MDP_REG_READ(offset + 8);
-	offset += 0x10;
-
-	cfg_ptr->r.rgb_1 = MDSS_MDP_REG_READ(offset);
-	cfg_ptr->g.rgb_1 = MDSS_MDP_REG_READ(offset + 4);
-	cfg_ptr->b.rgb_1 = MDSS_MDP_REG_READ(offset + 8);
+pa_config_exit:
+	mutex_unlock(&mdss_pp_mutex);
+	return ret;
 }
 
-static void pp_update_pcc_regs(u32 offset,
+
+static int pp_read_pa_v2_regs(char __iomem *addr,
+				struct mdp_pa_v2_data *pa_v2_config,
+				u32 disp_num)
+{
+	int i;
+	u32 data;
+
+	if (pa_v2_config->flags & MDP_PP_PA_HUE_ENABLE)
+		pa_v2_config->global_hue_adj = readl_relaxed(addr);
+	addr += 4;
+	if (pa_v2_config->flags & MDP_PP_PA_SAT_ENABLE)
+		pa_v2_config->global_sat_adj = readl_relaxed(addr);
+	addr += 4;
+	if (pa_v2_config->flags & MDP_PP_PA_VAL_ENABLE)
+		pa_v2_config->global_val_adj = readl_relaxed(addr);
+	addr += 4;
+	if (pa_v2_config->flags & MDP_PP_PA_CONT_ENABLE)
+		pa_v2_config->global_cont_adj = readl_relaxed(addr);
+	addr += 4;
+
+	/* Six zone LUT and thresh data */
+	if (pa_v2_config->flags & MDP_PP_PA_SIX_ZONE_ENABLE) {
+		data = (3 << 25);
+		writel_relaxed(data, addr);
+
+		for (i = 0; i < SIX_ZONE_LUT_ENTRIES; i++) {
+			addr += 4;
+			mdss_pp_res->six_zone_lut_curve_p1[disp_num][i] =
+				readl_relaxed(addr);
+			addr -= 4;
+			mdss_pp_res->six_zone_lut_curve_p0[disp_num][i] =
+				readl_relaxed(addr) & 0xFFF;
+		}
+
+		if (copy_to_user(pa_v2_config->six_zone_curve_p0,
+			&mdss_pp_res->six_zone_lut_curve_p0[disp_num][0],
+			SIX_ZONE_LUT_ENTRIES * sizeof(u32))) {
+			return -EFAULT;
+		}
+
+		if (copy_to_user(pa_v2_config->six_zone_curve_p1,
+			&mdss_pp_res->six_zone_lut_curve_p1[disp_num][0],
+			SIX_ZONE_LUT_ENTRIES * sizeof(u32))) {
+			return -EFAULT;
+		}
+
+		addr += 8;
+		pa_v2_config->six_zone_thresh = readl_relaxed(addr);
+		addr += 4;
+	} else {
+		addr += 12;
+	}
+
+	/* Skin memory color config registers */
+	if (pa_v2_config->flags & MDP_PP_PA_SKIN_ENABLE)
+		pp_read_pa_mem_col_regs(addr, &pa_v2_config->skin_cfg);
+
+	addr += 0x14;
+	/* Sky memory color config registers */
+	if (pa_v2_config->flags & MDP_PP_PA_SKY_ENABLE)
+		pp_read_pa_mem_col_regs(addr, &pa_v2_config->sky_cfg);
+
+	addr += 0x14;
+	/* Foliage memory color config registers */
+	if (pa_v2_config->flags & MDP_PP_PA_FOL_ENABLE)
+		pp_read_pa_mem_col_regs(addr, &pa_v2_config->fol_cfg);
+
+	return 0;
+}
+
+static void pp_read_pa_mem_col_regs(char __iomem *addr,
+				struct mdp_pa_mem_col_cfg *mem_col_cfg)
+{
+	mem_col_cfg->color_adjust_p0 = readl_relaxed(addr);
+	addr += 4;
+	mem_col_cfg->color_adjust_p1 = readl_relaxed(addr);
+	addr += 4;
+	mem_col_cfg->hue_region = readl_relaxed(addr);
+	addr += 4;
+	mem_col_cfg->sat_region = readl_relaxed(addr);
+	addr += 4;
+	mem_col_cfg->val_region = readl_relaxed(addr);
+}
+
+static int pp_copy_pa_six_zone_lut(struct mdp_pa_v2_cfg_data *pa_v2_config,
+				u32 disp_num)
+{
+	if (copy_from_user(&mdss_pp_res->six_zone_lut_curve_p0[disp_num][0],
+			pa_v2_config->pa_v2_data.six_zone_curve_p0,
+			SIX_ZONE_LUT_ENTRIES * sizeof(u32))) {
+		return -EFAULT;
+	}
+	if (copy_from_user(&mdss_pp_res->six_zone_lut_curve_p1[disp_num][0],
+			pa_v2_config->pa_v2_data.six_zone_curve_p1,
+			SIX_ZONE_LUT_ENTRIES * sizeof(u32))) {
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static void pp_read_pcc_regs(char __iomem *addr,
 				struct mdp_pcc_cfg_data *cfg_ptr)
 {
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.c);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.c);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.c);
-	offset += 0x10;
+	cfg_ptr->r.c = readl_relaxed(addr);
+	cfg_ptr->g.c = readl_relaxed(addr + 4);
+	cfg_ptr->b.c = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.r);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.r);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.r);
-	offset += 0x10;
+	cfg_ptr->r.r = readl_relaxed(addr);
+	cfg_ptr->g.r = readl_relaxed(addr + 4);
+	cfg_ptr->b.r = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.g);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.g);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.g);
-	offset += 0x10;
+	cfg_ptr->r.g = readl_relaxed(addr);
+	cfg_ptr->g.g = readl_relaxed(addr + 4);
+	cfg_ptr->b.g = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.b);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.b);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.b);
-	offset += 0x10;
+	cfg_ptr->r.b = readl_relaxed(addr);
+	cfg_ptr->g.b = readl_relaxed(addr + 4);
+	cfg_ptr->b.b = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rr);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rr);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rr);
-	offset += 0x10;
+	cfg_ptr->r.rr = readl_relaxed(addr);
+	cfg_ptr->g.rr = readl_relaxed(addr + 4);
+	cfg_ptr->b.rr = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rg);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rg);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rg);
-	offset += 0x10;
+	cfg_ptr->r.rg = readl_relaxed(addr);
+	cfg_ptr->g.rg = readl_relaxed(addr + 4);
+	cfg_ptr->b.rg = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rb);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rb);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rb);
-	offset += 0x10;
+	cfg_ptr->r.rb = readl_relaxed(addr);
+	cfg_ptr->g.rb = readl_relaxed(addr + 4);
+	cfg_ptr->b.rb = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gg);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gg);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gg);
-	offset += 0x10;
+	cfg_ptr->r.gg = readl_relaxed(addr);
+	cfg_ptr->g.gg = readl_relaxed(addr + 4);
+	cfg_ptr->b.gg = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.gb);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.gb);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.gb);
-	offset += 0x10;
+	cfg_ptr->r.gb = readl_relaxed(addr);
+	cfg_ptr->g.gb = readl_relaxed(addr + 4);
+	cfg_ptr->b.gb = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.bb);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.bb);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.bb);
-	offset += 0x10;
+	cfg_ptr->r.bb = readl_relaxed(addr);
+	cfg_ptr->g.bb = readl_relaxed(addr + 4);
+	cfg_ptr->b.bb = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_0);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_0);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_0);
-	offset += 0x10;
+	cfg_ptr->r.rgb_0 = readl_relaxed(addr);
+	cfg_ptr->g.rgb_0 = readl_relaxed(addr + 4);
+	cfg_ptr->b.rgb_0 = readl_relaxed(addr + 8);
+	addr += 0x10;
 
-	MDSS_MDP_REG_WRITE(offset, cfg_ptr->r.rgb_1);
-	MDSS_MDP_REG_WRITE(offset + 4, cfg_ptr->g.rgb_1);
-	MDSS_MDP_REG_WRITE(offset + 8, cfg_ptr->b.rgb_1);
+	cfg_ptr->r.rgb_1 = readl_relaxed(addr);
+	cfg_ptr->g.rgb_1 = readl_relaxed(addr + 4);
+	cfg_ptr->b.rgb_1 = readl_relaxed(addr + 8);
+}
+
+static void pp_update_pcc_regs(char __iomem *addr,
+				struct mdp_pcc_cfg_data *cfg_ptr)
+{
+	writel_relaxed(cfg_ptr->r.c, addr);
+	writel_relaxed(cfg_ptr->g.c, addr + 4);
+	writel_relaxed(cfg_ptr->b.c, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.r, addr);
+	writel_relaxed(cfg_ptr->g.r, addr + 4);
+	writel_relaxed(cfg_ptr->b.r, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.g, addr);
+	writel_relaxed(cfg_ptr->g.g, addr + 4);
+	writel_relaxed(cfg_ptr->b.g, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.b, addr);
+	writel_relaxed(cfg_ptr->g.b, addr + 4);
+	writel_relaxed(cfg_ptr->b.b, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.rr, addr);
+	writel_relaxed(cfg_ptr->g.rr, addr + 4);
+	writel_relaxed(cfg_ptr->b.rr, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.rg, addr);
+	writel_relaxed(cfg_ptr->g.rg, addr + 4);
+	writel_relaxed(cfg_ptr->b.rg, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.rb, addr);
+	writel_relaxed(cfg_ptr->g.rb, addr + 4);
+	writel_relaxed(cfg_ptr->b.rb, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.gg, addr);
+	writel_relaxed(cfg_ptr->g.gg, addr + 4);
+	writel_relaxed(cfg_ptr->b.gg, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.gb, addr);
+	writel_relaxed(cfg_ptr->g.gb, addr + 4);
+	writel_relaxed(cfg_ptr->b.gb, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.bb, addr);
+	writel_relaxed(cfg_ptr->g.bb, addr + 4);
+	writel_relaxed(cfg_ptr->b.bb, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.rgb_0, addr);
+	writel_relaxed(cfg_ptr->g.rgb_0, addr + 4);
+	writel_relaxed(cfg_ptr->b.rgb_0, addr + 8);
+	addr += 0x10;
+
+	writel_relaxed(cfg_ptr->r.rgb_1, addr);
+	writel_relaxed(cfg_ptr->g.rgb_1, addr + 4);
+	writel_relaxed(cfg_ptr->b.rgb_1, addr + 8);
 }
 
 int mdss_mdp_pcc_config(struct mdp_pcc_cfg_data *config,
 					u32 *copyback)
 {
 	int ret = 0;
-	u32 base, disp_num, dspp_num = 0;
+	u32 disp_num, dspp_num = 0;
+	char __iomem *addr;
 
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
@@ -1606,9 +2130,9 @@
 
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
-		base = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+		addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
 			  MDSS_MDP_REG_DSPP_PCC_BASE;
-		pp_read_pcc_regs(base, config);
+		pp_read_pcc_regs(addr, config);
 		*copyback = 1;
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 	} else {
@@ -1622,57 +2146,57 @@
 }
 
 static void pp_read_igc_lut(struct mdp_igc_lut_data *cfg,
-				u32 offset, u32 blk_idx)
+				char __iomem *addr, u32 blk_idx)
 {
 	int i;
 	u32 data;
 
 	/* INDEX_UPDATE & VALUE_UPDATEN */
 	data = (3 << 24) | (((~(1 << blk_idx)) & 0x7) << 28);
-	MDSS_MDP_REG_WRITE(offset, data);
+	writel_relaxed(data, addr);
 
 	for (i = 0; i < cfg->len; i++)
-		cfg->c0_c1_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+		cfg->c0_c1_data[i] = readl_relaxed(addr) & 0xFFF;
 
-	offset += 0x4;
-	MDSS_MDP_REG_WRITE(offset, data);
+	addr += 0x4;
+	writel_relaxed(data, addr);
 	for (i = 0; i < cfg->len; i++)
-		cfg->c0_c1_data[i] |= (MDSS_MDP_REG_READ(offset) & 0xFFF) << 16;
+		cfg->c0_c1_data[i] |= (readl_relaxed(addr) & 0xFFF) << 16;
 
-	offset += 0x4;
-	MDSS_MDP_REG_WRITE(offset, data);
+	addr += 0x4;
+	writel_relaxed(data, addr);
 	for (i = 0; i < cfg->len; i++)
-		cfg->c2_data[i] = MDSS_MDP_REG_READ(offset) & 0xFFF;
+		cfg->c2_data[i] = readl_relaxed(addr) & 0xFFF;
 }
 
 static void pp_update_igc_lut(struct mdp_igc_lut_data *cfg,
-				u32 offset, u32 blk_idx)
+				char __iomem *addr, u32 blk_idx)
 {
 	int i;
 	u32 data;
 	/* INDEX_UPDATE */
 	data = (1 << 25) | (((~(1 << blk_idx)) & 0x7) << 28);
-	MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[0] & 0xFFF) | data);
+	writel_relaxed((cfg->c0_c1_data[0] & 0xFFF) | data, addr);
 
 	/* disable index update */
 	data &= ~(1 << 25);
 	for (i = 1; i < cfg->len; i++)
-		MDSS_MDP_REG_WRITE(offset, (cfg->c0_c1_data[i] & 0xFFF) | data);
+		writel_relaxed((cfg->c0_c1_data[i] & 0xFFF) | data, addr);
 
-	offset += 0x4;
+	addr += 0x4;
 	data |= (1 << 25);
-	MDSS_MDP_REG_WRITE(offset, ((cfg->c0_c1_data[0] >> 16) & 0xFFF) | data);
+	writel_relaxed(((cfg->c0_c1_data[0] >> 16) & 0xFFF) | data, addr);
 	data &= ~(1 << 25);
 	for (i = 1; i < cfg->len; i++)
-		MDSS_MDP_REG_WRITE(offset,
-		((cfg->c0_c1_data[i] >> 16) & 0xFFF) | data);
+		writel_relaxed(((cfg->c0_c1_data[i] >> 16) & 0xFFF) | data,
+				addr);
 
-	offset += 0x4;
+	addr += 0x4;
 	data |= (1 << 25);
-	MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[0] & 0xFFF) | data);
+	writel_relaxed((cfg->c2_data[0] & 0xFFF) | data, addr);
 	data &= ~(1 << 25);
 	for (i = 1; i < cfg->len; i++)
-		MDSS_MDP_REG_WRITE(offset, (cfg->c2_data[i] & 0xFFF) | data);
+		writel_relaxed((cfg->c2_data[i] & 0xFFF) | data, addr);
 }
 
 int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl)
@@ -1700,8 +2224,10 @@
 					u32 *copyback, u32 copy_from_kernel)
 {
 	int ret = 0;
-	u32 tbl_idx, igc_offset, disp_num, dspp_num = 0;
+	u32 tbl_idx, disp_num, dspp_num = 0;
 	struct mdp_igc_lut_data local_cfg;
+	char __iomem *igc_addr;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
@@ -1727,13 +2253,14 @@
 			tbl_idx = 2;
 		else
 			tbl_idx = 0;
-		igc_offset = MDSS_MDP_REG_IGC_DSPP_BASE + (0x10 * tbl_idx);
+		igc_addr = mdata->mdp_base + MDSS_MDP_REG_IGC_DSPP_BASE +
+			(0x10 * tbl_idx);
 		local_cfg = *config;
 		local_cfg.c0_c1_data =
 			&mdss_pp_res->igc_lut_c0c1[disp_num][0];
 		local_cfg.c2_data =
 			&mdss_pp_res->igc_lut_c2[disp_num][0];
-		pp_read_igc_lut(&local_cfg, igc_offset, dspp_num);
+		pp_read_igc_lut(&local_cfg, igc_addr, dspp_num);
 		if (copy_to_user(config->c0_c1_data, local_cfg.c2_data,
 			config->len * sizeof(u32))) {
 			ret = -EFAULT;
@@ -1781,126 +2308,128 @@
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
 }
-static void pp_update_gc_one_lut(u32 offset,
+static void pp_update_gc_one_lut(char __iomem *addr,
 		struct mdp_ar_gc_lut_data *lut_data,
 		uint8_t num_stages)
 {
 	int i, start_idx, idx;
 
-	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	start_idx = (readl_relaxed(addr) >> 16) & 0xF;
 	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
-		MDSS_MDP_REG_WRITE(offset, lut_data[idx].x_start);
+		writel_relaxed(lut_data[idx].x_start, addr);
 	}
 	for (i = 0; i < start_idx; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
-		MDSS_MDP_REG_WRITE(offset, lut_data[idx].x_start);
+		writel_relaxed(lut_data[idx].x_start, addr);
 	}
-	offset += 4;
-	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	addr += 4;
+	start_idx = (readl_relaxed(addr) >> 16) & 0xF;
 	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
-		MDSS_MDP_REG_WRITE(offset, lut_data[idx].slope);
+		writel_relaxed(lut_data[idx].slope, addr);
 	}
 	for (i = 0; i < start_idx; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
-		MDSS_MDP_REG_WRITE(offset, lut_data[idx].slope);
+		writel_relaxed(lut_data[idx].slope, addr);
 	}
-	offset += 4;
-	start_idx = (MDSS_MDP_REG_READ(offset) >> 16) & 0xF;
+	addr += 4;
+	start_idx = (readl_relaxed(addr) >> 16) & 0xF;
 	for (i = start_idx; i < GC_LUT_SEGMENTS; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
-		MDSS_MDP_REG_WRITE(offset, lut_data[idx].offset);
+		writel_relaxed(lut_data[idx].offset, addr);
 	}
 	for (i = 0; i < start_idx; i++) {
 		idx = min((uint8_t)i, (uint8_t)(num_stages-1));
-		MDSS_MDP_REG_WRITE(offset, lut_data[idx].offset);
+		writel_relaxed(lut_data[idx].offset, addr);
 	}
 }
-static void pp_update_argc_lut(u32 offset, struct mdp_pgc_lut_data *config)
+static void pp_update_argc_lut(char __iomem *addr,
+				struct mdp_pgc_lut_data *config)
 {
-	pp_update_gc_one_lut(offset, config->r_data, config->num_r_stages);
-	offset += 0x10;
-	pp_update_gc_one_lut(offset, config->g_data, config->num_g_stages);
-	offset += 0x10;
-	pp_update_gc_one_lut(offset, config->b_data, config->num_b_stages);
+	pp_update_gc_one_lut(addr, config->r_data, config->num_r_stages);
+	addr += 0x10;
+	pp_update_gc_one_lut(addr, config->g_data, config->num_g_stages);
+	addr += 0x10;
+	pp_update_gc_one_lut(addr, config->b_data, config->num_b_stages);
 }
-static void pp_read_gc_one_lut(u32 offset,
+static void pp_read_gc_one_lut(char __iomem *addr,
 		struct mdp_ar_gc_lut_data *gc_data)
 {
 	int i, start_idx, data;
-	data = MDSS_MDP_REG_READ(offset);
+	data = readl_relaxed(addr);
 	start_idx = (data >> 16) & 0xF;
 	gc_data[start_idx].x_start = data & 0xFFF;
 
 	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
-		data = MDSS_MDP_REG_READ(offset);
+		data = readl_relaxed(addr);
 		gc_data[i].x_start = data & 0xFFF;
 	}
 	for (i = 0; i < start_idx; i++) {
-		data = MDSS_MDP_REG_READ(offset);
+		data = readl_relaxed(addr);
 		gc_data[i].x_start = data & 0xFFF;
 	}
 
-	offset += 4;
-	data = MDSS_MDP_REG_READ(offset);
+	addr += 4;
+	data = readl_relaxed(addr);
 	start_idx = (data >> 16) & 0xF;
 	gc_data[start_idx].slope = data & 0x7FFF;
 	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
-		data = MDSS_MDP_REG_READ(offset);
+		data = readl_relaxed(addr);
 		gc_data[i].slope = data & 0x7FFF;
 	}
 	for (i = 0; i < start_idx; i++) {
-		data = MDSS_MDP_REG_READ(offset);
+		data = readl_relaxed(addr);
 		gc_data[i].slope = data & 0x7FFF;
 	}
-	offset += 4;
-	data = MDSS_MDP_REG_READ(offset);
+	addr += 4;
+	data = readl_relaxed(addr);
 	start_idx = (data >> 16) & 0xF;
 	gc_data[start_idx].offset = data & 0x7FFF;
 	for (i = start_idx + 1; i < GC_LUT_SEGMENTS; i++) {
-		data = MDSS_MDP_REG_READ(offset);
+		data = readl_relaxed(addr);
 		gc_data[i].offset = data & 0x7FFF;
 	}
 	for (i = 0; i < start_idx; i++) {
-		data = MDSS_MDP_REG_READ(offset);
+		data = readl_relaxed(addr);
 		gc_data[i].offset = data & 0x7FFF;
 	}
 }
 
-static int pp_read_argc_lut(struct mdp_pgc_lut_data *config, u32 offset)
+static int pp_read_argc_lut(struct mdp_pgc_lut_data *config, char __iomem *addr)
 {
 	int ret = 0;
-	pp_read_gc_one_lut(offset, config->r_data);
-	offset += 0x10;
-	pp_read_gc_one_lut(offset, config->g_data);
-	offset += 0x10;
-	pp_read_gc_one_lut(offset, config->b_data);
+	pp_read_gc_one_lut(addr, config->r_data);
+	addr += 0x10;
+	pp_read_gc_one_lut(addr, config->g_data);
+	addr += 0x10;
+	pp_read_gc_one_lut(addr, config->b_data);
 	return ret;
 }
 
 /* Note: Assumes that its inputs have been checked by calling function */
-static void pp_update_hist_lut(char __iomem *offset,
+static void pp_update_hist_lut(char __iomem *addr,
 				struct mdp_hist_lut_data *cfg)
 {
 	int i;
 	for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
-		writel_relaxed(cfg->data[i], offset);
+		writel_relaxed(cfg->data[i], addr);
 	/* swap */
 	if (PP_LOCAT(cfg->block) == MDSS_PP_DSPP_CFG)
-		writel_relaxed(1, offset + 4);
+		writel_relaxed(1, addr + 4);
 	else
-		writel_relaxed(1, offset + 16);
+		writel_relaxed(1, addr + 16);
 }
 
 int mdss_mdp_argc_config(struct mdp_pgc_lut_data *config,
 				u32 *copyback)
 {
 	int ret = 0;
-	u32 argc_offset = 0, disp_num, dspp_num = 0;
+	u32 disp_num, dspp_num = 0;
 	struct mdp_pgc_lut_data local_cfg;
 	struct mdp_pgc_lut_data *pgc_ptr;
 	u32 tbl_size, r_size, g_size, b_size;
+	char __iomem *argc_addr = 0;
 
 	if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
@@ -1911,14 +2440,14 @@
 	disp_num = PP_BLOCK(config->block) - MDP_LOGICAL_BLOCK_DISP_0;
 	switch (PP_LOCAT(config->block)) {
 	case MDSS_PP_LM_CFG:
-		argc_offset = MDSS_MDP_REG_LM_OFFSET(dspp_num) +
+		argc_addr = mdss_mdp_get_mixer_addr_off(dspp_num) +
 			MDSS_MDP_REG_LM_GC_LUT_BASE;
 		pgc_ptr = &mdss_pp_res->argc_disp_cfg[disp_num];
 		mdss_pp_res->pp_disp_flags[disp_num] |=
 			PP_FLAGS_DIRTY_ARGC;
 		break;
 	case MDSS_PP_DSPP_CFG:
-		argc_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+		argc_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
 					MDSS_MDP_REG_DSPP_GC_BASE;
 		pgc_ptr = &mdss_pp_res->pgc_disp_cfg[disp_num];
 		mdss_pp_res->pp_disp_flags[disp_num] |=
@@ -1946,7 +2475,7 @@
 			&mdss_pp_res->gc_lut_g[disp_num][0];
 		local_cfg.b_data =
 			&mdss_pp_res->gc_lut_b[disp_num][0];
-		pp_read_argc_lut(&local_cfg, argc_offset);
+		pp_read_argc_lut(&local_cfg, argc_addr);
 		if (copy_to_user(config->r_data,
 			&mdss_pp_res->gc_lut_r[disp_num][0], tbl_size)) {
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -2017,7 +2546,8 @@
 					u32 *copyback)
 {
 	int i, ret = 0;
-	u32 hist_offset, disp_num, dspp_num = 0;
+	u32 disp_num, dspp_num = 0;
+	char __iomem *hist_addr;
 
 	if ((PP_BLOCK(config->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(config->block) >= MDP_BLOCK_MAX))
@@ -2035,11 +2565,11 @@
 		}
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
-		hist_offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+		hist_addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
 			  MDSS_MDP_REG_DSPP_HIST_LUT_BASE;
 		for (i = 0; i < ENHIST_LUT_ENTRIES; i++)
 			mdss_pp_res->enhist_lut[disp_num][i] =
-				MDSS_MDP_REG_READ(hist_offset);
+				readl_relaxed(hist_addr);
 		if (copy_to_user(config->data,
 			&mdss_pp_res->enhist_lut[disp_num][0],
 			ENHIST_LUT_ENTRIES * sizeof(u32))) {
@@ -2110,13 +2640,13 @@
 					u32 *copyback)
 {
 	int i, j, ret = 0;
-	u32 offset, disp_num, dspp_num = 0;
+	u32 disp_num, dspp_num = 0;
 	uint16_t *tbl_off;
 	struct mdp_gamut_cfg_data local_cfg;
 	uint16_t *r_tbl[MDP_GAMUT_TABLE_NUM];
 	uint16_t *g_tbl[MDP_GAMUT_TABLE_NUM];
 	uint16_t *b_tbl[MDP_GAMUT_TABLE_NUM];
-
+	char __iomem *addr;
 
 	if ((config->block < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(config->block >= MDP_BLOCK_MAX))
@@ -2137,7 +2667,7 @@
 		}
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
-		offset = MDSS_MDP_REG_DSPP_OFFSET(dspp_num) +
+		addr = mdss_mdp_get_dspp_addr_off(dspp_num) +
 			  MDSS_MDP_REG_DSPP_GAMUT_BASE;
 		for (i = 0; i < MDP_GAMUT_TABLE_NUM; i++) {
 			r_tbl[i] = kzalloc(
@@ -2149,8 +2679,8 @@
 			}
 			for (j = 0; j < config->tbl_size[i]; j++)
 				r_tbl[i][j] =
-					(u16)MDSS_MDP_REG_READ(offset);
-			offset += 4;
+					(u16)readl_relaxed(addr);
+			addr += 4;
 			ret = copy_to_user(config->r_tbl[i], r_tbl[i],
 				     sizeof(uint16_t) * config->tbl_size[i]);
 			kfree(r_tbl[i]);
@@ -2170,8 +2700,8 @@
 			}
 			for (j = 0; j < config->tbl_size[i]; j++)
 				g_tbl[i][j] =
-					(u16)MDSS_MDP_REG_READ(offset);
-			offset += 4;
+					(u16)readl_relaxed(addr);
+			addr += 4;
 			ret = copy_to_user(config->g_tbl[i], g_tbl[i],
 				     sizeof(uint16_t) * config->tbl_size[i]);
 			kfree(g_tbl[i]);
@@ -2191,8 +2721,8 @@
 			}
 			for (j = 0; j < config->tbl_size[i]; j++)
 				b_tbl[i][j] =
-					(u16)MDSS_MDP_REG_READ(offset);
-			offset += 4;
+					(u16)readl_relaxed(addr);
+			addr += 4;
 			ret = copy_to_user(config->b_tbl[i], b_tbl[i],
 				     sizeof(uint16_t) * config->tbl_size[i]);
 			kfree(b_tbl[i]);
@@ -2241,18 +2771,18 @@
 	mutex_unlock(&mdss_pp_mutex);
 	return ret;
 }
-static void pp_hist_read(char __iomem *v_base,
+static void pp_hist_read(char __iomem *v_addr,
 				struct pp_hist_col_info *hist_info)
 {
 	int i, i_start;
 	u32 data;
-	data = readl_relaxed(v_base);
+	data = readl_relaxed(v_addr);
 	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] = readl_relaxed(v_base) & 0xFFFFFF;
+		hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
 	for (i = 0; i < i_start - 1; i++)
-		hist_info->data[i] = readl_relaxed(v_base) & 0xFFFFFF;
+		hist_info->data[i] = readl_relaxed(v_addr) & 0xFFFFFF;
 	hist_info->hist_cnt_read++;
 }
 
@@ -2263,6 +2793,8 @@
 {
 	unsigned long flag;
 	int ret = 0;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
 	mutex_lock(&hist_info->hist_mutex);
 	/* check if it is idle */
 	if (hist_info->col_en) {
@@ -2282,7 +2814,7 @@
 	hist_info->col_en = true;
 	spin_unlock_irqrestore(&hist_info->hist_lock, flag);
 	hist_info->is_kick_ready = true;
-	mdss_mdp_hist_irq_enable(3 << shift_bit);
+	mdss_mdp_hist_intr_req(&mdata->hist_intr, 3 << shift_bit, true);
 	writel_relaxed(req->frame_cnt, ctl_base + 8);
 	/* Kick out reset start */
 	writel_relaxed(1, ctl_base + 4);
@@ -2291,7 +2823,8 @@
 	return ret;
 }
 
-int mdss_mdp_histogram_start(struct mdp_histogram_start_req *req)
+#define MDSS_MAX_HIST_BIN_SIZE 16777215
+int mdss_mdp_hist_start(struct mdp_histogram_start_req *req)
 {
 	u32 done_shift_bit;
 	char __iomem *ctl_base;
@@ -2299,9 +2832,13 @@
 	int i, ret = 0;
 	u32 disp_num, dspp_num = 0;
 	u32 mixer_cnt, mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+	u32 frame_size;
 	struct mdss_mdp_pipe *pipe;
 	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
 
+	if (!mdss_is_ready())
+		return -EPROBE_DEFER;
+
 	if ((PP_BLOCK(req->block) < MDP_LOGICAL_BLOCK_DISP_0) ||
 		(PP_BLOCK(req->block) >= MDP_BLOCK_MAX))
 		return -EINVAL;
@@ -2321,6 +2858,16 @@
 		ret = -EPERM;
 		goto hist_exit;
 	}
+
+	frame_size = (mdata->ctl_off[mixer_id[0]].width *
+					mdata->ctl_off[mixer_id[0]].height);
+	if (!frame_size ||
+		((MDSS_MAX_HIST_BIN_SIZE / frame_size) < req->frame_cnt)) {
+		pr_err("%s, too many frames for given display size, %d",
+						__func__, req->frame_cnt);
+		ret = -EINVAL;
+		goto hist_exit;
+	}
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
 	if (PP_LOCAT(req->block) == MDSS_PP_SSPP_CFG) {
@@ -2328,7 +2875,7 @@
 		if (!i) {
 			ret = -EINVAL;
 			pr_warn("Must pass pipe arguments, %d", i);
-			goto hist_exit;
+			goto hist_stop_clk;
 		}
 
 		for (i = 0; i < MDSS_PP_ARG_NUM; i++) {
@@ -2338,10 +2885,9 @@
 			if (IS_ERR_OR_NULL(pipe))
 				continue;
 			if (!pipe || pipe->num > MDSS_MDP_SSPP_VIG2) {
-				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 				ret = -EINVAL;
 				pr_warn("Invalid Hist pipe (%d)", i);
-				goto hist_exit;
+				goto hist_stop_clk;
 			}
 			done_shift_bit = (pipe->num * 4);
 			hist_info = &pipe->pp_res.hist;
@@ -2364,8 +2910,8 @@
 							PP_FLAGS_DIRTY_HIST_COL;
 		}
 	}
+hist_stop_clk:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
-
 hist_exit:
 	return ret;
 }
@@ -2375,6 +2921,8 @@
 {
 	int ret = 0;
 	unsigned long flag;
+	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
 	mutex_lock(&hist_info->hist_mutex);
 	if (hist_info->col_en == false) {
 		pr_debug("Histogram already disabled (%d)", (u32) ctl_base);
@@ -2387,7 +2935,7 @@
 	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);
+	mdss_mdp_hist_intr_req(&mdata->hist_intr, done_bit, false);
 	writel_relaxed(BIT(1), ctl_base);/* cancel */
 	ret = 0;
 exit:
@@ -2395,7 +2943,7 @@
 	return ret;
 }
 
-int mdss_mdp_histogram_stop(u32 block)
+int mdss_mdp_hist_stop(u32 block)
 {
 	int i, ret = 0;
 	char __iomem *ctl_base;
@@ -2472,6 +3020,150 @@
 	return ret;
 }
 
+/**
+ * mdss_mdp_hist_intr_req() - Request changes the histogram interupts
+ * @intr: structure containting state of interrupt register
+ * @bits: the bits on interrupt register that should be changed
+ * @en: true if bits should be set, false if bits should be cleared
+ *
+ * Adds or removes the bits from the interrupt request.
+ *
+ * Does not store reference count for each bit. I.e. a bit with multiple
+ * enable requests can be disabled with a single disable request.
+ *
+ * Return: 0 if uneventful, errno on invalid input
+ */
+int mdss_mdp_hist_intr_req(struct mdss_intr *intr, u32 bits, bool en)
+{
+	unsigned long flag;
+	int ret = 0;
+	if (!intr) {
+		pr_err("NULL addr passed, %p", intr);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&intr->lock, flag);
+	if (en)
+		intr->req |= bits;
+	else
+		intr->req &= ~bits;
+	spin_unlock_irqrestore(&intr->lock, flag);
+
+	mdss_mdp_hist_intr_setup(intr, MDSS_IRQ_REQ);
+
+	return ret;
+}
+
+
+#define MDSS_INTR_STATE_ACTIVE	1
+#define MDSS_INTR_STATE_NULL	0
+#define MDSS_INTR_STATE_SUSPEND	-1
+
+/**
+ * mdss_mdp_hist_intr_setup() - Manage intr and clk depending on requests.
+ * @intr: structure containting state of intr reg
+ * @state: MDSS_IRQ_SUSPEND if suspend is needed,
+ *         MDSS_IRQ_RESUME if resume is needed,
+ *         MDSS_IRQ_REQ if neither (i.e. requesting an interrupt)
+ *
+ * This function acts as a gatekeeper for the interrupt, making sure that the
+ * MDP clocks are enabled while the interrupts are enabled to prevent
+ * unclocked accesses.
+ *
+ * To reduce code repetition, 4 state transitions have been encoded here. Each
+ * transition updates the interrupt's state structure (mdss_intr) to reflect
+ * the which bits have been requested (intr->req), are currently enabled
+ * (intr->curr), as well as defines which interrupt bits need to be enabled or
+ * disabled ('en' and 'dis' respectively). The 4th state is not explicity
+ * coded in the if/else chain, but is for MDSS_IRQ_REQ's when the interrupt
+ * is in suspend, in which case, the only change required (intr->req being
+ * updated) has already occured in the calling function.
+ *
+ * To control the clock, which can't be requested while holding the spinlock,
+ * the inital state is compared with the exit state to detect when the
+ * interrupt needs a clock.
+ *
+ * The clock requests surrounding the majority of this function serve to
+ * enable the register writes to change the interrupt register, as well as to
+ * prevent a race condition that could keep the clocks on (due to mdp_clk_cnt
+ * never being decremented below 0) when a enable/disable occurs but the
+ * disable requests the clocks disabled before the enable is able to request
+ * the clocks enabled.
+ *
+ * Return: 0 if uneventful, errno on repeated action or invalid input
+ */
+int mdss_mdp_hist_intr_setup(struct mdss_intr *intr, int type)
+{
+	unsigned long flag;
+	int ret = 0, req_clk = 0;
+	u32 en = 0, dis = 0;
+	u32 diff, init_curr;
+	int init_state;
+	if (!intr) {
+		WARN(1, "NULL intr pointer");
+		return -EINVAL;
+	}
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	spin_lock_irqsave(&intr->lock, flag);
+
+	init_state = intr->state;
+	init_curr = intr->curr;
+
+	if (type == MDSS_IRQ_RESUME) {
+		/* resume intrs */
+		if (intr->state == MDSS_INTR_STATE_ACTIVE) {
+			ret = -EPERM;
+			goto exit;
+		}
+		en = intr->req;
+		dis = 0;
+		intr->curr = intr->req;
+		intr->state = intr->curr ?
+				MDSS_INTR_STATE_ACTIVE : MDSS_INTR_STATE_NULL;
+	} else if (type == MDSS_IRQ_SUSPEND) {
+		/* suspend intrs */
+		if (intr->state == MDSS_INTR_STATE_SUSPEND) {
+			ret = -EPERM;
+			goto exit;
+		}
+		en = 0;
+		dis = intr->curr;
+		intr->curr = 0;
+		intr->state = MDSS_INTR_STATE_SUSPEND;
+	} else if (intr->state != MDSS_IRQ_SUSPEND) {
+		/* Not resuming/suspending or in suspend state */
+		diff = intr->req ^ intr->curr;
+		en = diff & ~intr->curr;
+		dis = diff & ~intr->req;
+		intr->curr = intr->req;
+		intr->state = intr->curr ?
+				MDSS_INTR_STATE_ACTIVE : MDSS_INTR_STATE_NULL;
+	}
+
+	if (en)
+		mdss_mdp_hist_irq_enable(en);
+	if (dis)
+		mdss_mdp_hist_irq_disable(dis);
+
+	if ((init_state != MDSS_INTR_STATE_ACTIVE) &&
+				(intr->state == MDSS_INTR_STATE_ACTIVE))
+		req_clk = 1;
+	else if ((init_state == MDSS_INTR_STATE_ACTIVE) &&
+				(intr->state != MDSS_INTR_STATE_ACTIVE))
+		req_clk = -1;
+
+exit:
+	spin_unlock_irqrestore(&intr->lock, flag);
+	if (req_clk < 0)
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	else if (req_clk > 0)
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	return ret;
+}
+
 static int pp_hist_collect(struct mdp_histogram_data *hist,
 				struct pp_hist_col_info *hist_info,
 				char __iomem *ctl_base)
@@ -2796,7 +3488,6 @@
 	return out;
 }
 
-#define MDSS_AD_MAX_MIXERS 1
 static int mdss_ad_init_checks(struct msm_fb_data_type *mfd)
 {
 	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
@@ -2822,8 +3513,9 @@
 		pr_debug("no mixers connected, %d", mixer_num);
 		return -EHOSTDOWN;
 	}
-	if (mixer_num > MDSS_AD_MAX_MIXERS) {
-		pr_debug("too many mixers, not supported, %d", mixer_num);
+	if (mixer_num > mdata->nmax_concurrent_ad_hw) {
+		pr_debug("too many mixers, not supported, %d > %d", mixer_num,
+						mdata->nmax_concurrent_ad_hw);
 		return ret;
 	}
 
@@ -2987,6 +3679,11 @@
 			ret = -EINVAL;
 			goto error;
 		}
+		if (input->in.amb_light > MDSS_MDP_MAX_AD_AL) {
+			pr_warn("invalid input ambient light");
+			ret = -EINVAL;
+			goto error;
+		}
 		ad->ad_data_mode = MDSS_AD_INPUT_AMBIENT;
 		pr_debug("ambient = %d", input->in.amb_light);
 		ad->ad_data = input->in.amb_light;
@@ -3001,6 +3698,11 @@
 			ret = -EINVAL;
 			goto error;
 		}
+		if (input->in.strength > MDSS_MDP_MAX_AD_STR) {
+			pr_warn("invalid input strength");
+			ret = -EINVAL;
+			goto error;
+		}
 		ad->ad_data_mode = MDSS_AD_INPUT_STRENGTH;
 		pr_debug("strength = %d", input->in.strength);
 		ad->ad_data = input->in.strength;
@@ -3052,23 +3754,26 @@
 	return ret;
 }
 
-static void pp_ad_input_write(struct mdss_ad_info *ad, u32 bl_lvl)
+static void pp_ad_input_write(struct mdss_mdp_ad *ad_hw,
+						struct mdss_ad_info *ad)
 {
-	char __iomem *base = ad->base;
+	char __iomem *base;
+
+	base = ad_hw->base;
 	switch (ad->cfg.mode) {
 	case MDSS_AD_MODE_AUTO_BL:
 		writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
 		break;
 	case MDSS_AD_MODE_AUTO_STR:
-		writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+		writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
 		writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_AL);
 		break;
 	case MDSS_AD_MODE_TARG_STR:
-		writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+		writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
 		writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_TARG_STR);
 		break;
 	case MDSS_AD_MODE_MAN_STR:
-		writel_relaxed(bl_lvl, base + MDSS_MDP_REG_AD_BL);
+		writel_relaxed(ad->bl_data, base + MDSS_MDP_REG_AD_BL);
 		writel_relaxed(ad->ad_data, base + MDSS_MDP_REG_AD_STR_MAN);
 		break;
 	default:
@@ -3077,10 +3782,27 @@
 	}
 }
 
-static void pp_ad_init_write(struct mdss_ad_info *ad)
+#define MDSS_AD_MERGED_WIDTH 4
+static void pp_ad_init_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad,
+						struct mdss_mdp_ctl *ctl)
 {
+	struct mdss_data_type *mdata = ctl->mdata;
 	u32 temp;
-	char __iomem *base = ad->base;
+	u32 frame_start, frame_end, procs_start, procs_end, tile_ctrl;
+	u32 num;
+	char __iomem *base;
+	bool is_calc, is_dual_pipe;
+	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+	u32 mixer_num;
+	mixer_num = mdss_mdp_get_ctl_mixers(ctl->mfd->index, mixer_id);
+	if (mixer_num > 1)
+		is_dual_pipe = true;
+	else
+		is_dual_pipe = false;
+
+	base = ad_hw->base;
+	is_calc = ad->calc_hw_num == ad_hw->num;
+
 	writel_relaxed(ad->init.i_control[0] & 0x1F,
 				base + MDSS_MDP_REG_AD_CON_CTRL_0);
 	writel_relaxed(ad->init.i_control[1] << 8,
@@ -3115,13 +3837,50 @@
 
 	pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_FI, ad->init.asym_lut);
 	pp_ad_cfg_lut(base + MDSS_MDP_REG_AD_LUT_CC, ad->init.color_corr_lut);
+
+	if (mdata->mdp_rev >= MDSS_MDP_HW_REV_103) {
+		if (is_dual_pipe) {
+			num = ad_hw->num;
+			tile_ctrl = 0x5;
+			if (is_calc) {
+				frame_start = 0;
+				procs_start = 0;
+				frame_end = mdata->mixer_intf[num].width +
+							MDSS_AD_MERGED_WIDTH;
+				procs_end = mdata->mixer_intf[num].width;
+			} else {
+				tile_ctrl |= 0x10;
+				procs_start = ad->init.frame_w -
+					(mdata->mixer_intf[num].width);
+				procs_end = ad->init.frame_w;
+				frame_start = procs_start -
+							MDSS_AD_MERGED_WIDTH;
+				frame_end = procs_end;
+			}
+			procs_end -= 1;
+			frame_end -= 1;
+		} else {
+			frame_start = 0x0;
+			frame_end = 0xFFFF;
+			procs_start = 0x0;
+			procs_end = 0xFFFF;
+			tile_ctrl = 0x1;
+		}
+		writel_relaxed(frame_start, base + MDSS_MDP_REG_AD_FRAME_START);
+		writel_relaxed(frame_end, base + MDSS_MDP_REG_AD_FRAME_END);
+		writel_relaxed(procs_start, base + MDSS_MDP_REG_AD_PROCS_START);
+		writel_relaxed(procs_end, base + MDSS_MDP_REG_AD_PROCS_END);
+		writel_relaxed(tile_ctrl, base + MDSS_MDP_REG_AD_TILE_CTRL);
+	}
 }
 
 #define MDSS_PP_AD_DEF_CALIB 0x6E
-static void pp_ad_cfg_write(struct mdss_ad_info *ad)
+static void pp_ad_cfg_write(struct mdss_mdp_ad *ad_hw, struct mdss_ad_info *ad)
 {
-	char __iomem *base = ad->base;
+	char __iomem *base;
 	u32 temp, temp_calib = MDSS_PP_AD_DEF_CALIB;
+
+	base = ad_hw->base;
 	switch (ad->cfg.mode) {
 	case MDSS_AD_MODE_AUTO_BL:
 		temp = ad->cfg.backlight_max << 16;
@@ -3170,29 +3929,57 @@
 }
 
 #define MDSS_PP_AD_BYPASS_DEF 0x101
+static void pp_ad_bypass_config(struct mdss_ad_info *ad, u32 *opmode)
+{
+	if (ad->reg_sts & PP_STS_ENABLE)
+		*opmode = 0;
+	else
+		*opmode = MDSS_PP_AD_BYPASS_DEF;
+}
+
+static int pp_ad_setup_hw_nums(struct msm_fb_data_type *mfd,
+						struct mdss_ad_info *ad)
+{
+	u32 mixer_id[MDSS_MDP_INTF_MAX_LAYERMIXER];
+	u32 mixer_num;
+
+	mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
+	if (!mixer_num)
+		return -EINVAL;
+
+	/* default to left mixer */
+	ad->calc_hw_num = mixer_id[0];
+	return 0;
+}
+
 static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
 {
 	int ret = 0;
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
 	struct msm_fb_data_type *bl_mfd;
-	char __iomem *base;
-	u32 temp;
+	struct mdss_data_type *mdata;
 	u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
 
 	ret = mdss_mdp_get_ad(mfd, &ad);
-	if (ret)
-		return ret;
+	if (ret) {
+		ret = -EINVAL;
+		pr_debug("failed to get ad_info, err = %d", ret);
+		goto exit;
+	}
 	if (mfd->panel_info->type == WRITEBACK_PANEL) {
 		bl_mfd = mdss_get_mfd_from_index(0);
-		if (!bl_mfd)
-			return ret;
+		if (!bl_mfd) {
+			ret = -EINVAL;
+			pr_warn("failed to get primary FB bl handle, err = %d",
+									ret);
+			goto exit;
+		}
 	} else {
 		bl_mfd = mfd;
 	}
 
-
-	base = ad->base;
+	mdata = mfd_to_mdata(mfd);
 
 	mutex_lock(&ad->lock);
 	if (ad->sts != last_sts || ad->state != last_state) {
@@ -3222,17 +4009,17 @@
 				bl = ad->bl_lin[bl >> ad->bl_bright_shift];
 				bl = bl << ad->bl_bright_shift;
 			}
-			mutex_unlock(&bl_mfd->bl_lock);
+			ad->bl_data = bl;
 		}
-		mutex_unlock(&mfd->bl_lock);
-		pp_ad_input_write(ad, bl);
+		mutex_unlock(&bl_mfd->bl_lock);
+		ad->reg_sts |= PP_AD_STS_DIRTY_DATA;
 	}
 
 	if (ad->sts & PP_AD_STS_DIRTY_CFG) {
 		ad->sts &= ~PP_AD_STS_DIRTY_CFG;
 		ad->state |= PP_AD_STATE_CFG;
 
-		pp_ad_cfg_write(ad);
+		ad->reg_sts |= PP_AD_STS_DIRTY_CFG;
 
 		if (!MDSS_AD_MODE_DATA_MATCH(ad->cfg.mode, ad->ad_data_mode)) {
 			ad->sts &= ~PP_AD_STS_DIRTY_DATA;
@@ -3242,8 +4029,13 @@
 	}
 	if (ad->sts & PP_AD_STS_DIRTY_INIT) {
 		ad->sts &= ~PP_AD_STS_DIRTY_INIT;
-		ad->state |= PP_AD_STATE_INIT;
-		pp_ad_init_write(ad);
+		if (pp_ad_setup_hw_nums(mfd, ad)) {
+			pr_warn("failed to setup ad master");
+			ad->calc_hw_num = PP_AD_BAD_HW_NUM;
+		} else {
+			ad->state |= PP_AD_STATE_INIT;
+			ad->reg_sts |= PP_AD_STS_DIRTY_INIT;
+		}
 	}
 
 	/* update ad screen size if it has changed since last configuration */
@@ -3256,14 +4048,12 @@
 							ctl->height);
 		ad->init.frame_w = ctl->width;
 		ad->init.frame_h = ctl->height;
-		temp = ad->init.frame_w << 16;
-		temp |= ad->init.frame_h & 0xFFFF;
-		writel_relaxed(temp, base + MDSS_MDP_REG_AD_FRAME_SIZE);
+		ad->reg_sts |= PP_AD_STS_DIRTY_INIT;
 	}
 
 	if ((ad->sts & PP_STS_ENABLE) && PP_AD_STATE_IS_READY(ad->state)) {
 		bypass = 0;
-		ret = 1;
+		ad->reg_sts |= PP_AD_STS_DIRTY_ENABLE;
 		ad->state |= PP_AD_STATE_RUN;
 		mutex_lock(&bl_mfd->bl_lock);
 		if (bl_mfd != mfd)
@@ -3274,7 +4064,7 @@
 
 	} else {
 		if (ad->state & PP_AD_STATE_RUN) {
-			ret = 1;
+			ad->reg_sts = PP_AD_STS_DIRTY_ENABLE;
 			/* Clear state and regs when going to off state*/
 			ad->sts = 0;
 			ad->sts |= PP_AD_STS_DIRTY_VSYNC;
@@ -3287,6 +4077,7 @@
 			ad->ad_data_mode = 0;
 			ad->last_bl = 0;
 			ad->calc_itr = 0;
+			ad->calc_hw_num = PP_AD_BAD_HW_NUM;
 			memset(&ad->bl_lin, 0, sizeof(uint32_t) *
 								AD_BL_LIN_LEN);
 			memset(&ad->bl_lin_inv, 0, sizeof(uint32_t) *
@@ -3301,7 +4092,10 @@
 		}
 		ad->state &= ~PP_AD_STATE_RUN;
 	}
-	writel_relaxed(bypass, base);
+	if (!bypass)
+		ad->reg_sts |= PP_STS_ENABLE;
+	else
+		ad->reg_sts &= ~PP_STS_ENABLE;
 
 	if (PP_AD_STS_DIRTY_VSYNC & ad->sts) {
 		pr_debug("dirty vsync, calc_itr = %d", ad->calc_itr);
@@ -3324,6 +4118,7 @@
 								ad->state);
 	}
 	mutex_unlock(&ad->lock);
+exit:
 	return ret;
 }
 
@@ -3333,6 +4128,8 @@
 	struct mdss_ad_info *ad;
 	struct mdss_mdp_ctl *ctl;
 	struct msm_fb_data_type *mfd, *bl_mfd;
+	struct mdss_data_type *mdata;
+	char __iomem *base;
 	u32 bl, calc_done = 0;
 	ad = container_of(work, struct mdss_ad_info, calc_work);
 
@@ -3344,6 +4141,15 @@
 	mfd = ad->mfd;
 	bl_mfd = ad->bl_mfd;
 	ctl = mfd_to_ctl(ad->mfd);
+	mdata = mfd_to_mdata(ad->mfd);
+
+	if (!mdata || ad->calc_hw_num > mdata->nad_cfgs) {
+		mutex_unlock(&ad->lock);
+		return;
+	}
+
+
+	base = mdata->ad_off[ad->calc_hw_num].base;
 
 	if ((ad->cfg.mode == MDSS_AD_MODE_AUTO_STR) && (ad->last_bl == 0)) {
 		mutex_unlock(&ad->lock);
@@ -3353,20 +4159,20 @@
 	if (PP_AD_STATE_RUN & ad->state) {
 		/* Kick off calculation */
 		ad->calc_itr--;
-		writel_relaxed(1, ad->base + MDSS_MDP_REG_AD_START_CALC);
+		writel_relaxed(1, base + MDSS_MDP_REG_AD_START_CALC);
 	}
 	if (ad->state & PP_AD_STATE_RUN) {
 		do {
-			calc_done = readl_relaxed(ad->base +
+			calc_done = readl_relaxed(base +
 				MDSS_MDP_REG_AD_CALC_DONE);
 			if (!calc_done)
 				usleep(MDSS_PP_AD_SLEEP);
 		} while (!calc_done && (ad->state & PP_AD_STATE_RUN));
 		if (calc_done) {
-			ad->last_str = 0xFF & readl_relaxed(ad->base +
+			ad->last_str = 0xFF & readl_relaxed(base +
 						MDSS_MDP_REG_AD_STR_OUT);
 			if (MDSS_AD_RUNNING_AUTO_BL(ad)) {
-				bl = 0xFFFF & readl_relaxed(ad->base +
+				bl = 0xFFFF & readl_relaxed(base +
 						MDSS_MDP_REG_AD_BL_OUT);
 				if (ad->state & PP_AD_STATE_BL_LIN) {
 					bl = bl >> ad->bl_bright_shift;
@@ -3405,7 +4211,7 @@
 }
 
 #define PP_AD_LUT_LEN 33
-static void pp_ad_cfg_lut(char __iomem *offset, u32 *data)
+static void pp_ad_cfg_lut(char __iomem *addr, u32 *data)
 {
 	int i;
 	u32 temp;
@@ -3413,30 +4219,42 @@
 	for (i = 0; i < PP_AD_LUT_LEN - 1; i += 2) {
 		temp = data[i+1] << 16;
 		temp |= (data[i] & 0xFFFF);
-		writel_relaxed(temp, offset + (i*2));
+		writel_relaxed(temp, addr + (i*2));
 	}
 	writel_relaxed(data[PP_AD_LUT_LEN - 1] << 16,
-			offset + ((PP_AD_LUT_LEN - 1) * 2));
+			addr + ((PP_AD_LUT_LEN - 1) * 2));
 }
 
-int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_off)
+int mdss_mdp_ad_addr_setup(struct mdss_data_type *mdata, u32 *ad_offsets)
 {
 	u32 i;
 	int rc = 0;
 
-	mdata->ad_cfgs = devm_kzalloc(&mdata->pdev->dev,
-				sizeof(struct mdss_ad_info) * mdata->nad_cfgs,
+	mdata->ad_off = devm_kzalloc(&mdata->pdev->dev,
+				sizeof(struct mdss_mdp_ad) * mdata->nad_cfgs,
 				GFP_KERNEL);
 
+	if (!mdata->ad_off) {
+		pr_err("unable to setup assertive display hw:devm_kzalloc fail\n");
+		return -ENOMEM;
+	}
+
+	mdata->ad_cfgs = devm_kzalloc(&mdata->pdev->dev,
+			sizeof(struct mdss_ad_info) * mdata->nad_cfgs,
+			GFP_KERNEL);
+
 	if (!mdata->ad_cfgs) {
 		pr_err("unable to setup assertive display:devm_kzalloc fail\n");
+		devm_kfree(&mdata->pdev->dev, mdata->ad_off);
 		return -ENOMEM;
 	}
 
 	mdata->ad_calc_wq = create_singlethread_workqueue("ad_calc_wq");
 	for (i = 0; i < mdata->nad_cfgs; i++) {
-		mdata->ad_cfgs[i].base = mdata->mdp_base + ad_off[i];
+		mdata->ad_off[i].base = mdata->mdp_base + ad_offsets[i];
+		mdata->ad_off[i].num = i;
 		mdata->ad_cfgs[i].num = i;
+		mdata->ad_cfgs[i].reg_sts = 0;
 		mdata->ad_cfgs[i].calc_itr = 0;
 		mdata->ad_cfgs[i].last_str = 0xFFFFFFFF;
 		mdata->ad_cfgs[i].last_bl = 0;
@@ -3563,8 +4381,8 @@
 		return ret;
 	}
 
-	if (cfg->size == 0) {
-		pr_err("Invalid buffer size");
+	if (cfg->size == 0 || cfg->size > PAGE_SIZE) {
+		pr_err("Invalid buffer size %d", cfg->size);
 		return ret;
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index b680823..c3e1916 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -200,14 +200,20 @@
 		mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
 	}
 
-	if (isr & MDSS_MDP_INTR_WB_0_DONE)
+	if (isr & MDSS_MDP_INTR_WB_0_DONE) {
 		mdss_mdp_intr_done(MDP_INTR_WB_0);
+		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
+	}
 
-	if (isr & MDSS_MDP_INTR_WB_1_DONE)
+	if (isr & MDSS_MDP_INTR_WB_1_DONE) {
 		mdss_mdp_intr_done(MDP_INTR_WB_1);
+		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
+	}
 
-	if (isr & MDSS_MDP_INTR_WB_2_DONE)
+	if (isr & MDSS_MDP_INTR_WB_2_DONE) {
 		mdss_mdp_intr_done(MDP_INTR_WB_2);
+		mdss_misr_crc_collect(mdata, DISPLAY_MISR_MDP);
+	}
 
 mdp_isr_done:
 	hist_isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_HIST_INTR_STATUS);
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 81e803e..20b8446 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -55,6 +55,11 @@
 #define CLOCK_EVT_FEAT_C3STOP		0x000008
 #define CLOCK_EVT_FEAT_DUMMY		0x000010
 
+/*
+ * Core shall set the interrupt affinity dynamically in broadcast mode
+ */
+#define CLOCK_EVT_FEAT_DYNIRQ		0x000020
+
 /**
  * struct clock_event_device - clock event device descriptor
  * @event_handler:	Assigned by the framework to be called by the low
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 5ab7183..6b76dfd7 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -147,7 +147,9 @@
 extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
 extern int cpuidle_register_device(struct cpuidle_device *dev);
 extern void cpuidle_unregister_device(struct cpuidle_device *dev);
-
+extern int cpuidle_register(struct cpuidle_driver *drv,
+			    const struct cpumask *const coupled_cpus);
+extern void cpuidle_unregister(struct cpuidle_driver *drv);
 extern void cpuidle_pause_and_lock(void);
 extern void cpuidle_resume_and_unlock(void);
 extern int cpuidle_enable_device(struct cpuidle_device *dev);
@@ -168,7 +170,10 @@
 static inline int cpuidle_register_device(struct cpuidle_device *dev)
 {return -ENODEV; }
 static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
-
+static inline int cpuidle_register(struct cpuidle_driver *drv,
+				   const struct cpumask *const coupled_cpus)
+{return -ENODEV; }
+static inline void cpuidle_unregister(struct cpuidle_driver *drv) { }
 static inline void cpuidle_pause_and_lock(void) { }
 static inline void cpuidle_resume_and_unlock(void) { }
 static inline int cpuidle_enable_device(struct cpuidle_device *dev)
diff --git a/include/linux/kref.h b/include/linux/kref.h
index aa5acc26..6f515f2 100644
--- a/include/linux/kref.h
+++ b/include/linux/kref.h
@@ -18,6 +18,7 @@
 #include <linux/bug.h>
 #include <linux/atomic.h>
 #include <linux/kernel.h>
+#include <linux/mutex.h>
 
 struct kref {
 	atomic_t refcount;
@@ -94,6 +95,23 @@
 	return kref_sub(kref, 1, release);
 }
 
+static inline int kref_put_mutex(struct kref *kref,
+				 void (*release)(struct kref *kref),
+				 struct mutex *lock)
+{
+	WARN_ON(release == NULL);
+        if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) {
+		mutex_lock(lock);
+		if (unlikely(!atomic_dec_and_test(&kref->refcount))) {
+			mutex_unlock(lock);
+			return 0;
+		}
+		release(kref);
+		return 1;
+	}
+	return 0;
+}
+
 
 /**
  * kref_get_unless_zero - Increment refcount for object unless it is zero.
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 3067df8..a691330 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -320,6 +320,27 @@
 #define MDP_PP_IGC_FLAG_ROM0	0x10
 #define MDP_PP_IGC_FLAG_ROM1	0x20
 
+#define MDP_PP_PA_HUE_ENABLE		0x10
+#define MDP_PP_PA_SAT_ENABLE		0x20
+#define MDP_PP_PA_VAL_ENABLE		0x40
+#define MDP_PP_PA_CONT_ENABLE		0x80
+#define MDP_PP_PA_SIX_ZONE_ENABLE	0x100
+#define MDP_PP_PA_SKIN_ENABLE		0x200
+#define MDP_PP_PA_SKY_ENABLE		0x400
+#define MDP_PP_PA_FOL_ENABLE		0x800
+#define MDP_PP_PA_HUE_MASK		0x1000
+#define MDP_PP_PA_SAT_MASK		0x2000
+#define MDP_PP_PA_VAL_MASK		0x4000
+#define MDP_PP_PA_CONT_MASK		0x8000
+#define MDP_PP_PA_SIX_ZONE_HUE_MASK	0x10000
+#define MDP_PP_PA_SIX_ZONE_SAT_MASK	0x20000
+#define MDP_PP_PA_SIX_ZONE_VAL_MASK	0x40000
+#define MDP_PP_PA_MEM_COL_SKIN_MASK	0x80000
+#define MDP_PP_PA_MEM_COL_SKY_MASK	0x100000
+#define MDP_PP_PA_MEM_COL_FOL_MASK	0x200000
+#define MDP_PP_PA_MEM_PROTECT_EN	0x400000
+#define MDP_PP_PA_SAT_ZERO_EXP_EN	0x800000
+
 #define MDSS_PP_DSPP_CFG	0x000
 #define MDSS_PP_SSPP_CFG	0x100
 #define MDSS_PP_LM_CFG	0x200
@@ -364,6 +385,7 @@
 #define MDP_OVERLAY_PP_SHARP_CFG       0x10
 #define MDP_OVERLAY_PP_HIST_CFG        0x20
 #define MDP_OVERLAY_PP_HIST_LUT_CFG    0x40
+#define MDP_OVERLAY_PP_PA_V2_CFG       0x80
 
 #define MDP_CSC_FLAG_ENABLE	0x1
 #define MDP_CSC_FLAG_YUV_IN	0x2
@@ -392,6 +414,31 @@
 	uint32_t cont_adj;
 };
 
+struct mdp_pa_mem_col_cfg {
+	uint32_t color_adjust_p0;
+	uint32_t color_adjust_p1;
+	uint32_t hue_region;
+	uint32_t sat_region;
+	uint32_t val_region;
+};
+
+#define MDP_SIX_ZONE_TABLE_NUM		384
+
+struct mdp_pa_v2_data {
+	/* Mask bits for PA features */
+	uint32_t flags;
+	uint32_t global_hue_adj;
+	uint32_t global_sat_adj;
+	uint32_t global_val_adj;
+	uint32_t global_cont_adj;
+	uint32_t *six_zone_curve_p0;
+	uint32_t *six_zone_curve_p1;
+	uint32_t six_zone_thresh;
+	struct mdp_pa_mem_col_cfg skin_cfg;
+	struct mdp_pa_mem_col_cfg sky_cfg;
+	struct mdp_pa_mem_col_cfg fol_cfg;
+};
+
 struct mdp_igc_lut_data {
 	uint32_t block;
 	uint32_t len, ops;
@@ -419,6 +466,7 @@
 	struct mdp_csc_cfg csc_cfg;
 	struct mdp_qseed_cfg qseed_cfg[2];
 	struct mdp_pa_cfg pa_cfg;
+	struct mdp_pa_v2_data pa_v2_cfg;
 	struct mdp_igc_lut_data igc_cfg;
 	struct mdp_sharp_cfg sharp_cfg;
 	struct mdp_histogram_cfg hist_cfg;
@@ -565,19 +613,21 @@
 	uint32_t *b;
 };
 
+#define MISR_CRC_BATCH_SIZE 32
 enum {
-	DISPLAY_MISR_EDP,
+	DISPLAY_MISR_EDP = 0,
 	DISPLAY_MISR_DSI0,
 	DISPLAY_MISR_DSI1,
 	DISPLAY_MISR_HDMI,
 	DISPLAY_MISR_LCDC,
+	DISPLAY_MISR_MDP,
 	DISPLAY_MISR_ATV,
 	DISPLAY_MISR_DSI_CMD,
 	DISPLAY_MISR_MAX
 };
 
 enum {
-	MISR_OP_NONE,
+	MISR_OP_NONE = 0,
 	MISR_OP_SFM,
 	MISR_OP_MFM,
 	MISR_OP_BM,
@@ -588,7 +638,7 @@
 	uint32_t block_id;
 	uint32_t frame_count;
 	uint32_t crc_op_mode;
-	uint32_t crc_value[32];
+	uint32_t crc_value[MISR_CRC_BATCH_SIZE];
 };
 
 /*
@@ -704,6 +754,11 @@
 	struct mdp_pa_cfg pa_data;
 };
 
+struct mdp_pa_v2_cfg_data {
+	uint32_t block;
+	struct mdp_pa_v2_data pa_v2_data;
+};
+
 struct mdp_dither_cfg_data {
 	uint32_t block;
 	uint32_t flags;
@@ -832,6 +887,7 @@
 	mdp_op_qseed_cfg,
 	mdp_bl_scale_cfg,
 	mdp_op_pa_cfg,
+	mdp_op_pa_v2_cfg,
 	mdp_op_dither_cfg,
 	mdp_op_gamut_cfg,
 	mdp_op_calib_cfg,
@@ -863,6 +919,7 @@
 		struct mdp_qseed_cfg_data qseed_cfg_data;
 		struct mdp_bl_scale_data bl_scale_data;
 		struct mdp_pa_cfg_data pa_cfg_data;
+		struct mdp_pa_v2_cfg_data pa_v2_cfg_data;
 		struct mdp_dither_cfg_data dither_cfg_data;
 		struct mdp_gamut_cfg_data gamut_cfg_data;
 		struct mdp_calib_config_data calib_cfg;
diff --git a/include/linux/sensors.h b/include/linux/sensors.h
index d5b140c..3520034 100644
--- a/include/linux/sensors.h
+++ b/include/linux/sensors.h
@@ -17,6 +17,36 @@
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
 
+#define SENSORS_ACCELERATION_HANDLE		0
+#define SENSORS_MAGNETIC_FIELD_HANDLE		1
+#define SENSORS_ORIENTATION_HANDLE		2
+#define SENSORS_LIGHT_HANDLE			3
+#define SENSORS_PROXIMITY_HANDLE		4
+#define SENSORS_GYROSCOPE_HANDLE		5
+#define SENSORS_PRESSURE_HANDLE			6
+
+#define SENSOR_TYPE_ACCELEROMETER		1
+#define SENSOR_TYPE_GEOMAGNETIC_FIELD		2
+#define SENSOR_TYPE_MAGNETIC_FIELD  SENSOR_TYPE_GEOMAGNETIC_FIELD
+#define SENSOR_TYPE_ORIENTATION			3
+#define SENSOR_TYPE_GYROSCOPE			4
+#define SENSOR_TYPE_LIGHT			5
+#define SENSOR_TYPE_PRESSURE			6
+#define SENSOR_TYPE_TEMPERATURE			7
+#define SENSOR_TYPE_PROXIMITY			8
+#define SENSOR_TYPE_GRAVITY			9
+#define SENSOR_TYPE_LINEAR_ACCELERATION		10
+#define SENSOR_TYPE_ROTATION_VECTOR		11
+#define SENSOR_TYPE_RELATIVE_HUMIDITY		12
+#define SENSOR_TYPE_AMBIENT_TEMPERATURE		13
+#define SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED	14
+#define SENSOR_TYPE_GAME_ROTATION_VECTOR	15
+#define SENSOR_TYPE_GYROSCOPE_UNCALIBRATED	16
+#define SENSOR_TYPE_SIGNIFICANT_MOTION		17
+#define SENSOR_TYPE_STEP_DETECTOR		18
+#define SENSOR_TYPE_STEP_COUNTER		19
+#define SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR	20
+
 struct sensors_classdev {
 	struct device		*dev;
 	struct list_head	 node;
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 494a314..dc15221 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -8,6 +8,7 @@
 
 #include <linux/clockchips.h>
 #include <linux/irqflags.h>
+#include <linux/hrtimer.h>
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 868be9f..ef7d118 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -93,6 +93,27 @@
 	unsigned int num_panscan_windows;
 	struct msm_vidc_panscan_window wnd[1];
 };
+struct msm_vidc_s3d_frame_packing_payload {
+	unsigned int fpa_id;
+	unsigned int cancel_flag;
+	unsigned int fpa_type;
+	unsigned int quin_cunx_flag;
+	unsigned int content_interprtation_type;
+	unsigned int spatial_flipping_flag;
+	unsigned int frame0_flipped_flag;
+	unsigned int field_views_flag;
+	unsigned int current_frame_is_frame0_flag;
+	unsigned int frame0_self_contained_flag;
+	unsigned int frame1_self_contained_flag;
+	unsigned int frame0_graid_pos_x;
+	unsigned int frame0_graid_pos_y;
+	unsigned int frame1_graid_pos_x;
+	unsigned int frame1_graid_pos_y;
+	unsigned int fpa_reserved_byte;
+	unsigned int fpa_repetition_period;
+	unsigned int fpa_extension_flag;
+};
+
 enum msm_vidc_extradata_type {
 	EXTRADATA_NONE = 0x00000000,
 	EXTRADATA_MB_QUANTIZATION = 0x00000001,
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 7b0ad14..568a3fa 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -152,6 +152,7 @@
 enum msm_vfe_axi_stream_cmd {
 	STOP_STREAM,
 	START_STREAM,
+	STOP_IMMEDIATELY,
 };
 
 struct msm_vfe_axi_stream_cfg_cmd {
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index b62a759..75fe3a2 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6279,6 +6279,206 @@
 #define VOICE_CMD_GET_PARAM				0x0001133E
 #define VOICE_EVT_GET_PARAM_ACK				0x00011008
 
+
+/** ID of the Bass Boost module.
+    This module supports the following parameter IDs:
+    - #AUDPROC_PARAM_ID_BASS_BOOST_ENABLE
+    - #AUDPROC_PARAM_ID_BASS_BOOST_MODE
+    - #AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH
+*/
+#define AUDPROC_MODULE_ID_BASS_BOOST                             0x000108A1
+/** ID of the Bass Boost enable parameter used by
+    AUDPROC_MODULE_ID_BASS_BOOST.
+*/
+#define AUDPROC_PARAM_ID_BASS_BOOST_ENABLE                       0x000108A2
+/** ID of the Bass Boost mode parameter used by
+    AUDPROC_MODULE_ID_BASS_BOOST.
+*/
+#define AUDPROC_PARAM_ID_BASS_BOOST_MODE                         0x000108A3
+/** ID of the Bass Boost strength parameter used by
+    AUDPROC_MODULE_ID_BASS_BOOST.
+*/
+#define AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH                     0x000108A4
+
+/** ID of the Virtualizer module. This module supports the
+    following parameter IDs:
+    - #AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE
+    - #AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH
+    - #AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE
+    - #AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST
+*/
+#define AUDPROC_MODULE_ID_VIRTUALIZER                            0x000108A5
+/** ID of the Virtualizer enable parameter used by
+    AUDPROC_MODULE_ID_VIRTUALIZER.
+*/
+#define AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE                      0x000108A6
+/** ID of the Virtualizer strength parameter used by
+    AUDPROC_MODULE_ID_VIRTUALIZER.
+*/
+#define AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH                    0x000108A7
+/** ID of the Virtualizer out type parameter used by
+    AUDPROC_MODULE_ID_VIRTUALIZER.
+*/
+#define AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE                    0x000108A8
+/** ID of the Virtualizer out type parameter used by
+    AUDPROC_MODULE_ID_VIRTUALIZER.
+*/
+#define AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST                 0x000108A9
+
+/** ID of the Reverb module. This module supports the following
+    parameter IDs:
+    - #AUDPROC_PARAM_ID_REVERB_ENABLE
+    - #AUDPROC_PARAM_ID_REVERB_MODE
+    - #AUDPROC_PARAM_ID_REVERB_PRESET
+    - #AUDPROC_PARAM_ID_REVERB_WET_MIX
+    - #AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST
+    - #AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL
+    - #AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL
+    - #AUDPROC_PARAM_ID_REVERB_DECAY_TIME
+    - #AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO
+    - #AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL
+    - #AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY
+    - #AUDPROC_PARAM_ID_REVERB_LEVEL
+    - #AUDPROC_PARAM_ID_REVERB_DELAY
+    - #AUDPROC_PARAM_ID_REVERB_DIFFUSION
+    - #AUDPROC_PARAM_ID_REVERB_DENSITY
+*/
+#define AUDPROC_MODULE_ID_REVERB                          0x000108AA
+/** ID of the Reverb enable parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_ENABLE                    0x000108AB
+/** ID of the Reverb mode parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_MODE                      0x000108AC
+/** ID of the Reverb preset parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_PRESET                    0x000108AD
+/** ID of the Reverb wet mix parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_WET_MIX                   0x000108AE
+/** ID of the Reverb gain adjust parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST               0x000108AF
+/** ID of the Reverb room level parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL                0x000108B0
+/** ID of the Reverb room hf level parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL             0x000108B1
+/** ID of the Reverb decay time parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DECAY_TIME                0x000108B2
+/** ID of the Reverb decay hf ratio parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO            0x000108B3
+/** ID of the Reverb reflections level parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL         0x000108B4
+/** ID of the Reverb reflections delay parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY         0x000108B5
+/** ID of the Reverb level parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_LEVEL                      0x000108B6
+/** ID of the Reverb delay parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DELAY                      0x000108B7
+/** ID of the Reverb diffusion parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DIFFUSION                  0x000108B8
+/** ID of the Reverb density parameter used by
+    AUDPROC_MODULE_ID_REVERB.
+*/
+#define AUDPROC_PARAM_ID_REVERB_DENSITY                    0x000108B9
+
+/** ID of the Popless Equalizer module. This module supports the
+    following parameter IDs:
+    - #AUDPROC_PARAM_ID_EQ_ENABLE
+    - #AUDPROC_PARAM_ID_EQ_CONFIG
+    - #AUDPROC_PARAM_ID_EQ_NUM_BANDS
+    - #AUDPROC_PARAM_ID_EQ_BAND_LEVELS
+    - #AUDPROC_PARAM_ID_EQ_BAND_LEVEL_RANGE
+    - #AUDPROC_PARAM_ID_EQ_BAND_FREQS
+    - #AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ_RANGE
+    - #AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ
+    - #AUDPROC_PARAM_ID_EQ_BAND_INDEX
+    - #AUDPROC_PARAM_ID_EQ_PRESET_ID
+    - #AUDPROC_PARAM_ID_EQ_NUM_PRESETS
+    - #AUDPROC_PARAM_ID_EQ_GET_PRESET_NAME
+*/
+#define AUDPROC_MODULE_ID_POPLESS_EQUALIZER                    0x000108BA
+/** ID of the Popless Equalizer enable parameter used by
+    AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+*/
+#define AUDPROC_PARAM_ID_EQ_ENABLE                             0x000108BB
+/** ID of the Popless Equalizer config parameter used by
+    AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+*/
+#define AUDPROC_PARAM_ID_EQ_CONFIG                             0x000108BC
+/** ID of the Popless Equalizer number of bands parameter used
+    by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+    used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_NUM_BANDS                          0x000108BD
+/** ID of the Popless Equalizer band levels parameter used by
+    AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+    used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_BAND_LEVELS                        0x000108BE
+/** ID of the Popless Equalizer band level range parameter used
+    by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+    used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_BAND_LEVEL_RANGE                   0x000108BF
+/** ID of the Popless Equalizer band frequencies parameter used
+    by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is
+    used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_BAND_FREQS                         0x000108C0
+/** ID of the Popless Equalizer single band frequency range
+    parameter used by AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+    This param ID is used for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ_RANGE             0x000108C1
+/** ID of the Popless Equalizer single band frequency parameter
+    used by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID
+    is used for set param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ                   0x000108C2
+/** ID of the Popless Equalizer band index parameter used by
+    AUDPROC_MODULE_ID_POPLESS_EQUALIZER.
+*/
+#define AUDPROC_PARAM_ID_EQ_BAND_INDEX                         0x000108C3
+/** ID of the Popless Equalizer preset id parameter used by
+    AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+    for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_PRESET_ID                          0x000108C4
+/** ID of the Popless Equalizer number of presets parameter used
+    by AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+    for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_NUM_PRESETS                        0x000108C5
+/** ID of the Popless Equalizer preset name parameter used by
+    AUDPROC_MODULE_ID_POPLESS_EQUALIZER. This param ID is used
+    for get param only.
+*/
+#define AUDPROC_PARAM_ID_EQ_PRESET_NAME                        0x000108C6
+
 /* Set Q6 topologies */
 #define ASM_CMD_ADD_TOPOLOGIES				0x00010DBE
 #define ADM_CMD_ADD_TOPOLOGIES				0x00010335
diff --git a/include/sound/audio_effects.h b/include/sound/audio_effects.h
new file mode 100644
index 0000000..3444477
--- /dev/null
+++ b/include/sound/audio_effects.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _AUDIO_EFFECTS_H
+#define _AUDIO_EFFECTS_H
+
+/** AUDIO EFFECTS **/
+
+
+/* CONFIG GET/SET */
+#define CONFIG_CACHE			0
+#define CONFIG_SET			1
+#define CONFIG_GET			2
+
+/* CONFIG HEADER */
+/*
+
+	MODULE_ID,
+	DEVICE,
+	NUM_COMMANDS,
+	COMMAND_ID_1,
+	CONFIG_CACHE/SET/GET,
+	OFFSET_1,
+	LENGTH_1,
+	VALUES_1,
+	...,
+	...,
+	COMMAND_ID_2,
+	CONFIG_CACHE/SET/GET,
+	OFFSET_2,
+	LENGTH_2,
+	VALUES_2,
+	...,
+	...,
+	COMMAND_ID_3,
+	...
+*/
+
+
+/* CONFIG PARAM IDs */
+#define VIRTUALIZER_MODULE		0x00001000
+#define VIRTUALIZER_ENABLE		0x00001001
+#define VIRTUALIZER_STRENGTH		0x00001002
+#define VIRTUALIZER_OUT_TYPE		0x00001003
+#define VIRTUALIZER_GAIN_ADJUST		0x00001004
+#define VIRTUALIZER_ENABLE_PARAM_LEN		1
+#define VIRTUALIZER_STRENGTH_PARAM_LEN		1
+#define VIRTUALIZER_OUT_TYPE_PARAM_LEN		1
+#define VIRTUALIZER_GAIN_ADJUST_PARAM_LEN	1
+
+#define REVERB_MODULE			0x00002000
+#define REVERB_ENABLE			0x00002001
+#define REVERB_MODE			0x00002002
+#define REVERB_PRESET			0x00002003
+#define REVERB_WET_MIX			0x00002004
+#define REVERB_GAIN_ADJUST		0x00002005
+#define REVERB_ROOM_LEVEL		0x00002006
+#define REVERB_ROOM_HF_LEVEL		0x00002007
+#define REVERB_DECAY_TIME		0x00002008
+#define REVERB_DECAY_HF_RATIO		0x00002009
+#define REVERB_REFLECTIONS_LEVEL	0x0000200a
+#define REVERB_REFLECTIONS_DELAY	0x0000200b
+#define REVERB_LEVEL			0x0000200c
+#define REVERB_DELAY			0x0000200d
+#define REVERB_DIFFUSION		0x0000200e
+#define REVERB_DENSITY			0x0000200f
+#define REVERB_ENABLE_PARAM_LEN			1
+#define REVERB_MODE_PARAM_LEN			1
+#define REVERB_PRESET_PARAM_LEN			1
+#define REVERB_WET_MIX_PARAM_LEN		1
+#define REVERB_GAIN_ADJUST_PARAM_LEN		1
+#define REVERB_ROOM_LEVEL_PARAM_LEN		1
+#define REVERB_ROOM_HF_LEVEL_PARAM_LEN		1
+#define REVERB_DECAY_TIME_PARAM_LEN		1
+#define REVERB_DECAY_HF_RATIO_PARAM_LEN		1
+#define REVERB_REFLECTIONS_LEVEL_PARAM_LEN	1
+#define REVERB_REFLECTIONS_DELAY_PARAM_LEN	1
+#define REVERB_LEVEL_PARAM_LEN			1
+#define REVERB_DELAY_PARAM_LEN			1
+#define REVERB_DIFFUSION_PARAM_LEN		1
+#define REVERB_DENSITY_PARAM_LEN		1
+
+#define BASS_BOOST_MODULE		0x00003000
+#define BASS_BOOST_ENABLE		0x00003001
+#define BASS_BOOST_MODE			0x00003002
+#define BASS_BOOST_STRENGTH		0x00003003
+#define BASS_BOOST_ENABLE_PARAM_LEN		1
+#define BASS_BOOST_MODE_PARAM_LEN		1
+#define BASS_BOOST_STRENGTH_PARAM_LEN		1
+
+#define EQ_MODULE			0x00004000
+#define EQ_ENABLE			0x00004001
+#define EQ_CONFIG			0x00004002
+#define EQ_NUM_BANDS			0x00004003
+#define EQ_BAND_LEVELS			0x00004004
+#define EQ_BAND_LEVEL_RANGE		0x00004005
+#define EQ_BAND_FREQS			0x00004006
+#define EQ_SINGLE_BAND_FREQ_RANGE	0x00004007
+#define EQ_SINGLE_BAND_FREQ		0x00004008
+#define EQ_BAND_INDEX			0x00004009
+#define EQ_PRESET_ID			0x0000400a
+#define EQ_NUM_PRESETS			0x0000400b
+#define EQ_PRESET_NAME			0x0000400c
+#define EQ_ENABLE_PARAM_LEN			1
+#define EQ_CONFIG_PARAM_LEN			3
+#define EQ_CONFIG_PER_BAND_PARAM_LEN		5
+#define EQ_NUM_BANDS_PARAM_LEN			1
+#define EQ_BAND_LEVELS_PARAM_LEN		13
+#define EQ_BAND_LEVEL_RANGE_PARAM_LEN		2
+#define EQ_BAND_FREQS_PARAM_LEN			13
+#define EQ_SINGLE_BAND_FREQ_RANGE_PARAM_LEN	2
+#define EQ_SINGLE_BAND_FREQ_PARAM_LEN		1
+#define EQ_BAND_INDEX_PARAM_LEN			1
+#define EQ_PRESET_ID_PARAM_LEN			1
+#define EQ_NUM_PRESETS_PARAM_LEN		1
+#define EQ_PRESET_NAME_PARAM_LEN		32
+
+#define EQ_TYPE_NONE	0
+#define EQ_BASS_BOOST	1
+#define EQ_BASS_CUT	2
+#define EQ_TREBLE_BOOST	3
+#define EQ_TREBLE_CUT	4
+#define EQ_BAND_BOOST	5
+#define EQ_BAND_CUT	6
+
+
+
+#define COMMAND_PAYLOAD_LEN	3
+#define COMMAND_PAYLOAD_SZ	(COMMAND_PAYLOAD_LEN * sizeof(uint32_t))
+#define MAX_INBAND_PARAM_SZ	4096
+#define Q27_UNITY		(1 << 27)
+#define Q8_UNITY		(1 << 8)
+#define CUSTOM_OPENSL_PRESET	18
+
+#define VIRTUALIZER_ENABLE_PARAM_SZ	\
+			(VIRTUALIZER_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_STRENGTH_PARAM_SZ	\
+			(VIRTUALIZER_STRENGTH_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_OUT_TYPE_PARAM_SZ	\
+			(VIRTUALIZER_OUT_TYPE_PARAM_LEN*sizeof(uint32_t))
+#define VIRTUALIZER_GAIN_ADJUST_PARAM_SZ	\
+			(VIRTUALIZER_GAIN_ADJUST_PARAM_LEN*sizeof(uint32_t))
+struct virtualizer_params {
+	uint32_t device;
+	uint32_t enable_flag;
+	uint32_t strength;
+	uint32_t out_type;
+	int32_t gain_adjust;
+};
+
+#define NUM_OSL_REVERB_PRESETS_SUPPORTED	6
+#define REVERB_ENABLE_PARAM_SZ		\
+			(REVERB_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_MODE_PARAM_SZ		\
+			(REVERB_MODE_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_PRESET_PARAM_SZ		\
+			(REVERB_PRESET_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_WET_MIX_PARAM_SZ		\
+			(REVERB_WET_MIX_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_GAIN_ADJUST_PARAM_SZ	\
+			(REVERB_GAIN_ADJUST_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_ROOM_LEVEL_PARAM_SZ	\
+			(REVERB_ROOM_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_ROOM_HF_LEVEL_PARAM_SZ	\
+			(REVERB_ROOM_HF_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DECAY_TIME_PARAM_SZ	\
+			(REVERB_DECAY_TIME_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DECAY_HF_RATIO_PARAM_SZ	\
+			(REVERB_DECAY_HF_RATIO_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_REFLECTIONS_LEVEL_PARAM_SZ	\
+			(REVERB_REFLECTIONS_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_REFLECTIONS_DELAY_PARAM_SZ	\
+			(REVERB_REFLECTIONS_DELAY_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_LEVEL_PARAM_SZ		\
+			(REVERB_LEVEL_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DELAY_PARAM_SZ		\
+			(REVERB_DELAY_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DIFFUSION_PARAM_SZ	\
+			(REVERB_DIFFUSION_PARAM_LEN*sizeof(uint32_t))
+#define REVERB_DENSITY_PARAM_SZ		\
+			(REVERB_DENSITY_PARAM_LEN*sizeof(uint32_t))
+struct reverb_params {
+	uint32_t device;
+	uint32_t enable_flag;
+	uint32_t mode;
+	uint32_t preset;
+	uint32_t wet_mix;
+	int32_t  gain_adjust;
+	int32_t  room_level;
+	int32_t  room_hf_level;
+	uint32_t decay_time;
+	uint32_t decay_hf_ratio;
+	int32_t  reflections_level;
+	uint32_t reflections_delay;
+	int32_t  level;
+	uint32_t delay;
+	uint32_t diffusion;
+	uint32_t density;
+};
+
+#define BASS_BOOST_ENABLE_PARAM_SZ	\
+			(BASS_BOOST_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define BASS_BOOST_MODE_PARAM_SZ	\
+			(BASS_BOOST_MODE_PARAM_LEN*sizeof(uint32_t))
+#define BASS_BOOST_STRENGTH_PARAM_SZ	\
+			(BASS_BOOST_STRENGTH_PARAM_LEN*sizeof(uint32_t))
+struct bass_boost_params {
+	uint32_t device;
+	uint32_t enable_flag;
+	uint32_t mode;
+	uint32_t strength;
+};
+
+
+#define MAX_EQ_BANDS 12
+#define MAX_OSL_EQ_BANDS 5
+#define EQ_ENABLE_PARAM_SZ			\
+			(EQ_ENABLE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PARAM_SZ			\
+			(EQ_CONFIG_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PER_BAND_PARAM_SZ		\
+			(EQ_CONFIG_PER_BAND_PARAM_LEN*sizeof(uint32_t))
+#define EQ_CONFIG_PARAM_MAX_LEN			(EQ_CONFIG_PARAM_LEN+\
+			MAX_EQ_BANDS*EQ_CONFIG_PER_BAND_PARAM_LEN)
+#define EQ_CONFIG_PARAM_MAX_SZ			\
+			(EQ_CONFIG_PARAM_MAX_LEN*sizeof(uint32_t))
+#define EQ_NUM_BANDS_PARAM_SZ			\
+			(EQ_NUM_BANDS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_LEVELS_PARAM_SZ			\
+			(EQ_BAND_LEVELS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_LEVEL_RANGE_PARAM_SZ		\
+			(EQ_BAND_LEVEL_RANGE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_FREQS_PARAM_SZ			\
+			(EQ_BAND_FREQS_PARAM_LEN*sizeof(uint32_t))
+#define EQ_SINGLE_BAND_FREQ_RANGE_PARAM_SZ	\
+			(EQ_SINGLE_BAND_FREQ_RANGE_PARAM_LEN*sizeof(uint32_t))
+#define EQ_SINGLE_BAND_FREQ_PARAM_SZ		\
+			(EQ_SINGLE_BAND_FREQ_PARAM_LEN*sizeof(uint32_t))
+#define EQ_BAND_INDEX_PARAM_SZ			\
+			(EQ_BAND_INDEX_PARAM_LEN*sizeof(uint32_t))
+#define EQ_PRESET_ID_PARAM_SZ			\
+			(EQ_PRESET_ID_PARAM_LEN*sizeof(uint32_t))
+#define EQ_NUM_PRESETS_PARAM_SZ			\
+			(EQ_NUM_PRESETS_PARAM_LEN*sizeof(uint8_t))
+struct eq_config_t {
+	int32_t eq_pregain;
+	int32_t preset_id;
+	uint32_t num_bands;
+};
+struct eq_per_band_config_t {
+	int32_t band_idx;
+	uint32_t filter_type;
+	uint32_t freq_millihertz;
+	int32_t  gain_millibels;
+	uint32_t quality_factor;
+};
+struct eq_per_band_freq_range_t {
+	uint32_t band_index;
+	uint32_t min_freq_millihertz;
+	uint32_t max_freq_millihertz;
+};
+
+struct eq_params {
+	uint32_t device;
+	uint32_t enable_flag;
+	struct eq_config_t config;
+	struct eq_per_band_config_t per_band_cfg[MAX_EQ_BANDS];
+	struct eq_per_band_freq_range_t per_band_freq_range[MAX_EQ_BANDS];
+	uint32_t band_index;
+	uint32_t freq_millihertz;
+};
+
+#endif /*_MSM_AUDIO_EFFECTS_H*/
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index eb3b41a..9a459b8 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -377,6 +377,9 @@
 
 int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp);
 
+int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
+				    uint32_t params_length);
+
 /* Client can set the IO mode to either AIO/SIO mode */
 int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
 
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index f113755..d6d0d41 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -370,14 +370,34 @@
 	return to_cpumask(tick_broadcast_oneshot_mask);
 }
 
-static int tick_broadcast_set_event(ktime_t expires, int force)
+/*
+ * Set broadcast interrupt affinity
+ */
+static void tick_broadcast_set_affinity(struct clock_event_device *bc,
+					const struct cpumask *cpumask)
 {
-	struct clock_event_device *bc = tick_broadcast_device.evtdev;
+	if (!(bc->features & CLOCK_EVT_FEAT_DYNIRQ))
+		return;
+
+	if (cpumask_equal(bc->cpumask, cpumask))
+		return;
+
+	bc->cpumask = cpumask;
+	irq_set_affinity(bc->irq, bc->cpumask);
+}
+
+static int tick_broadcast_set_event(struct clock_event_device *bc, int cpu,
+				    ktime_t expires, int force)
+{
+	int ret;
 
 	if (bc->mode != CLOCK_EVT_MODE_ONESHOT)
 		clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
 
-	return clockevents_program_event(bc, expires, force);
+	ret = clockevents_program_event(bc, expires, force);
+	if (!ret)
+		tick_broadcast_set_affinity(bc, cpumask_of(cpu));
+	return ret;
 }
 
 int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
@@ -406,7 +426,7 @@
 {
 	struct tick_device *td;
 	ktime_t now, next_event;
-	int cpu;
+	int cpu, next_cpu = 0;
 
 	raw_spin_lock(&tick_broadcast_lock);
 again:
@@ -417,10 +437,12 @@
 	/* Find all expired events */
 	for_each_cpu(cpu, tick_get_broadcast_oneshot_mask()) {
 		td = &per_cpu(tick_cpu_device, cpu);
-		if (td->evtdev->next_event.tv64 <= now.tv64)
+		if (td->evtdev->next_event.tv64 <= now.tv64) {
 			cpumask_set_cpu(cpu, to_cpumask(tmpmask));
-		else if (td->evtdev->next_event.tv64 < next_event.tv64)
+		} else if (td->evtdev->next_event.tv64 < next_event.tv64) {
 			next_event.tv64 = td->evtdev->next_event.tv64;
+			next_cpu = cpu;
+		}
 	}
 
 	/*
@@ -443,7 +465,7 @@
 		 * Rearm the broadcast device. If event expired,
 		 * repeat the above
 		 */
-		if (tick_broadcast_set_event(next_event, 0))
+		if (tick_broadcast_set_event(dev, next_cpu, next_event, 0))
 			goto again;
 	}
 	raw_spin_unlock(&tick_broadcast_lock);
@@ -486,7 +508,7 @@
 			cpumask_set_cpu(cpu, tick_get_broadcast_oneshot_mask());
 			clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
 			if (dev->next_event.tv64 < bc->next_event.tv64)
-				tick_broadcast_set_event(dev->next_event, 1);
+				tick_broadcast_set_event(bc, cpu, dev->next_event, 1);
 		}
 	} else {
 		if (cpumask_test_cpu(cpu, tick_get_broadcast_oneshot_mask())) {
@@ -555,7 +577,7 @@
 			clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
 			tick_broadcast_init_next_event(to_cpumask(tmpmask),
 						       tick_next_period);
-			tick_broadcast_set_event(tick_next_period, 1);
+			tick_broadcast_set_event(bc, cpu, tick_next_period, 1);
 		} else
 			bc->next_event.tv64 = KTIME_MAX;
 	} else {
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 8daa015..f8e9d7a 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -612,9 +612,10 @@
 static inline int
 snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
 {
-	struct snd_compr_tstamp tstamp = {0};
+	struct snd_compr_tstamp tstamp;
 	int ret;
 
+	memset(&tstamp, 0, sizeof(tstamp));
 	ret = snd_compr_update_tstamp(stream, &tstamp);
 	if (ret == 0)
 		ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index aaa132e..caae9c6 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -1829,6 +1829,7 @@
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_codec *codec = w->codec;
+	struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
 	u16 adc_reg;
 	u8 init_bit_shift;
 
@@ -1856,6 +1857,9 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
+		if (w->reg == TAPAN_A_TX_3_EN)
+			wcd9xxx_resmgr_notifier_call(&tapan->resmgr,
+						WCD9XXX_EVENT_PRE_TX_3_ON);
 		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
 				1 << init_bit_shift);
 		break;
@@ -1864,6 +1868,11 @@
 		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
 
 		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (w->reg == TAPAN_A_TX_3_EN)
+			wcd9xxx_resmgr_notifier_call(&tapan->resmgr,
+						WCD9XXX_EVENT_POST_TX_3_OFF);
+		break;
 	}
 	return 0;
 }
@@ -2847,7 +2856,7 @@
 
 	{"DAC1", "Switch", "CLASS_H_DSM MUX"},
 	{"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
-	{"HPHR DAC", NULL, "RX2 CHAIN"},
+	{"HPHR DAC", NULL, "RDAC3 MUX"},
 
 	{"LINEOUT1", NULL, "LINEOUT1 PA"},
 	{"LINEOUT2", NULL, "LINEOUT2 PA"},
@@ -2858,11 +2867,14 @@
 	{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
 	{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
 
-	{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
 
 	{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
 	{"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
 
+	{"RDAC4 MUX", "DEM3", "RX3 MIX1"},
+	{"RDAC4 MUX", "DEM2", "RX2 CHAIN"},
+	{"LINEOUT1 DAC", NULL, "RDAC4 MUX"},
+
 	{"SPK PA", NULL, "SPK DAC"},
 	{"SPK DAC", NULL, "VDD_SPKDRV"},
 
@@ -2875,7 +2887,7 @@
 	{"LINEOUT1 DAC", NULL, "CDC_CP_VDD"},
 	{"LINEOUT2 DAC", NULL, "CDC_CP_VDD"},
 
-	{"RDAC3 MUX", "DEM2", "RX2 MIX1"},
+	{"RDAC3 MUX", "DEM2", "RX2 CHAIN"},
 	{"RDAC3 MUX", "DEM1", "RX1 CHAIN"},
 
 	{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
@@ -3010,9 +3022,6 @@
 static const struct snd_soc_dapm_route wcd9302_map[] = {
 	{"SPK DAC", "Switch", "RX3 MIX1"},
 
-	{"RDAC4 MUX", "DEM3", "RX3 MIX1"},
-	{"RDAC4 MUX", "DEM2", "RX2 CHAIN"},
-	{"LINEOUT1 DAC", NULL, "RDAC4 MUX"},
 
 	{"RDAC5 MUX", "DEM4", "RX3 MIX1"},
 	{"RDAC5 MUX", "DEM3_INV", "RDAC4 MUX"},
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 6771aae..61ae859 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -128,7 +128,7 @@
 			S_IRUGO | S_IWUSR | S_IWGRP);
 MODULE_PARM_DESC(impedance_detect_en, "enable/disable impedance detect");
 
-static bool detect_use_vddio_switch = true;
+static bool detect_use_vddio_switch;
 
 struct wcd9xxx_mbhc_detect {
 	u16 dce;
@@ -973,7 +973,9 @@
 	if (noreldetection)
 		wcd9xxx_turn_onoff_rel_detection(codec, false);
 
-	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x0);
+	if (mbhc->mbhc_cfg->do_recalibration)
+		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
+				    0x0);
 	/* Turn on the override */
 	if (!override_bypass)
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
@@ -983,8 +985,9 @@
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
 				    0x0);
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
-				    0x2);
+		if (mbhc->mbhc_cfg->do_recalibration)
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
+					    0x2, 0x2);
 		usleep_range(mbhc->mbhc_data.t_sta_dce,
 			     mbhc->mbhc_data.t_sta_dce);
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
@@ -996,8 +999,9 @@
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
 		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
 				    0x0);
-		snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2,
-				    0x2);
+		if (mbhc->mbhc_cfg->do_recalibration)
+			snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
+					    0x2, 0x2);
 		usleep_range(mbhc->mbhc_data.t_sta_dce,
 			     mbhc->mbhc_data.t_sta_dce);
 		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
@@ -1141,48 +1145,59 @@
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
 	snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 
+	if (!mbhc->mbhc_cfg->do_recalibration) {
+		if (!is_cs_enable)
+			wcd9xxx_calibrate_hs_polling(mbhc);
+	}
+
 	/* don't flip override */
 	bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
 	snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
 	snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
 
-	/* recalibrate dce_z and sta_z */
-	reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
-	change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
-				     btn_det->mbhc_nsc << 3);
-	wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
-	if (change)
-		snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
-	if (dce_z && sta_z) {
-		pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
-			 __func__,
-			 mbhc->mbhc_data.sta_z, sta_z & 0xffff,
-			 mbhc->mbhc_data.dce_z, dce_z & 0xffff);
-		mbhc->mbhc_data.dce_z = dce_z;
-		mbhc->mbhc_data.sta_z = sta_z;
-		wcd9xxx_mbhc_calc_thres(mbhc);
-		wcd9xxx_calibrate_hs_polling(mbhc);
-	} else {
-		pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n", __func__,
-			dce_z, sta_z);
-	}
-
-	if (is_cs_enable) {
-		/* recalibrate dce_nsc_cs_z */
-		reg = snd_soc_read(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
-		snd_soc_update_bits(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
-				    0x78, WCD9XXX_MBHC_NSC_CS << 3);
-		wcd9xxx_get_z(mbhc, &dce_z, NULL);
-		snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
-		if (dce_z) {
-			pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x\n", __func__,
-				 mbhc->mbhc_data.dce_nsc_cs_z, dce_z & 0xffff);
-			mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
+	if (mbhc->mbhc_cfg->do_recalibration) {
+		/* recalibrate dce_z and sta_z */
+		reg = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+		change = snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+					     0x78, btn_det->mbhc_nsc << 3);
+		wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+		if (change)
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg);
+		if (dce_z && sta_z) {
+			pr_debug("%s: sta_z 0x%x -> 0x%x, dce_z 0x%x -> 0x%x\n",
+				 __func__,
+				 mbhc->mbhc_data.sta_z, sta_z & 0xffff,
+				 mbhc->mbhc_data.dce_z, dce_z & 0xffff);
+			mbhc->mbhc_data.dce_z = dce_z;
+			mbhc->mbhc_data.sta_z = sta_z;
+			wcd9xxx_mbhc_calc_thres(mbhc);
+			wcd9xxx_calibrate_hs_polling(mbhc);
 		} else {
-			pr_debug("%s: failed get new dce_nsc_cs_z\n", __func__);
+			pr_warn("%s: failed get new dce_z/sta_z 0x%x/0x%x\n",
+				__func__, dce_z, sta_z);
+		}
+
+		if (is_cs_enable) {
+			/* recalibrate dce_nsc_cs_z */
+			reg = snd_soc_read(mbhc->codec,
+					   WCD9XXX_A_CDC_MBHC_B1_CTL);
+			snd_soc_update_bits(mbhc->codec,
+					    WCD9XXX_A_CDC_MBHC_B1_CTL,
+					    0x78, WCD9XXX_MBHC_NSC_CS << 3);
+			wcd9xxx_get_z(mbhc, &dce_z, NULL);
+			snd_soc_write(mbhc->codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+				      reg);
+			if (dce_z) {
+				pr_debug("%s: dce_nsc_cs_z 0x%x -> 0x%x\n",
+					 __func__, mbhc->mbhc_data.dce_nsc_cs_z,
+					 dce_z & 0xffff);
+				mbhc->mbhc_data.dce_nsc_cs_z = dce_z;
+			} else {
+				pr_debug("%s: failed get new dce_nsc_cs_z\n",
+					 __func__);
+			}
 		}
 	}
-
 	return bias_value;
 }
 
@@ -1752,6 +1767,7 @@
 
 	/* GND and MIC swap detection requires at least 2 rounds of DCE */
 	BUG_ON(NUM_DCE_PLUG_INS_DETECT < 2);
+	detect_use_vddio_switch = mbhc->mbhc_cfg->use_vddio_meas;
 
 	/*
 	 * There are chances vddio switch is on and cfilt voltage is adjusted
@@ -2049,8 +2065,11 @@
 	pr_debug("%s: enter\n", __func__);
 
 	WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
-	current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
-				  (1 << MBHC_CS_ENABLE_INSERTION)) != 0);
+
+	current_source_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
+		      (1 << MBHC_CS_ENABLE_INSERTION)) != 0) &&
+		     (!(snd_soc_read(mbhc->codec,
+				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
 
 	if (current_source_enable) {
 		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
@@ -2175,9 +2194,10 @@
 	unsigned long retry = 0, timeout;
 	bool cs_enable;
 
-	cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
-		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
-
+	cs_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
+		      (1 << MBHC_CS_ENABLE_REMOVAL)) != 0) &&
+		     (!(snd_soc_read(mbhc->codec,
+				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
 	if (cs_enable)
 		wcd9xxx_turn_onoff_current_source(mbhc, true, false);
 
@@ -2689,8 +2709,11 @@
 
 	mbhc = container_of(work, struct wcd9xxx_mbhc, correct_plug_swch);
 	codec = mbhc->codec;
-	current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
-				  (1 << MBHC_CS_ENABLE_POLLING)) != 0);
+
+	current_source_enable = (((mbhc->mbhc_cfg->cs_enable_flags &
+		      (1 << MBHC_CS_ENABLE_POLLING)) != 0) &&
+		     (!(snd_soc_read(codec,
+				     mbhc->mbhc_bias_regs.ctl_reg) & 0x80)));
 
 	wcd9xxx_onoff_ext_mclk(mbhc, true);
 
@@ -3219,7 +3242,9 @@
 				 __func__);
 			if (mbhc->update_z) {
 				wcd9xxx_update_z(mbhc);
-				mbhc->update_z = false;
+				dce_z = mbhc->mbhc_data.dce_z;
+				sta_z = mbhc->mbhc_data.sta_z;
+				mbhc->update_z = true;
 			}
 			stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
 						mbhc->mbhc_data.micb_mv);
@@ -3245,7 +3270,9 @@
 
 	if (mbhc->update_z) {
 		wcd9xxx_update_z(mbhc);
-		mbhc->update_z = false;
+		dce_z = mbhc->mbhc_data.dce_z;
+		sta_z = mbhc->mbhc_data.sta_z;
+		mbhc->update_z = true;
 	}
 
 	stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
@@ -4236,7 +4263,8 @@
 		if (mbhc->hph_status & SND_JACK_OC_HPHL)
 			hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
 		if (!(mbhc->event_state &
-		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR |
+		       1 << MBHC_EVENT_PRE_TX_3_ON)))
 			wcd9xxx_switch_micbias(mbhc, 0);
 		break;
 	case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
@@ -4247,7 +4275,8 @@
 		if (mbhc->hph_status & SND_JACK_OC_HPHR)
 			hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
 		if (!(mbhc->event_state &
-		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+		      (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR |
+		       1 << MBHC_EVENT_PRE_TX_3_ON)))
 			wcd9xxx_switch_micbias(mbhc, 0);
 		break;
 	/* Clock usage change */
@@ -4329,6 +4358,28 @@
 	case WCD9XXX_EVENT_POST_BG_MBHC_ON:
 		/* Not used for now */
 		break;
+	case WCD9XXX_EVENT_PRE_TX_3_ON:
+		/*
+		 * if polling is ON, mbhc micbias not enabled
+		 *  switch micbias source to VDDIO
+		 */
+		set_bit(MBHC_EVENT_PRE_TX_3_ON, &mbhc->event_state);
+		if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg)
+		      & 0x80) &&
+		    mbhc->polling_active && !mbhc->mbhc_micbias_switched)
+			wcd9xxx_switch_micbias(mbhc, 1);
+		break;
+	case WCD9XXX_EVENT_POST_TX_3_OFF:
+		/*
+		 * Switch back to micbias if HPH PA or TX3 path
+		 * is disabled
+		 */
+		clear_bit(MBHC_EVENT_PRE_TX_3_ON, &mbhc->event_state);
+		if (mbhc->polling_active && mbhc->mbhc_micbias_switched &&
+		    !(mbhc->event_state & (1 << MBHC_EVENT_PA_HPHL |
+		      1 << MBHC_EVENT_PA_HPHR)))
+			wcd9xxx_switch_micbias(mbhc, 0);
+		break;
 	default:
 		WARN(1, "Unknown event %d\n", event);
 		ret = -EINVAL;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 39f59bb..98f73fc 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -123,6 +123,8 @@
 enum wcd9xxx_mbhc_event_state {
 	MBHC_EVENT_PA_HPHL,
 	MBHC_EVENT_PA_HPHR,
+	MBHC_EVENT_PRE_TX_3_ON,
+	MBHC_EVENT_POST_TX_3_OFF,
 };
 
 struct wcd9xxx_mbhc_general_cfg {
@@ -228,6 +230,8 @@
 	bool (*swap_gnd_mic) (struct snd_soc_codec *);
 	unsigned long cs_enable_flags;
 	bool use_int_rbias;
+	bool do_recalibration;
+	bool use_vddio_meas;
 };
 
 struct wcd9xxx_cfilt_mode {
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 6a22ff2..e56b182 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -92,6 +92,9 @@
 
 	"WCD9XXX_EVENT_POST_RESUME",
 
+	"WCD9XXX_EVENT_PRE_TX_3_ON",
+	"WCD9XXX_EVENT_POST_TX_3_OFF",
+
 	"WCD9XXX_EVENT_LAST",
 };
 
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 603bd1e..9f383b6 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -105,6 +105,9 @@
 
 	WCD9XXX_EVENT_POST_RESUME,
 
+	WCD9XXX_EVENT_PRE_TX_3_ON,
+	WCD9XXX_EVENT_POST_TX_3_OFF,
+
 	WCD9XXX_EVENT_LAST,
 };
 
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index c25a460..ceea3d2 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -94,6 +94,8 @@
 	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
 			    1 << MBHC_CS_ENABLE_INSERTION |
 			    1 << MBHC_CS_ENABLE_REMOVAL),
+	.do_recalibration = true,
+	.use_vddio_meas = true,
 };
 
 struct msm_auxpcm_gpio {
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index b34750a..c120e0c 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -129,6 +129,8 @@
 	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
 			    1 << MBHC_CS_ENABLE_INSERTION |
 			    1 << MBHC_CS_ENABLE_REMOVAL),
+	.do_recalibration = true,
+	.use_vddio_meas = true,
 };
 
 struct msm_auxpcm_gpio {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index d9af6f3..408ec03 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -102,6 +102,8 @@
 	.cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
 			    1 << MBHC_CS_ENABLE_INSERTION |
 			    1 << MBHC_CS_ENABLE_REMOVAL),
+	.do_recalibration = false,
+	.use_vddio_meas = false,
 };
 
 /*
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 5aa84a0..ea16f47 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -3,7 +3,7 @@
 			msm-multi-ch-pcm-q6-v2.o msm-pcm-lpa-v2.o \
 			msm-pcm-afe-v2.o msm-pcm-voip-v2.o \
 			msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
-			msm-lsm-client.o
+			msm-lsm-client.o msm-audio-effects-q6-v2.o
 obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
 				 msm-dai-stub-v2.o
 obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
new file mode 100644
index 0000000..5e4d9d3
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.c
@@ -0,0 +1,721 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+#include <sound/compress_params.h>
+#include "msm-audio-effects-q6-v2.h"
+
+int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
+				struct virtualizer_params *virtualizer,
+				long *values)
+{
+	int devices = *values++;
+	int num_commands = *values++;
+	char *params;
+	int *updt_params, i, prev_enable_flag;
+	uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+	if (!ac) {
+		pr_err("%s: cannot set audio effects\n", __func__);
+		return -EINVAL;
+	}
+	params = kzalloc(params_length, GFP_KERNEL);
+	if (!params) {
+		pr_err("%s, params memory alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	pr_debug("%s: device: %d\n", __func__, devices);
+	updt_params = (int *)params;
+	params_length = 0;
+	for (i = 0; i < num_commands; i++) {
+		uint32_t command_id = *values++;
+		uint32_t command_config_state = *values++;
+		uint32_t index_offset = *values++;
+		uint32_t length = *values++;
+		switch (command_id) {
+		case VIRTUALIZER_ENABLE:
+			pr_debug("%s: VIRTUALIZER_ENABLE\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			prev_enable_flag = virtualizer->enable_flag;
+			virtualizer->enable_flag = *values++;
+			if (prev_enable_flag != virtualizer->enable_flag) {
+				*updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_VIRTUALIZER_ENABLE;
+				*updt_params++ = VIRTUALIZER_ENABLE_PARAM_SZ;
+				*updt_params++ = virtualizer->enable_flag;
+				params_length += COMMAND_PAYLOAD_SZ +
+					VIRTUALIZER_ENABLE_PARAM_SZ;
+			}
+			break;
+		case VIRTUALIZER_STRENGTH:
+			pr_debug("%s: VIRTUALIZER_STRENGTH\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			virtualizer->strength = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_VIRTUALIZER_STRENGTH;
+				*updt_params++ = VIRTUALIZER_STRENGTH_PARAM_SZ;
+				*updt_params++ = virtualizer->strength;
+				params_length += COMMAND_PAYLOAD_SZ +
+					VIRTUALIZER_STRENGTH_PARAM_SZ;
+			}
+			break;
+		case VIRTUALIZER_OUT_TYPE:
+			pr_debug("%s: VIRTUALIZER_OUT_TYPE\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			virtualizer->out_type = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_VIRTUALIZER_OUT_TYPE;
+				*updt_params++ = VIRTUALIZER_OUT_TYPE_PARAM_SZ;
+				*updt_params++ = virtualizer->out_type;
+				params_length += COMMAND_PAYLOAD_SZ +
+					VIRTUALIZER_OUT_TYPE_PARAM_SZ;
+			}
+			break;
+		case VIRTUALIZER_GAIN_ADJUST:
+			pr_debug("%s: VIRTUALIZER_GAIN_ADJUST\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			virtualizer->gain_adjust = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_VIRTUALIZER;
+				*updt_params++ =
+				       AUDPROC_PARAM_ID_VIRTUALIZER_GAIN_ADJUST;
+				*updt_params++ =
+					VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
+				*updt_params++ = virtualizer->gain_adjust;
+				params_length += COMMAND_PAYLOAD_SZ +
+					VIRTUALIZER_GAIN_ADJUST_PARAM_SZ;
+			}
+			break;
+		default:
+			pr_err("%s: Invalid command to set config\n", __func__);
+			break;
+		}
+	}
+	if (params_length)
+		q6asm_send_audio_effects_params(ac, params,
+						params_length);
+invalid_config:
+	kfree(params);
+	return rc;
+}
+
+int msm_audio_effects_reverb_handler(struct audio_client *ac,
+				     struct reverb_params *reverb,
+				     long *values)
+{
+	int devices = *values++;
+	int num_commands = *values++;
+	char *params;
+	int *updt_params, i, prev_enable_flag;
+	uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+	if (!ac) {
+		pr_err("%s: cannot set audio effects\n", __func__);
+		return -EINVAL;
+	}
+	params = kzalloc(params_length, GFP_KERNEL);
+	if (!params) {
+		pr_err("%s, params memory alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	pr_debug("%s: device: %d\n", __func__, devices);
+	updt_params = (int *)params;
+	params_length = 0;
+	for (i = 0; i < num_commands; i++) {
+		uint32_t command_id = *values++;
+		uint32_t command_config_state = *values++;
+		uint32_t index_offset = *values++;
+		uint32_t length = *values++;
+		switch (command_id) {
+		case REVERB_ENABLE:
+			pr_debug("%s: REVERB_ENABLE\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			prev_enable_flag = reverb->enable_flag;
+			reverb->enable_flag = *values++;
+			if (prev_enable_flag != reverb->enable_flag) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ = AUDPROC_PARAM_ID_REVERB_ENABLE;
+				*updt_params++ = REVERB_ENABLE_PARAM_SZ;
+				*updt_params++ = reverb->enable_flag;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_ENABLE_PARAM_SZ;
+			}
+			break;
+		case REVERB_MODE:
+			pr_debug("%s: REVERB_MODE\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->mode = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ = AUDPROC_PARAM_ID_REVERB_MODE;
+				*updt_params++ = REVERB_MODE_PARAM_SZ;
+				*updt_params++ = reverb->mode;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_MODE_PARAM_SZ;
+			}
+			break;
+		case REVERB_PRESET:
+			pr_debug("%s: REVERB_PRESET\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->preset = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ = AUDPROC_PARAM_ID_REVERB_PRESET;
+				*updt_params++ = REVERB_PRESET_PARAM_SZ;
+				*updt_params++ = reverb->preset;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_PRESET_PARAM_SZ;
+			}
+			break;
+		case REVERB_WET_MIX:
+			pr_debug("%s: REVERB_WET_MIX\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->wet_mix = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_REVERB_WET_MIX;
+				*updt_params++ = REVERB_WET_MIX_PARAM_SZ;
+				*updt_params++ = reverb->wet_mix;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_WET_MIX_PARAM_SZ;
+			}
+			break;
+		case REVERB_GAIN_ADJUST:
+			pr_debug("%s: REVERB_GAIN_ADJUST\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->gain_adjust = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_REVERB_GAIN_ADJUST;
+				*updt_params++ = REVERB_GAIN_ADJUST_PARAM_SZ;
+				*updt_params++ = reverb->gain_adjust;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_GAIN_ADJUST_PARAM_SZ;
+			}
+			break;
+		case REVERB_ROOM_LEVEL:
+			pr_debug("%s: REVERB_ROOM_LEVEL\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->room_level = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_REVERB_ROOM_LEVEL;
+				*updt_params++ = REVERB_ROOM_LEVEL_PARAM_SZ;
+				*updt_params++ = reverb->room_level;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_ROOM_LEVEL_PARAM_SZ;
+			}
+			break;
+		case REVERB_ROOM_HF_LEVEL:
+			pr_debug("%s: REVERB_ROOM_HF_LEVEL\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->room_hf_level = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_REVERB_ROOM_HF_LEVEL;
+				*updt_params++ = REVERB_ROOM_HF_LEVEL_PARAM_SZ;
+				*updt_params++ = reverb->room_hf_level;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_ROOM_HF_LEVEL_PARAM_SZ;
+			}
+			break;
+		case REVERB_DECAY_TIME:
+			pr_debug("%s: REVERB_DECAY_TIME\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->decay_time = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_REVERB_DECAY_TIME;
+				*updt_params++ = REVERB_DECAY_TIME_PARAM_SZ;
+				*updt_params++ = reverb->decay_time;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_DECAY_TIME_PARAM_SZ;
+			}
+			break;
+		case REVERB_DECAY_HF_RATIO:
+			pr_debug("%s: REVERB_DECAY_HF_RATIO\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->decay_hf_ratio = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_REVERB_DECAY_HF_RATIO;
+				*updt_params++ = REVERB_DECAY_HF_RATIO_PARAM_SZ;
+				*updt_params++ = reverb->decay_hf_ratio;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_DECAY_HF_RATIO_PARAM_SZ;
+			}
+			break;
+		case REVERB_REFLECTIONS_LEVEL:
+			pr_debug("%s: REVERB_REFLECTIONS_LEVEL\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->reflections_level = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+				      AUDPROC_PARAM_ID_REVERB_REFLECTIONS_LEVEL;
+				*updt_params++ =
+					REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
+				*updt_params++ = reverb->reflections_level;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_REFLECTIONS_LEVEL_PARAM_SZ;
+			}
+			break;
+		case REVERB_REFLECTIONS_DELAY:
+			pr_debug("%s: REVERB_REFLECTIONS_DELAY\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->reflections_delay = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+				      AUDPROC_PARAM_ID_REVERB_REFLECTIONS_DELAY;
+				*updt_params++ =
+					REVERB_REFLECTIONS_DELAY_PARAM_SZ;
+				*updt_params++ = reverb->reflections_delay;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_REFLECTIONS_DELAY_PARAM_SZ;
+			}
+			break;
+		case REVERB_LEVEL:
+			pr_debug("%s: REVERB_LEVEL\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->level = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ = AUDPROC_PARAM_ID_REVERB_LEVEL;
+				*updt_params++ = REVERB_LEVEL_PARAM_SZ;
+				*updt_params++ = reverb->level;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_LEVEL_PARAM_SZ;
+			}
+			break;
+		case REVERB_DELAY:
+			pr_debug("%s: REVERB_DELAY\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->delay = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ = AUDPROC_PARAM_ID_REVERB_DELAY;
+				*updt_params++ = REVERB_DELAY_PARAM_SZ;
+				*updt_params++ = reverb->delay;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_DELAY_PARAM_SZ;
+			}
+			break;
+		case REVERB_DIFFUSION:
+			pr_debug("%s: REVERB_DIFFUSION\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->diffusion = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_REVERB_DIFFUSION;
+				*updt_params++ = REVERB_DIFFUSION_PARAM_SZ;
+				*updt_params++ = reverb->diffusion;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_DIFFUSION_PARAM_SZ;
+			}
+			break;
+		case REVERB_DENSITY:
+			pr_debug("%s: REVERB_DENSITY\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			reverb->density = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_REVERB;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_REVERB_DENSITY;
+				*updt_params++ = REVERB_DENSITY_PARAM_SZ;
+				*updt_params++ = reverb->density;
+				params_length += COMMAND_PAYLOAD_SZ +
+					REVERB_DENSITY_PARAM_SZ;
+			}
+			break;
+		default:
+			pr_err("%s: Invalid command to set config\n", __func__);
+			break;
+		}
+	}
+	if (params_length)
+		q6asm_send_audio_effects_params(ac, params,
+						params_length);
+invalid_config:
+	kfree(params);
+	return rc;
+}
+
+int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
+					struct bass_boost_params *bass_boost,
+					long *values)
+{
+	int devices = *values++;
+	int num_commands = *values++;
+	char *params;
+	int *updt_params, i, prev_enable_flag;
+	uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+	if (!ac) {
+		pr_err("%s: cannot set audio effects\n", __func__);
+		return -EINVAL;
+	}
+	params = kzalloc(params_length, GFP_KERNEL);
+	if (!params) {
+		pr_err("%s, params memory alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	pr_debug("%s: device: %d\n", __func__, devices);
+	updt_params = (int *)params;
+	params_length = 0;
+	for (i = 0; i < num_commands; i++) {
+		uint32_t command_id = *values++;
+		uint32_t command_config_state = *values++;
+		uint32_t index_offset = *values++;
+		uint32_t length = *values++;
+		switch (command_id) {
+		case BASS_BOOST_ENABLE:
+			pr_debug("%s: BASS_BOOST_ENABLE\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			prev_enable_flag = bass_boost->enable_flag;
+			bass_boost->enable_flag = *values++;
+			if (prev_enable_flag != bass_boost->enable_flag) {
+				*updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_BASS_BOOST_ENABLE;
+				*updt_params++ = BASS_BOOST_ENABLE_PARAM_SZ;
+				*updt_params++ = bass_boost->enable_flag;
+				params_length += COMMAND_PAYLOAD_SZ +
+					BASS_BOOST_ENABLE_PARAM_SZ;
+			}
+			break;
+		case BASS_BOOST_MODE:
+			pr_debug("%s: BASS_BOOST_MODE\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			bass_boost->mode = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_BASS_BOOST_MODE;
+				*updt_params++ = BASS_BOOST_MODE_PARAM_SZ;
+				*updt_params++ = bass_boost->mode;
+				params_length += COMMAND_PAYLOAD_SZ +
+					BASS_BOOST_MODE_PARAM_SZ;
+			}
+			break;
+		case BASS_BOOST_STRENGTH:
+			pr_debug("%s: BASS_BOOST_STRENGTH\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			bass_boost->strength = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ = AUDPROC_MODULE_ID_BASS_BOOST;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_BASS_BOOST_STRENGTH;
+				*updt_params++ = BASS_BOOST_STRENGTH_PARAM_SZ;
+				*updt_params++ = bass_boost->strength;
+				params_length += COMMAND_PAYLOAD_SZ +
+					BASS_BOOST_STRENGTH_PARAM_SZ;
+			}
+			break;
+		default:
+			pr_err("%s: Invalid command to set config\n", __func__);
+			break;
+		}
+	}
+	if (params_length)
+		q6asm_send_audio_effects_params(ac, params,
+						params_length);
+invalid_config:
+	kfree(params);
+	return rc;
+}
+
+int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
+					 struct eq_params *eq,
+					 long *values)
+{
+	int devices = *values++;
+	int num_commands = *values++;
+	char *params;
+	int *updt_params, i, prev_enable_flag;
+	uint32_t params_length = (MAX_INBAND_PARAM_SZ);
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+	if (!ac) {
+		pr_err("%s: cannot set audio effects\n", __func__);
+		return -EINVAL;
+	}
+	params = kzalloc(params_length, GFP_KERNEL);
+	if (!params) {
+		pr_err("%s, params memory alloc failed\n", __func__);
+		return -ENOMEM;
+	}
+	pr_debug("%s: device: %d\n", __func__, devices);
+	updt_params = (int *)params;
+	params_length = 0;
+	for (i = 0; i < num_commands; i++) {
+		uint32_t command_id = *values++;
+		uint32_t command_config_state = *values++;
+		uint32_t index_offset = *values++;
+		uint32_t length = *values++;
+		int idx, j;
+		switch (command_id) {
+		case EQ_ENABLE:
+			pr_debug("%s: EQ_ENABLE\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			prev_enable_flag = eq->enable_flag;
+			eq->enable_flag = *values++;
+			pr_debug("%s: prev_enable_flag : %d, eq.enable_flag : %d",
+				__func__, prev_enable_flag, eq->enable_flag);
+			if (prev_enable_flag != eq->enable_flag) {
+				*updt_params++ =
+					AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+				*updt_params++ = AUDPROC_PARAM_ID_EQ_ENABLE;
+				*updt_params++ = EQ_ENABLE_PARAM_SZ;
+				*updt_params++ = eq->enable_flag;
+				params_length += COMMAND_PAYLOAD_SZ +
+					EQ_ENABLE_PARAM_SZ;
+			}
+			break;
+		case EQ_CONFIG:
+			pr_debug("%s: EQ_CONFIG\n", __func__);
+			if (length < EQ_CONFIG_PARAM_LEN || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			for (idx = 0; idx < MAX_EQ_BANDS; idx++)
+				eq->per_band_cfg[idx].band_idx = -1;
+			eq->config.eq_pregain = *values++;
+			eq->config.preset_id = *values++;
+			eq->config.num_bands = *values++;
+			if (eq->config.num_bands > MAX_EQ_BANDS) {
+				pr_err("invalid num of bands\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			if (eq->config.num_bands &&
+			    (((length - EQ_CONFIG_PARAM_LEN)/
+				EQ_CONFIG_PER_BAND_PARAM_LEN)
+				!= eq->config.num_bands)) {
+				pr_err("invalid length to set config per band\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			for (j = 0; j < eq->config.num_bands; j++) {
+				idx = *values++;
+				eq->per_band_cfg[idx].band_idx = idx;
+				eq->per_band_cfg[idx].filter_type = *values++;
+				eq->per_band_cfg[idx].freq_millihertz =
+								*values++;
+				eq->per_band_cfg[idx].gain_millibels =
+								*values++;
+				eq->per_band_cfg[idx].quality_factor =
+								*values++;
+			}
+			if (command_config_state == CONFIG_SET) {
+				int config_param_length = EQ_CONFIG_PARAM_SZ +
+					(EQ_CONFIG_PER_BAND_PARAM_SZ*
+					 eq->config.num_bands);
+				*updt_params++ =
+					AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+				*updt_params++ = AUDPROC_PARAM_ID_EQ_CONFIG;
+				*updt_params++ = config_param_length;
+				*updt_params++ = eq->config.eq_pregain;
+				*updt_params++ = eq->config.preset_id;
+				*updt_params++ = eq->config.num_bands;
+				for (idx = 0; idx < MAX_EQ_BANDS; idx++) {
+					if (eq->per_band_cfg[idx].band_idx < 0)
+						continue;
+					*updt_params++ =
+					  eq->per_band_cfg[idx].filter_type;
+					*updt_params++ =
+					  eq->per_band_cfg[idx].freq_millihertz;
+					*updt_params++ =
+					  eq->per_band_cfg[idx].gain_millibels;
+					*updt_params++ =
+					  eq->per_band_cfg[idx].quality_factor;
+					*updt_params++ =
+					  eq->per_band_cfg[idx].band_idx;
+				}
+				params_length += COMMAND_PAYLOAD_SZ +
+						config_param_length;
+			}
+			break;
+		case EQ_BAND_INDEX:
+			pr_debug("%s: EQ_BAND_INDEX\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			idx = *values++;
+			if (idx > MAX_EQ_BANDS) {
+				pr_err("invalid band index\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			eq->band_index = idx;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ =
+					AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_EQ_BAND_INDEX;
+				*updt_params++ = EQ_BAND_INDEX_PARAM_SZ;
+				*updt_params++ = eq->band_index;
+				params_length += COMMAND_PAYLOAD_SZ +
+					EQ_BAND_INDEX_PARAM_SZ;
+			}
+			break;
+		case EQ_SINGLE_BAND_FREQ:
+			pr_debug("%s: EQ_SINGLE_BAND_FREQ\n", __func__);
+			if (length != 1 || index_offset != 0) {
+				pr_err("no valid params\n");
+				rc = -EINVAL;
+				goto invalid_config;
+			}
+			if (eq->band_index > MAX_EQ_BANDS) {
+				pr_err("invalid band index to set frequency\n");
+				break;
+			}
+			eq->freq_millihertz = *values++;
+			if (command_config_state == CONFIG_SET) {
+				*updt_params++ =
+					AUDPROC_MODULE_ID_POPLESS_EQUALIZER;
+				*updt_params++ =
+					AUDPROC_PARAM_ID_EQ_SINGLE_BAND_FREQ;
+				*updt_params++ = EQ_SINGLE_BAND_FREQ_PARAM_SZ;
+				*updt_params++ = eq->freq_millihertz;
+				params_length += COMMAND_PAYLOAD_SZ +
+					EQ_SINGLE_BAND_FREQ_PARAM_SZ;
+			}
+			break;
+		default:
+			pr_err("%s: Invalid command to set config\n", __func__);
+			break;
+		}
+	}
+	if (params_length)
+		q6asm_send_audio_effects_params(ac, params,
+						params_length);
+invalid_config:
+	kfree(params);
+	return rc;
+}
diff --git a/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h
new file mode 100644
index 0000000..3d2e6d4
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-audio-effects-q6-v2.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MSM_AUDIO_EFFECTS_H
+#define _MSM_AUDIO_EFFECTS_H
+
+#include <sound/audio_effects.h>
+
+int msm_audio_effects_reverb_handler(struct audio_client *ac,
+				     struct reverb_params *reverb,
+				     long *values);
+
+int msm_audio_effects_bass_boost_handler(struct audio_client *ac,
+					struct bass_boost_params *bass_boost,
+					long *values);
+int msm_audio_effects_virtualizer_handler(struct audio_client *ac,
+				struct virtualizer_params *virtualizer,
+				long *values);
+
+int msm_audio_effects_popless_eq_handler(struct audio_client *ac,
+					 struct eq_params *eq,
+					 long *values);
+#endif /*_MSM_AUDIO_EFFECTS_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 55d50ed..7935100 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -43,6 +43,7 @@
 
 #include "msm-pcm-routing-v2.h"
 #include "audio_ocmem.h"
+#include "msm-audio-effects-q6-v2.h"
 
 #define DSP_PP_BUFFERING_IN_MSEC	25
 #define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC	150
@@ -71,6 +72,7 @@
 	atomic_t audio_ocmem_req;
 	struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
 	uint32_t volume[MSM_FRONTEND_DAI_MAX][2]; /* For both L & R */
+	struct msm_compr_audio_effects *audio_effects[MSM_FRONTEND_DAI_MAX];
 };
 
 struct msm_compr_audio {
@@ -109,6 +111,7 @@
 	atomic_t xrun;
 	atomic_t close;
 	atomic_t wait_on_close;
+	atomic_t error;
 
 	wait_queue_head_t eos_wait;
 	wait_queue_head_t drain_wait;
@@ -118,6 +121,13 @@
 	spinlock_t lock;
 };
 
+struct msm_compr_audio_effects {
+	struct bass_boost_params bass_boost;
+	struct virtualizer_params virtualizer;
+	struct reverb_params reverb;
+	struct eq_params equalizer;
+};
+
 static int msm_compr_set_volume(struct snd_compr_stream *cstream,
 				uint32_t volume_l, uint32_t volume_r)
 {
@@ -164,17 +174,11 @@
 
 	pr_debug("%s: bytes_received = %d copied_total = %d\n",
 		__func__, prtd->bytes_received, prtd->copied_total);
-	/*
-	 * FIXME: Initial and trailing silence removal API call to DSP results
-	 *	to a glitch during the stream transition for gapless playback.
-	 *	Add this when the issue is fixed from DSP.
-	 */
-/*
 	if (prtd->first_buffer)
 		q6asm_send_meta_data(prtd->audio_client,
 				prtd->gapless_state.initial_samples_drop,
 				prtd->gapless_state.trailing_samples_drop);
-*/
+
 	buffer_length = prtd->codec_param.buffer.fragment_size;
 	bytes_available = prtd->bytes_received - prtd->copied_total;
 	if (bytes_available < prtd->codec_param.buffer.fragment_size)
@@ -354,6 +358,14 @@
 	case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3:
 		pr_debug("ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3\n");
 		break;
+	case RESET_EVENTS:
+		pr_err("Received reset events CB, move to error state");
+		spin_lock(&prtd->lock);
+		snd_compr_fragment_elapsed(cstream);
+		prtd->copied_total = prtd->bytes_received;
+		atomic_set(&prtd->error, 1);
+		spin_unlock(&prtd->lock);
+		break;
 	default:
 		pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
 		break;
@@ -514,10 +526,18 @@
 
 	prtd->cstream = cstream;
 	pdata->cstream[rtd->dai_link->be_id] = cstream;
+	pdata->audio_effects[rtd->dai_link->be_id] =
+		 kzalloc(sizeof(struct msm_compr_audio_effects), GFP_KERNEL);
+	if (!pdata->audio_effects[rtd->dai_link->be_id]) {
+		pr_err("%s: Could not allocate memory for effects\n", __func__);
+		kfree(prtd);
+		return -ENOMEM;
+	}
 	prtd->audio_client = q6asm_audio_client_alloc(
 				(app_cb)compr_event_handler, prtd);
 	if (!prtd->audio_client) {
-		pr_err("%s: Could not allocate memory\n", __func__);
+		pr_err("%s: Could not allocate memory for client\n", __func__);
+		kfree(pdata->audio_effects[rtd->dai_link->be_id]);
 		kfree(prtd);
 		return -ENOMEM;
 	}
@@ -545,6 +565,7 @@
 	atomic_set(&prtd->xrun, 0);
 	atomic_set(&prtd->close, 0);
 	atomic_set(&prtd->wait_on_close, 0);
+	atomic_set(&prtd->error, 0);
 
 	init_waitqueue_head(&prtd->eos_wait);
 	init_waitqueue_head(&prtd->drain_wait);
@@ -629,6 +650,7 @@
 
 	q6asm_audio_client_free(ac);
 
+	kfree(pdata->audio_effects[soc_prtd->dai_link->be_id]);
 	kfree(prtd);
 
 	return 0;
@@ -759,6 +781,14 @@
 		return -EINVAL;
 	}
 
+	spin_lock_irqsave(&prtd->lock, flags);
+	if (atomic_read(&prtd->error)) {
+		pr_err("%s Got RESET EVENTS notification, return immediately", __func__);
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		return 0;
+	}
+	spin_unlock_irqrestore(&prtd->lock, flags);
+
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		pr_debug("%s: SNDRV_PCM_TRIGGER_START\n", __func__);
@@ -1072,6 +1102,15 @@
 	tstamp.byte_offset = prtd->byte_offset;
 	tstamp.copied_total = prtd->copied_total;
 	first_buffer = prtd->first_buffer;
+
+	if (atomic_read(&prtd->error)) {
+		pr_err("%s Got RESET EVENTS notification, return error", __func__);
+		tstamp.pcm_io_frames = 0;
+		memcpy(arg, &tstamp, sizeof(struct snd_compr_tstamp));
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		return -EINVAL;
+	}
+
 	spin_unlock_irqrestore(&prtd->lock, flags);
 
 	/*
@@ -1160,6 +1199,14 @@
 		return 0;
 	}
 
+	spin_lock_irqsave(&prtd->lock, flags);
+	if (atomic_read(&prtd->error)) {
+		pr_err("%s Got RESET EVENTS notification", __func__);
+		spin_unlock_irqrestore(&prtd->lock, flags);
+		return -EINVAL;
+	}
+	spin_unlock_irqrestore(&prtd->lock, flags);
+
 	dstn = prtd->buffer + prtd->app_pointer;
 	if (count < prtd->buffer_size - prtd->app_pointer) {
 		if (copy_from_user(dstn, buf, count))
@@ -1282,50 +1329,125 @@
 }
 
 static int msm_compr_volume_put(struct snd_kcontrol *kcontrol,
-				 struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned long fe_id = kcontrol->private_value;
 	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
 			snd_soc_platform_get_drvdata(platform);
-	struct snd_compr_stream *cstream = pdata->cstream[mc->reg];
-	uint32_t *volume = pdata->volume[mc->reg];
+	struct snd_compr_stream *cstream = NULL;
+	uint32_t *volume = NULL;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bounds fe_id %lu\n",
+			__func__, fe_id);
+		return -EINVAL;
+	}
+
+	cstream = pdata->cstream[fe_id];
+	volume = pdata->volume[fe_id];
 
 	volume[0] = ucontrol->value.integer.value[0];
 	volume[1] = ucontrol->value.integer.value[1];
-	pr_debug("%s: mc->reg %d left_vol %d right_vol %d\n",
-		__func__, mc->reg, volume[0], volume[1]);
+	pr_debug("%s: fe_id %lu left_vol %d right_vol %d\n",
+		 __func__, fe_id, volume[0], volume[1]);
 	if (cstream)
 		msm_compr_set_volume(cstream, volume[0], volume[1]);
 	return 0;
 }
 
 static int msm_compr_volume_get(struct snd_kcontrol *kcontrol,
-				 struct snd_ctl_elem_value *ucontrol)
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
+	unsigned long fe_id = kcontrol->private_value;
+
 	struct msm_compr_pdata *pdata =
 		snd_soc_platform_get_drvdata(platform);
-	uint32_t *volume = pdata->volume[mc->reg];
-	pr_debug("%s: mc->reg %d\n", __func__, mc->reg);
+	uint32_t *volume = NULL;
+
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
+		return -EINVAL;
+	}
+
+	volume = pdata->volume[fe_id];
+	pr_debug("%s: fe_id %lu\n", __func__, fe_id);
 	ucontrol->value.integer.value[0] = volume[0];
 	ucontrol->value.integer.value[1] = volume[1];
 
 	return 0;
 }
 
-/* System Pin has no volume control */
-static const struct snd_kcontrol_new msm_compr_volume_controls[] = {
-	SOC_DOUBLE_EXT_TLV("Compress Playback Volume",
-			MSM_FRONTEND_DAI_MULTIMEDIA4,
-			0, 8, COMPRESSED_LR_VOL_MAX_STEPS, 0,
-			msm_compr_volume_get,
-			msm_compr_volume_put,
-			msm_compr_vol_gain),
-};
+static int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
+	unsigned long fe_id = kcontrol->private_value;
+	struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+			snd_soc_platform_get_drvdata(platform);
+	struct msm_compr_audio_effects *audio_effects = NULL;
+	struct snd_compr_stream *cstream = NULL;
+	struct msm_compr_audio *prtd = NULL;
+	long *values = &(ucontrol->value.integer.value[0]);
+	int effects_module;
+
+	pr_debug("%s\n", __func__);
+	if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+		pr_err("%s Received out of bounds fe_id %lu\n",
+			__func__, fe_id);
+		return -EINVAL;
+	}
+	cstream = pdata->cstream[fe_id];
+	audio_effects = pdata->audio_effects[fe_id];
+	if (!cstream || !audio_effects) {
+		pr_err("%s: stream or effects inactive\n", __func__);
+		return -EINVAL;
+	}
+	prtd = cstream->runtime->private_data;
+	if (!prtd) {
+		pr_err("%s: cannot set audio effects\n", __func__);
+		return -EINVAL;
+	}
+	effects_module = *values++;
+	switch (effects_module) {
+	case VIRTUALIZER_MODULE:
+		pr_debug("%s: VIRTUALIZER_MODULE\n", __func__);
+		msm_audio_effects_virtualizer_handler(prtd->audio_client,
+						&(audio_effects->virtualizer),
+						values);
+		break;
+	case REVERB_MODULE:
+		pr_debug("%s: REVERB_MODULE\n", __func__);
+		msm_audio_effects_reverb_handler(prtd->audio_client,
+						 &(audio_effects->reverb),
+						 values);
+		break;
+	case BASS_BOOST_MODULE:
+		pr_debug("%s: BASS_BOOST_MODULE\n", __func__);
+		msm_audio_effects_bass_boost_handler(prtd->audio_client,
+						   &(audio_effects->bass_boost),
+						     values);
+		break;
+	case EQ_MODULE:
+		pr_debug("%s: EQ_MODULE\n", __func__);
+		msm_audio_effects_popless_eq_handler(prtd->audio_client,
+						    &(audio_effects->equalizer),
+						     values);
+		break;
+	default:
+		pr_err("%s Invalid effects config module\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int msm_compr_audio_effects_config_get(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_value *ucontrol)
+{
+	/* dummy function */
+	return 0;
+}
 
 static int msm_compr_probe(struct snd_soc_platform *platform)
 {
@@ -1345,12 +1467,141 @@
 	for (i = 0; i < MSM_FRONTEND_DAI_MAX; i++) {
 		pdata->volume[i][0] = COMPRESSED_LR_VOL_MAX_STEPS;
 		pdata->volume[i][1] = COMPRESSED_LR_VOL_MAX_STEPS;
+		pdata->audio_effects[i] = NULL;
 		pdata->cstream[i] = NULL;
 	}
 
 	return 0;
 }
 
+static int msm_compr_volume_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = COMPRESSED_LR_VOL_MAX_STEPS;
+	return 0;
+}
+
+static int msm_compr_audio_effects_config_info(struct snd_kcontrol *kcontrol,
+					       struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 128;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xFFFFFFFF;
+	return 0;
+}
+
+static int msm_compr_add_volume_control(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Compress Playback";
+	const char *deviceNo       = "NN";
+	const char *suffix         = "Volume";
+	char *mixer_str = NULL;
+	int ctl_len;
+	struct snd_kcontrol_new fe_volume_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+			  SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_compr_volume_info,
+		.tlv.p = msm_compr_vol_gain,
+		.get = msm_compr_volume_get,
+		.put = msm_compr_volume_put,
+		.private_value = 0,
+		}
+	};
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		return 0;
+	}
+	pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n",
+		 __func__, rtd->dai_link->name, rtd->dai_link->be_id,
+		 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
+		  strlen(suffix) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+	if (!mixer_str) {
+		pr_err("failed to allocate mixer ctrl str of len %d", ctl_len);
+		return 0;
+	}
+	snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
+		 rtd->pcm->device, suffix);
+	fe_volume_control[0].name = mixer_str;
+	fe_volume_control[0].private_value = rtd->dai_link->be_id;
+	pr_debug("Registering new mixer ctl %s", mixer_str);
+	snd_soc_add_platform_controls(rtd->platform, fe_volume_control,
+				      ARRAY_SIZE(fe_volume_control));
+	kfree(mixer_str);
+	return 0;
+}
+
+static int msm_compr_add_audio_effects_control(struct snd_soc_pcm_runtime *rtd)
+{
+	const char *mixer_ctl_name = "Audio Effects Config";
+	const char *deviceNo       = "NN";
+	char *mixer_str = NULL;
+	int ctl_len;
+	struct snd_kcontrol_new fe_audio_effects_config_control[1] = {
+		{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "?",
+		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+		.info = msm_compr_audio_effects_config_info,
+		.get = msm_compr_audio_effects_config_get,
+		.put = msm_compr_audio_effects_config_put,
+		.private_value = 0,
+		}
+	};
+
+
+	if (!rtd) {
+		pr_err("%s NULL rtd\n", __func__);
+		return 0;
+	}
+
+	pr_debug("%s: added new compr FE with name %s, id %d, cpu dai %s, device no %d\n",
+		 __func__, rtd->dai_link->name, rtd->dai_link->be_id,
+		 rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+
+	ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+	mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+	if (!mixer_str) {
+		pr_err("failed to allocate mixer ctrl str of len %d", ctl_len);
+		return 0;
+	}
+
+	snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+
+	fe_audio_effects_config_control[0].name = mixer_str;
+	fe_audio_effects_config_control[0].private_value = rtd->dai_link->be_id;
+	pr_debug("Registering new mixer ctl %s", mixer_str);
+	snd_soc_add_platform_controls(rtd->platform,
+				fe_audio_effects_config_control,
+				ARRAY_SIZE(fe_audio_effects_config_control));
+	kfree(mixer_str);
+	return 0;
+}
+
+static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
+{
+	int rc;
+
+	rc = msm_compr_add_volume_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add Compr Volume Control\n", __func__);
+	rc = msm_compr_add_audio_effects_control(rtd);
+	if (rc)
+		pr_err("%s: Could not add Compr Audio Effects Control\n",
+			__func__);
+	return 0;
+}
+
 static struct snd_compr_ops msm_compr_ops = {
 	.open		= msm_compr_open,
 	.free		= msm_compr_free,
@@ -1367,8 +1618,7 @@
 static struct snd_soc_platform_driver msm_soc_platform = {
 	.probe		= msm_compr_probe,
 	.compr_ops	= &msm_compr_ops,
-	.controls	= msm_compr_volume_controls,
-	.num_controls	= ARRAY_SIZE(msm_compr_volume_controls),
+	.pcm_new = msm_compr_new,
 };
 
 static __devinit int msm_compr_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 2804c6a..b45a218 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -62,10 +62,13 @@
 	uint32_t  buf_addr_lsw;
 	uint32_t  mmap_hdl;
 };
-static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv);
 static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
 static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
 			uint32_t pkt_size, uint32_t cmd_flg);
+static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
+					  struct apr_hdr *hdr,
+					  uint32_t pkt_size, uint32_t cmd_flg);
 static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
 			uint32_t pkt_size, uint32_t cmd_flg);
 static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
@@ -364,7 +367,6 @@
 	struct list_head		*ptr, *next;
 	int				result;
 	int				size = 4096;
-
 	get_asm_custom_topology(&cal_block);
 	if (cal_block.cal_size == 0) {
 		pr_debug("%s: no cal to send addr= 0x%x\n",
@@ -422,8 +424,9 @@
 		}
 	}
 
-	q6asm_add_hdr(ac, &asm_top.hdr, APR_PKT_SIZE(APR_HDR_SIZE,
-						sizeof(asm_top)), TRUE);
+	q6asm_add_hdr_custom_topology(ac, &asm_top.hdr,
+				      APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(asm_top)), TRUE);
 
 	asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
 	asm_top.payload_addr_lsw = cal_block.cal_paddr;
@@ -445,7 +448,7 @@
 	result = wait_event_timeout(ac->cmd_wait,
 			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
 	if (!result) {
-		pr_err("%s: Set topologies failed payload = 0x%x\n",
+		pr_err("%s: Set topologies failed after timedout payload = 0x%x\n",
 			__func__, cal_block.cal_paddr);
 		goto done;
 	}
@@ -775,7 +778,7 @@
 	if ((atomic_read(&this_mmap.ref_cnt) == 0) ||
 	    (this_mmap.apr == NULL)) {
 		this_mmap.apr = apr_register("ADSP", "ASM", \
-					(apr_fn)q6asm_mmapcallback,\
+					(apr_fn)q6asm_srvc_callback,\
 					0x0FFFFFFFF, &this_mmap);
 		if (this_mmap.apr == NULL) {
 			pr_debug("%s Unable to register APR ASM common port\n",
@@ -869,7 +872,6 @@
 		pr_err("%s: session not active: %d\n", __func__, session_id);
 		goto err;
 	}
-
 	return session[session_id];
 err:
 	return NULL;
@@ -1042,7 +1044,7 @@
 	return -EINVAL;
 }
 
-static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv)
+static int32_t q6asm_srvc_callback(struct apr_client_data *data, void *priv)
 {
 	uint32_t sid = 0;
 	uint32_t dir = 0;
@@ -1089,6 +1091,7 @@
 		switch (payload[0]) {
 		case ASM_CMD_SHARED_MEM_MAP_REGIONS:
 		case ASM_CMD_SHARED_MEM_UNMAP_REGIONS:
+		case ASM_CMD_ADD_TOPOLOGIES:
 			if (payload[1] != 0) {
 				pr_err("%s: cmd = 0x%x returned error = 0x%x sid:%d\n",
 					__func__, payload[0], payload[1], sid);
@@ -1614,6 +1617,36 @@
 	return;
 }
 
+static void q6asm_add_hdr_custom_topology(struct audio_client *ac,
+					  struct apr_hdr *hdr,
+					  uint32_t pkt_size, uint32_t cmd_flg)
+{
+	pr_debug("%s:pkt_size=%d cmd_flg=%d session=%d\n", __func__, pkt_size,
+		cmd_flg, ac->session);
+	if (ac->apr == NULL) {
+		pr_err("%s: ac->apr is NULL", __func__);
+		return;
+	}
+
+	mutex_lock(&ac->cmd_lock);
+	hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+				APR_HDR_LEN(sizeof(struct apr_hdr)),\
+				APR_PKT_VER);
+	hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->dest_svc = APR_SVC_ASM;
+	hdr->dest_domain = APR_DOMAIN_ADSP;
+	hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+	hdr->dest_port = 0;
+	if (cmd_flg) {
+		hdr->token = ((ac->session << 8) | 0x0001) ;
+		atomic_set(&ac->cmd_state, 1);
+	}
+	hdr->pkt_size  = pkt_size;
+	mutex_unlock(&ac->cmd_lock);
+	return;
+}
+
 static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
 			u32 pkt_size, u32 cmd_flg, u32 token)
 {
@@ -3930,6 +3963,58 @@
 	return -EINVAL;
 }
 
+int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
+				    uint32_t params_length)
+{
+	char *asm_params = NULL;
+	struct apr_hdr hdr;
+	struct asm_stream_cmd_set_pp_params_v2 payload_params;
+	int sz, rc;
+
+	pr_debug("%s\n", __func__);
+	if (!ac || ac->apr == NULL || params == NULL) {
+		pr_err("APR handle NULL or params NULL\n");
+		return -EINVAL;
+	}
+	sz = sizeof(struct apr_hdr) +
+	     sizeof(struct asm_stream_cmd_set_pp_params_v2) +
+	     params_length;
+	asm_params = kzalloc(sz, GFP_KERNEL);
+	if (!asm_params) {
+		pr_err("%s, adm params memory alloc failed", __func__);
+		return -ENOMEM;
+	}
+	q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
+			    sizeof(struct asm_stream_cmd_set_pp_params_v2) +
+			    params_length), TRUE);
+	hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
+	payload_params.data_payload_addr_lsw = 0;
+	payload_params.data_payload_addr_msw = 0;
+	payload_params.mem_map_handle = 0;
+	payload_params.data_payload_size = params_length;
+	memcpy(((u8 *)asm_params), &hdr, sizeof(struct apr_hdr));
+	memcpy(((u8 *)asm_params + sizeof(struct apr_hdr)), &payload_params,
+		sizeof(struct asm_stream_cmd_set_pp_params_v2));
+	memcpy(((u8 *)asm_params + sizeof(struct apr_hdr) +
+		 sizeof(struct asm_stream_cmd_set_pp_params_v2)),
+		params, params_length);
+	rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
+	if (rc < 0) {
+		pr_err("%s: audio effects set-params send failed\n", __func__);
+		goto fail_send_param;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+				(atomic_read(&ac->cmd_state) == 0), 1*HZ);
+	if (!rc) {
+		pr_err("%s: timeout, audio effects set-params\n", __func__);
+		goto fail_send_param;
+	}
+	rc = 0;
+fail_send_param:
+	kfree(asm_params);
+	return rc;
+}
+
 static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
 {
 	struct apr_hdr hdr;
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 58b8399..b9af9b6 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -756,6 +756,14 @@
 	rtd->compr = compr;
 	compr->private_data = rtd;
 
+	if (platform->driver->pcm_new) {
+		ret = platform->driver->pcm_new(rtd);
+		if (ret < 0) {
+			pr_err("asoc: compress pcm constructor failed\n");
+			goto compr_err;
+		}
+	}
+
 	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
 		cpu_dai->name);
 	return ret;