Merge "msm: kgsl: Add NULL check for next_event hook"
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index a9528c5..7ed873f 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -56,9 +56,9 @@
 - qcom,enable-gpio:			Specifies the panel lcd/display enable gpio.
 - qcom,rst-gpio:			Specifies the panel reset gpio.
 - qcom,te-gpio:				Specifies the gpio used for TE.
-- qcom,dsi-lpg-channel :		LPG channel for backlight.
-- qcom,dsi-pwm-period :			PWM period in microseconds.
-- qcom,dsi-pwm-gpio :			PWM gpio.
+- qcom,pwm-lpg-channel:			LPG channel for backlight.
+- qcom,pwm-period:			PWM period in microseconds.
+- qcom,pwm-pmic-gpio:			PMIC gpio binding to backlight.
 - qcom,mdss-pan-broadcast-mode:		Boolean used to enable broadcast mode.
 - qcom,cont-splash-enabled:		Boolean used to enable continuous splash mode.
 - qcom,fbc-enabled:			Boolean used to enable frame buffer compression mode.
@@ -174,6 +174,19 @@
 - qcom,off-cmds-dsi-state:		A string that Specifies the ctrl state for sending ON commands.
 					Supported modes are "DSI_LP_MODE" and "DSI_HS_MODE".
 
+
+- qcom,panel-on-cmds: 			A byte stream formed by multiple dcs packets base on
+					qcom dsi controller protocol.
+					byte 0 : dcs data type
+					byte 1 : set to indicate this is an individual packet
+						(no chain).
+					byte 2 : virtual channel number
+					byte 3 : expect ack from client (dcs read command)
+					byte 4 : wait number of specified ms after dcs command
+						transmitted
+					byte 5, 6: 16 bits length in network byte order
+					byte 7 and beyond: number byte of payload
+
 Note, if a given optional qcom,* binding is not present, then the driver will configure
 the default values specified.
 
@@ -204,7 +217,7 @@
 		qcom,mdss-pan-dsi-mdp-tr = <0x04>;
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
 		qcom,mdss-pan-frame-rate = <60>;
-		qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+		qcom,panel-on-cmds = [32 01 00 00 00 00 02 00 00];
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
 		qcom,panel-off-cmds = [22 01 00 00 00 00 00];
 		qcom,off-cmds-dsi-state = "DSI LP MODE";
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index 9a7fa90..7616505 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -91,6 +91,7 @@
 - gpios : should contain phandle to gpio controller node and array of
     #gpio-cells specifying specific gpio (controller specific)
 - qcom,gpio-reset : should contain index to gpio used by sensors reset_n
+- qcom,gpio-standby : should contain index to gpio used by sensors standby_n
 - qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor
 - qcom,gpio-req-tbl-flags : should contain direction of gpios present in
     qcom,gpio-req-tbl-num property (in the same order)
@@ -201,11 +202,15 @@
                qcom,cam-vreg-op-mode = <105000 80000 0 100000>;
                qcom,gpio-no-mux = <0>;
                gpios = <&msmgpio 15 0>,
+                       <&msmgpio 90 0>,
+                       <&msmgpio 89 0>;
                qcom,gpio-reset = <1>;
-               qcom,gpio-req-tbl-num = <0 1>;
-               qcom,gpio-req-tbl-flags = <1 0>;
+               qcom,gpio-standby = <2>;
+               qcom,gpio-req-tbl-num = <0 1 2>;
+               qcom,gpio-req-tbl-flags = <1 0 0>;
                qcom,gpio-req-tbl-label = "CAMIF_MCLK",
-                                         "CAM_RESET1";
+                                         "CAM_RESET1",
+                                         "CAM_STANDBY";
                qcom,gpio-set-tbl-num = <1 1>;
                qcom,gpio-set-tbl-flags = <0 2>;
                qcom,gpio-set-tbl-delay = <1000 4000>;
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index e6f0da5..b350e24 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -64,6 +64,9 @@
 			curve.
 - qcom,hold-soc-est: if the voltage-based estimated SoC is above this percent,
 			the BMS will clamp SoC to be at least 1.
+- qcom,tm-temp-margin: if the pmic die temperature changes by more than this
+			value, recalibrate the ADCs. The unit of this property
+			is in millidegrees celsius.
 
 Parent node optional properties:
 - qcom,ignore-shutdown-soc: A boolean that controls whether BMS will
@@ -122,6 +125,7 @@
 	qcom,low-ocv-correction-limit-uv = <100>;
 	qcom,high-ocv-correction-limit-uv = <50>;
 	qcom,hold-soc-est = <3>;
+	qcom,tm-temp-margin = <5000>;
 
 	qcom,bms-iadc@3800 {
 		reg = <0x3800 0x100>;
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 10ca8a8..7bc748d 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -51,474 +51,474 @@
 					     00 00 00 00 0a 00 00 01 97 /* lane2 config */
 					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
 					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
-		qcom,panel-on-cmds = [29 01 00 00 00 02 FF EE
-					29 01 00 00 00 02 26 08
-					29 01 00 00 00 02 26 00
-					29 01 00 00 10 02 FF 00
-					29 01 00 00 00 02 BA 03
-					29 01 00 00 00 02 C2 03
-					29 01 00 00 00 02 FF 01
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 00 4A
-					29 01 00 00 00 02 01 33
-					29 01 00 00 00 02 02 53
-					29 01 00 00 00 02 03 55
-					29 01 00 00 00 02 04 55
-					29 01 00 00 00 02 05 33
-					29 01 00 00 00 02 06 22
-					29 01 00 00 00 02 08 56
-					29 01 00 00 00 02 09 8F
-					29 01 00 00 00 02 36 73
-					29 01 00 00 00 02 0B 9F
-					29 01 00 00 00 02 0C 9F
-					29 01 00 00 00 02 0D 2F
-					29 01 00 00 00 02 0E 24
-					29 01 00 00 00 02 11 83
-					29 01 00 00 00 02 12 03
-					29 01 00 00 00 02 71 2C
-					29 01 00 00 00 02 6F 03
-					29 01 00 00 00 02 0F 0A
-					29 01 00 00 00 02 FF 05
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 01 00
-					29 01 00 00 00 02 02 8B
-					29 01 00 00 00 02 03 82
-					29 01 00 00 00 02 04 82
-					29 01 00 00 00 02 05 30
-					29 01 00 00 00 02 06 33
-					29 01 00 00 00 02 07 01
-					29 01 00 00 00 02 08 00
-					29 01 00 00 00 02 09 46
-					29 01 00 00 00 02 0A 46
-					29 01 00 00 00 02 0D 0B
-					29 01 00 00 00 02 0E 1D
-					29 01 00 00 00 02 0F 08
-					29 01 00 00 00 02 10 53
-					29 01 00 00 00 02 11 00
-					29 01 00 00 00 02 12 00
-					29 01 00 00 00 02 14 01
-					29 01 00 00 00 02 15 00
-					29 01 00 00 00 02 16 05
-					29 01 00 00 00 02 17 00
-					29 01 00 00 00 02 19 7F
-					29 01 00 00 00 02 1A FF
-					29 01 00 00 00 02 1B 0F
-					29 01 00 00 00 02 1C 00
-					29 01 00 00 00 02 1D 00
-					29 01 00 00 00 02 1E 00
-					29 01 00 00 00 02 1F 07
-					29 01 00 00 00 02 20 00
-					29 01 00 00 00 02 21 06
-					29 01 00 00 00 02 22 55
-					29 01 00 00 00 02 23 4D
-					29 01 00 00 00 02 2D 02
-					29 01 00 00 00 02 28 01
-					29 01 00 00 00 02 2F 02
-					29 01 00 00 00 02 83 01
-					29 01 00 00 00 02 9E 58
-					29 01 00 00 00 02 9F 6A
-					29 01 00 00 00 02 A0 01
-					29 01 00 00 00 02 A2 10
-					29 01 00 00 00 02 BB 0A
-					29 01 00 00 00 02 BC 0A
-					29 01 00 00 00 02 32 08
-					29 01 00 00 00 02 33 B8
-					29 01 00 00 00 02 36 01
-					29 01 00 00 00 02 37 00
-					29 01 00 00 00 02 43 00
-					29 01 00 00 00 02 4B 21
-					29 01 00 00 00 02 4C 03
-					29 01 00 00 00 02 50 21
-					29 01 00 00 00 02 51 03
-					29 01 00 00 00 02 58 21
-					29 01 00 00 00 02 59 03
-					29 01 00 00 00 02 5D 21
-					29 01 00 00 00 02 5E 03
-					29 01 00 00 00 02 6C 00
-					29 01 00 00 00 02 6D 00
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 FF 01
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 75 00
-					29 01 00 00 00 02 76 7D
-					29 01 00 00 00 02 77 00
-					29 01 00 00 00 02 78 8A
-					29 01 00 00 00 02 79 00
-					29 01 00 00 00 02 7A 9C
-					29 01 00 00 00 02 7B 00
-					29 01 00 00 00 02 7C B1
-					29 01 00 00 00 02 7D 00
-					29 01 00 00 00 02 7E BF
-					29 01 00 00 00 02 7F 00
-					29 01 00 00 00 02 80 CF
-					29 01 00 00 00 02 81 00
-					29 01 00 00 00 02 82 DD
-					29 01 00 00 00 02 83 00
-					29 01 00 00 00 02 84 E8
-					29 01 00 00 00 02 85 00
-					29 01 00 00 00 02 86 F2
-					29 01 00 00 00 02 87 01
-					29 01 00 00 00 02 88 1F
-					29 01 00 00 00 02 89 01
-					29 01 00 00 00 02 8A 41
-					29 01 00 00 00 02 8B 01
-					29 01 00 00 00 02 8C 78
-					29 01 00 00 00 02 8D 01
-					29 01 00 00 00 02 8E A5
-					29 01 00 00 00 02 8F 01
-					29 01 00 00 00 02 90 EE
-					29 01 00 00 00 02 91 02
-					29 01 00 00 00 02 92 29
-					29 01 00 00 00 02 93 02
-					29 01 00 00 00 02 94 2A
-					29 01 00 00 00 02 95 02
-					29 01 00 00 00 02 96 5D
-					29 01 00 00 00 02 97 02
-					29 01 00 00 00 02 98 93
-					29 01 00 00 00 02 99 02
-					29 01 00 00 00 02 9A B8
-					29 01 00 00 00 02 9B 02
-					29 01 00 00 00 02 9C E7
-					29 01 00 00 00 02 9D 03
-					29 01 00 00 00 02 9E 07
-					29 01 00 00 00 02 9F 03
-					29 01 00 00 00 02 A0 37
-					29 01 00 00 00 02 A2 03
-					29 01 00 00 00 02 A3 46
-					29 01 00 00 00 02 A4 03
-					29 01 00 00 00 02 A5 56
-					29 01 00 00 00 02 A6 03
-					29 01 00 00 00 02 A7 66
-					29 01 00 00 00 02 A9 03
-					29 01 00 00 00 02 AA 7A
-					29 01 00 00 00 02 AB 03
-					29 01 00 00 00 02 AC 93
-					29 01 00 00 00 02 AD 03
-					29 01 00 00 00 02 AE A3
-					29 01 00 00 00 02 AF 03
-					29 01 00 00 00 02 B0 B4
-					29 01 00 00 00 02 B1 03
-					29 01 00 00 00 02 B2 CB
-					29 01 00 00 00 02 B3 00
-					29 01 00 00 00 02 B4 7D
-					29 01 00 00 00 02 B5 00
-					29 01 00 00 00 02 B6 8A
-					29 01 00 00 00 02 B7 00
-					29 01 00 00 00 02 B8 9C
-					29 01 00 00 00 02 B9 00
-					29 01 00 00 00 02 BA B1
-					29 01 00 00 00 02 BB 00
-					29 01 00 00 00 02 BC BF
-					29 01 00 00 00 02 BD 00
-					29 01 00 00 00 02 BE CF
-					29 01 00 00 00 02 BF 00
-					29 01 00 00 00 02 C0 DD
-					29 01 00 00 00 02 C1 00
-					29 01 00 00 00 02 C2 E8
-					29 01 00 00 00 02 C3 00
-					29 01 00 00 00 02 C4 F2
-					29 01 00 00 00 02 C5 01
-					29 01 00 00 00 02 C6 1F
-					29 01 00 00 00 02 C7 01
-					29 01 00 00 00 02 C8 41
-					29 01 00 00 00 02 C9 01
-					29 01 00 00 00 02 CA 78
-					29 01 00 00 00 02 CB 01
-					29 01 00 00 00 02 CC A5
-					29 01 00 00 00 02 CD 01
-					29 01 00 00 00 02 CE EE
-					29 01 00 00 00 02 CF 02
-					29 01 00 00 00 02 D0 29
-					29 01 00 00 00 02 D1 02
-					29 01 00 00 00 02 D2 2A
-					29 01 00 00 00 02 D3 02
-					29 01 00 00 00 02 D4 5D
-					29 01 00 00 00 02 D5 02
-					29 01 00 00 00 02 D6 93
-					29 01 00 00 00 02 D7 02
-					29 01 00 00 00 02 D8 B8
-					29 01 00 00 00 02 D9 02
-					29 01 00 00 00 02 DA E7
-					29 01 00 00 00 02 DB 03
-					29 01 00 00 00 02 DC 07
-					29 01 00 00 00 02 DD 03
-					29 01 00 00 00 02 DE 37
-					29 01 00 00 00 02 DF 03
-					29 01 00 00 00 02 E0 46
-					29 01 00 00 00 02 E1 03
-					29 01 00 00 00 02 E2 56
-					29 01 00 00 00 02 E3 03
-					29 01 00 00 00 02 E4 66
-					29 01 00 00 00 02 E5 03
-					29 01 00 00 00 02 E6 7A
-					29 01 00 00 00 02 E7 03
-					29 01 00 00 00 02 E8 93
-					29 01 00 00 00 02 E9 03
-					29 01 00 00 00 02 EA A3
-					29 01 00 00 00 02 EB 03
-					29 01 00 00 00 02 EC B4
-					29 01 00 00 00 02 ED 03
-					29 01 00 00 00 02 EE CB
-					29 01 00 00 00 02 EF 00
-					29 01 00 00 00 02 F0 ED
-					29 01 00 00 00 02 F1 00
-					29 01 00 00 00 02 F2 F3
-					29 01 00 00 00 02 F3 00
-					29 01 00 00 00 02 F4 FE
-					29 01 00 00 00 02 F5 01
-					29 01 00 00 00 02 F6 09
-					29 01 00 00 00 02 F7 01
-					29 01 00 00 00 02 F8 13
-					29 01 00 00 00 02 F9 01
-					29 01 00 00 00 02 FA 1D
-					29 01 00 00 00 02 FF 02
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 00 01
-					29 01 00 00 00 02 01 26
-					29 01 00 00 00 02 02 01
-					29 01 00 00 00 02 03 2F
-					29 01 00 00 00 02 04 01
-					29 01 00 00 00 02 05 37
-					29 01 00 00 00 02 06 01
-					29 01 00 00 00 02 07 56
-					29 01 00 00 00 02 08 01
-					29 01 00 00 00 02 09 70
-					29 01 00 00 00 02 0A 01
-					29 01 00 00 00 02 0B 9D
-					29 01 00 00 00 02 0C 01
-					29 01 00 00 00 02 0D C2
-					29 01 00 00 00 02 0E 01
-					29 01 00 00 00 02 0F FF
-					29 01 00 00 00 02 10 02
-					29 01 00 00 00 02 11 31
-					29 01 00 00 00 02 12 02
-					29 01 00 00 00 02 13 32
-					29 01 00 00 00 02 14 02
-					29 01 00 00 00 02 15 60
-					29 01 00 00 00 02 16 02
-					29 01 00 00 00 02 17 94
-					29 01 00 00 00 02 18 02
-					29 01 00 00 00 02 19 B5
-					29 01 00 00 00 02 1A 02
-					29 01 00 00 00 02 1B E3
-					29 01 00 00 00 02 1C 03
-					29 01 00 00 00 02 1D 03
-					29 01 00 00 00 02 1E 03
-					29 01 00 00 00 02 1F 2D
-					29 01 00 00 00 02 20 03
-					29 01 00 00 00 02 21 3A
-					29 01 00 00 00 02 22 03
-					29 01 00 00 00 02 23 48
-					29 01 00 00 00 02 24 03
-					29 01 00 00 00 02 25 57
-					29 01 00 00 00 02 26 03
-					29 01 00 00 00 02 27 68
-					29 01 00 00 00 02 28 03
-					29 01 00 00 00 02 29 7B
-					29 01 00 00 00 02 2A 03
-					29 01 00 00 00 02 2B 90
-					29 01 00 00 00 02 2D 03
-					29 01 00 00 00 02 2F A0
-					29 01 00 00 00 02 30 03
-					29 01 00 00 00 02 31 CB
-					29 01 00 00 00 02 32 00
-					29 01 00 00 00 02 33 ED
-					29 01 00 00 00 02 34 00
-					29 01 00 00 00 02 35 F3
-					29 01 00 00 00 02 36 00
-					29 01 00 00 00 02 37 FE
-					29 01 00 00 00 02 38 01
-					29 01 00 00 00 02 39 09
-					29 01 00 00 00 02 3A 01
-					29 01 00 00 00 02 3B 13
-					29 01 00 00 00 02 3D 01
-					29 01 00 00 00 02 3F 1D
-					29 01 00 00 00 02 40 01
-					29 01 00 00 00 02 41 26
-					29 01 00 00 00 02 42 01
-					29 01 00 00 00 02 43 2F
-					29 01 00 00 00 02 44 01
-					29 01 00 00 00 02 45 37
-					29 01 00 00 00 02 46 01
-					29 01 00 00 00 02 47 56
-					29 01 00 00 00 02 48 01
-					29 01 00 00 00 02 49 70
-					29 01 00 00 00 02 4A 01
-					29 01 00 00 00 02 4B 9D
-					29 01 00 00 00 02 4C 01
-					29 01 00 00 00 02 4D C2
-					29 01 00 00 00 02 4E 01
-					29 01 00 00 00 02 4F FF
-					29 01 00 00 00 02 50 02
-					29 01 00 00 00 02 51 31
-					29 01 00 00 00 02 52 02
-					29 01 00 00 00 02 53 32
-					29 01 00 00 00 02 54 02
-					29 01 00 00 00 02 55 60
-					29 01 00 00 00 02 56 02
-					29 01 00 00 00 02 58 94
-					29 01 00 00 00 02 59 02
-					29 01 00 00 00 02 5A B5
-					29 01 00 00 00 02 5B 02
-					29 01 00 00 00 02 5C E3
-					29 01 00 00 00 02 5D 03
-					29 01 00 00 00 02 5E 03
-					29 01 00 00 00 02 5F 03
-					29 01 00 00 00 02 60 2D
-					29 01 00 00 00 02 61 03
-					29 01 00 00 00 02 62 3A
-					29 01 00 00 00 02 63 03
-					29 01 00 00 00 02 64 48
-					29 01 00 00 00 02 65 03
-					29 01 00 00 00 02 66 57
-					29 01 00 00 00 02 67 03
-					29 01 00 00 00 02 68 68
-					29 01 00 00 00 02 69 03
-					29 01 00 00 00 02 6A 7B
-					29 01 00 00 00 02 6B 03
-					29 01 00 00 00 02 6C 90
-					29 01 00 00 00 02 6D 03
-					29 01 00 00 00 02 6E A0
-					29 01 00 00 00 02 6F 03
-					29 01 00 00 00 02 70 CB
-					29 01 00 00 00 02 71 00
-					29 01 00 00 00 02 72 19
-					29 01 00 00 00 02 73 00
-					29 01 00 00 00 02 74 36
-					29 01 00 00 00 02 75 00
-					29 01 00 00 00 02 76 55
-					29 01 00 00 00 02 77 00
-					29 01 00 00 00 02 78 70
-					29 01 00 00 00 02 79 00
-					29 01 00 00 00 02 7A 83
-					29 01 00 00 00 02 7B 00
-					29 01 00 00 00 02 7C 99
-					29 01 00 00 00 02 7D 00
-					29 01 00 00 00 02 7E A8
-					29 01 00 00 00 02 7F 00
-					29 01 00 00 00 02 80 B7
-					29 01 00 00 00 02 81 00
-					29 01 00 00 00 02 82 C5
-					29 01 00 00 00 02 83 00
-					29 01 00 00 00 02 84 F7
-					29 01 00 00 00 02 85 01
-					29 01 00 00 00 02 86 1E
-					29 01 00 00 00 02 87 01
-					29 01 00 00 00 02 88 60
-					29 01 00 00 00 02 89 01
-					29 01 00 00 00 02 8A 95
-					29 01 00 00 00 02 8B 01
-					29 01 00 00 00 02 8C E1
-					29 01 00 00 00 02 8D 02
-					29 01 00 00 00 02 8E 20
-					29 01 00 00 00 02 8F 02
-					29 01 00 00 00 02 90 23
-					29 01 00 00 00 02 91 02
-					29 01 00 00 00 02 92 59
-					29 01 00 00 00 02 93 02
-					29 01 00 00 00 02 94 94
-					29 01 00 00 00 02 95 02
-					29 01 00 00 00 02 96 B4
-					29 01 00 00 00 02 97 02
-					29 01 00 00 00 02 98 E1
-					29 01 00 00 00 02 99 03
-					29 01 00 00 00 02 9A 01
-					29 01 00 00 00 02 9B 03
-					29 01 00 00 00 02 9C 28
-					29 01 00 00 00 02 9D 03
-					29 01 00 00 00 02 9E 30
-					29 01 00 00 00 02 9F 03
-					29 01 00 00 00 02 A0 37
-					29 01 00 00 00 02 A2 03
-					29 01 00 00 00 02 A3 3B
-					29 01 00 00 00 02 A4 03
-					29 01 00 00 00 02 A5 40
-					29 01 00 00 00 02 A6 03
-					29 01 00 00 00 02 A7 50
-					29 01 00 00 00 02 A9 03
-					29 01 00 00 00 02 AA 6D
-					29 01 00 00 00 02 AB 03
-					29 01 00 00 00 02 AC 80
-					29 01 00 00 00 02 AD 03
-					29 01 00 00 00 02 AE CB
-					29 01 00 00 00 02 AF 00
-					29 01 00 00 00 02 B0 19
-					29 01 00 00 00 02 B1 00
-					29 01 00 00 00 02 B2 36
-					29 01 00 00 00 02 B3 00
-					29 01 00 00 00 02 B4 55
-					29 01 00 00 00 02 B5 00
-					29 01 00 00 00 02 B6 70
-					29 01 00 00 00 02 B7 00
-					29 01 00 00 00 02 B8 83
-					29 01 00 00 00 02 B9 00
-					29 01 00 00 00 02 BA 99
-					29 01 00 00 00 02 BB 00
-					29 01 00 00 00 02 BC A8
-					29 01 00 00 00 02 BD 00
-					29 01 00 00 00 02 BE B7
-					29 01 00 00 00 02 BF 00
-					29 01 00 00 00 02 C0 C5
-					29 01 00 00 00 02 C1 00
-					29 01 00 00 00 02 C2 F7
-					29 01 00 00 00 02 C3 01
-					29 01 00 00 00 02 C4 1E
-					29 01 00 00 00 02 C5 01
-					29 01 00 00 00 02 C6 60
-					29 01 00 00 00 02 C7 01
-					29 01 00 00 00 02 C8 95
-					29 01 00 00 00 02 C9 01
-					29 01 00 00 00 02 CA E1
-					29 01 00 00 00 02 CB 02
-					29 01 00 00 00 02 CC 20
-					29 01 00 00 00 02 CD 02
-					29 01 00 00 00 02 CE 23
-					29 01 00 00 00 02 CF 02
-					29 01 00 00 00 02 D0 59
-					29 01 00 00 00 02 D1 02
-					29 01 00 00 00 02 D2 94
-					29 01 00 00 00 02 D3 02
-					29 01 00 00 00 02 D4 B4
-					29 01 00 00 00 02 D5 02
-					29 01 00 00 00 02 D6 E1
-					29 01 00 00 00 02 D7 03
-					29 01 00 00 00 02 D8 01
-					29 01 00 00 00 02 D9 03
-					29 01 00 00 00 02 DA 28
-					29 01 00 00 00 02 DB 03
-					29 01 00 00 00 02 DC 30
-					29 01 00 00 00 02 DD 03
-					29 01 00 00 00 02 DE 37
-					29 01 00 00 00 02 DF 03
-					29 01 00 00 00 02 E0 3B
-					29 01 00 00 00 02 E1 03
-					29 01 00 00 00 02 E2 40
-					29 01 00 00 00 02 E3 03
-					29 01 00 00 00 02 E4 50
-					29 01 00 00 00 02 E5 03
-					29 01 00 00 00 02 E6 6D
-					29 01 00 00 00 02 E7 03
-					29 01 00 00 00 02 E8 80
-					29 01 00 00 00 02 E9 03
-					29 01 00 00 00 02 EA CB
-					29 01 00 00 00 02 FF 01
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 FF 02
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 FF 04
-					29 01 00 00 00 02 FB 01
-					29 01 00 00 00 02 FF 00
-					29 01 00 00 64 02 11 00
-					29 01 00 00 00 02 FF EE
-					29 01 00 00 00 02 12 50
-					29 01 00 00 00 02 13 02
-					29 01 00 00 00 02 6A 60
-					29 01 00 00 00 02 FF 00
-					29 01 00 00 78 02 29 00];
+		qcom,panel-on-cmds = [29 01 00 00 00 00 02 FF EE
+					29 01 00 00 00 00 02 26 08
+					29 01 00 00 00 00 02 26 00
+					29 01 00 00 10 00 02 FF 00
+					29 01 00 00 00 00 02 BA 03
+					29 01 00 00 00 00 02 C2 03
+					29 01 00 00 00 00 02 FF 01
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 00 4A
+					29 01 00 00 00 00 02 01 33
+					29 01 00 00 00 00 02 02 53
+					29 01 00 00 00 00 02 03 55
+					29 01 00 00 00 00 02 04 55
+					29 01 00 00 00 00 02 05 33
+					29 01 00 00 00 00 02 06 22
+					29 01 00 00 00 00 02 08 56
+					29 01 00 00 00 00 02 09 8F
+					29 01 00 00 00 00 02 36 73
+					29 01 00 00 00 00 02 0B 9F
+					29 01 00 00 00 00 02 0C 9F
+					29 01 00 00 00 00 02 0D 2F
+					29 01 00 00 00 00 02 0E 24
+					29 01 00 00 00 00 02 11 83
+					29 01 00 00 00 00 02 12 03
+					29 01 00 00 00 00 02 71 2C
+					29 01 00 00 00 00 02 6F 03
+					29 01 00 00 00 00 02 0F 0A
+					29 01 00 00 00 00 02 FF 05
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 01 00
+					29 01 00 00 00 00 02 02 8B
+					29 01 00 00 00 00 02 03 82
+					29 01 00 00 00 00 02 04 82
+					29 01 00 00 00 00 02 05 30
+					29 01 00 00 00 00 02 06 33
+					29 01 00 00 00 00 02 07 01
+					29 01 00 00 00 00 02 08 00
+					29 01 00 00 00 00 02 09 46
+					29 01 00 00 00 00 02 0A 46
+					29 01 00 00 00 00 02 0D 0B
+					29 01 00 00 00 00 02 0E 1D
+					29 01 00 00 00 00 02 0F 08
+					29 01 00 00 00 00 02 10 53
+					29 01 00 00 00 00 02 11 00
+					29 01 00 00 00 00 02 12 00
+					29 01 00 00 00 00 02 14 01
+					29 01 00 00 00 00 02 15 00
+					29 01 00 00 00 00 02 16 05
+					29 01 00 00 00 00 02 17 00
+					29 01 00 00 00 00 02 19 7F
+					29 01 00 00 00 00 02 1A FF
+					29 01 00 00 00 00 02 1B 0F
+					29 01 00 00 00 00 02 1C 00
+					29 01 00 00 00 00 02 1D 00
+					29 01 00 00 00 00 02 1E 00
+					29 01 00 00 00 00 02 1F 07
+					29 01 00 00 00 00 02 20 00
+					29 01 00 00 00 00 02 21 06
+					29 01 00 00 00 00 02 22 55
+					29 01 00 00 00 00 02 23 4D
+					29 01 00 00 00 00 02 2D 02
+					29 01 00 00 00 00 02 28 01
+					29 01 00 00 00 00 02 2F 02
+					29 01 00 00 00 00 02 83 01
+					29 01 00 00 00 00 02 9E 58
+					29 01 00 00 00 00 02 9F 6A
+					29 01 00 00 00 00 02 A0 01
+					29 01 00 00 00 00 02 A2 10
+					29 01 00 00 00 00 02 BB 0A
+					29 01 00 00 00 00 02 BC 0A
+					29 01 00 00 00 00 02 32 08
+					29 01 00 00 00 00 02 33 B8
+					29 01 00 00 00 00 02 36 01
+					29 01 00 00 00 00 02 37 00
+					29 01 00 00 00 00 02 43 00
+					29 01 00 00 00 00 02 4B 21
+					29 01 00 00 00 00 02 4C 03
+					29 01 00 00 00 00 02 50 21
+					29 01 00 00 00 00 02 51 03
+					29 01 00 00 00 00 02 58 21
+					29 01 00 00 00 00 02 59 03
+					29 01 00 00 00 00 02 5D 21
+					29 01 00 00 00 00 02 5E 03
+					29 01 00 00 00 00 02 6C 00
+					29 01 00 00 00 00 02 6D 00
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 FF 01
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 75 00
+					29 01 00 00 00 00 02 76 7D
+					29 01 00 00 00 00 02 77 00
+					29 01 00 00 00 00 02 78 8A
+					29 01 00 00 00 00 02 79 00
+					29 01 00 00 00 00 02 7A 9C
+					29 01 00 00 00 00 02 7B 00
+					29 01 00 00 00 00 02 7C B1
+					29 01 00 00 00 00 02 7D 00
+					29 01 00 00 00 00 02 7E BF
+					29 01 00 00 00 00 02 7F 00
+					29 01 00 00 00 00 02 80 CF
+					29 01 00 00 00 00 02 81 00
+					29 01 00 00 00 00 02 82 DD
+					29 01 00 00 00 00 02 83 00
+					29 01 00 00 00 00 02 84 E8
+					29 01 00 00 00 00 02 85 00
+					29 01 00 00 00 00 02 86 F2
+					29 01 00 00 00 00 02 87 01
+					29 01 00 00 00 00 02 88 1F
+					29 01 00 00 00 00 02 89 01
+					29 01 00 00 00 00 02 8A 41
+					29 01 00 00 00 00 02 8B 01
+					29 01 00 00 00 00 02 8C 78
+					29 01 00 00 00 00 02 8D 01
+					29 01 00 00 00 00 02 8E A5
+					29 01 00 00 00 00 02 8F 01
+					29 01 00 00 00 00 02 90 EE
+					29 01 00 00 00 00 02 91 02
+					29 01 00 00 00 00 02 92 29
+					29 01 00 00 00 00 02 93 02
+					29 01 00 00 00 00 02 94 2A
+					29 01 00 00 00 00 02 95 02
+					29 01 00 00 00 00 02 96 5D
+					29 01 00 00 00 00 02 97 02
+					29 01 00 00 00 00 02 98 93
+					29 01 00 00 00 00 02 99 02
+					29 01 00 00 00 00 02 9A B8
+					29 01 00 00 00 00 02 9B 02
+					29 01 00 00 00 00 02 9C E7
+					29 01 00 00 00 00 02 9D 03
+					29 01 00 00 00 00 02 9E 07
+					29 01 00 00 00 00 02 9F 03
+					29 01 00 00 00 00 02 A0 37
+					29 01 00 00 00 00 02 A2 03
+					29 01 00 00 00 00 02 A3 46
+					29 01 00 00 00 00 02 A4 03
+					29 01 00 00 00 00 02 A5 56
+					29 01 00 00 00 00 02 A6 03
+					29 01 00 00 00 00 02 A7 66
+					29 01 00 00 00 00 02 A9 03
+					29 01 00 00 00 00 02 AA 7A
+					29 01 00 00 00 00 02 AB 03
+					29 01 00 00 00 00 02 AC 93
+					29 01 00 00 00 00 02 AD 03
+					29 01 00 00 00 00 02 AE A3
+					29 01 00 00 00 00 02 AF 03
+					29 01 00 00 00 00 02 B0 B4
+					29 01 00 00 00 00 02 B1 03
+					29 01 00 00 00 00 02 B2 CB
+					29 01 00 00 00 00 02 B3 00
+					29 01 00 00 00 00 02 B4 7D
+					29 01 00 00 00 00 02 B5 00
+					29 01 00 00 00 00 02 B6 8A
+					29 01 00 00 00 00 02 B7 00
+					29 01 00 00 00 00 02 B8 9C
+					29 01 00 00 00 00 02 B9 00
+					29 01 00 00 00 00 02 BA B1
+					29 01 00 00 00 00 02 BB 00
+					29 01 00 00 00 00 02 BC BF
+					29 01 00 00 00 00 02 BD 00
+					29 01 00 00 00 00 02 BE CF
+					29 01 00 00 00 00 02 BF 00
+					29 01 00 00 00 00 02 C0 DD
+					29 01 00 00 00 00 02 C1 00
+					29 01 00 00 00 00 02 C2 E8
+					29 01 00 00 00 00 02 C3 00
+					29 01 00 00 00 00 02 C4 F2
+					29 01 00 00 00 00 02 C5 01
+					29 01 00 00 00 00 02 C6 1F
+					29 01 00 00 00 00 02 C7 01
+					29 01 00 00 00 00 02 C8 41
+					29 01 00 00 00 00 02 C9 01
+					29 01 00 00 00 00 02 CA 78
+					29 01 00 00 00 00 02 CB 01
+					29 01 00 00 00 00 02 CC A5
+					29 01 00 00 00 00 02 CD 01
+					29 01 00 00 00 00 02 CE EE
+					29 01 00 00 00 00 02 CF 02
+					29 01 00 00 00 00 02 D0 29
+					29 01 00 00 00 00 02 D1 02
+					29 01 00 00 00 00 02 D2 2A
+					29 01 00 00 00 00 02 D3 02
+					29 01 00 00 00 00 02 D4 5D
+					29 01 00 00 00 00 02 D5 02
+					29 01 00 00 00 00 02 D6 93
+					29 01 00 00 00 00 02 D7 02
+					29 01 00 00 00 00 02 D8 B8
+					29 01 00 00 00 00 02 D9 02
+					29 01 00 00 00 00 02 DA E7
+					29 01 00 00 00 00 02 DB 03
+					29 01 00 00 00 00 02 DC 07
+					29 01 00 00 00 00 02 DD 03
+					29 01 00 00 00 00 02 DE 37
+					29 01 00 00 00 00 02 DF 03
+					29 01 00 00 00 00 02 E0 46
+					29 01 00 00 00 00 02 E1 03
+					29 01 00 00 00 00 02 E2 56
+					29 01 00 00 00 00 02 E3 03
+					29 01 00 00 00 00 02 E4 66
+					29 01 00 00 00 00 02 E5 03
+					29 01 00 00 00 00 02 E6 7A
+					29 01 00 00 00 00 02 E7 03
+					29 01 00 00 00 00 02 E8 93
+					29 01 00 00 00 00 02 E9 03
+					29 01 00 00 00 00 02 EA A3
+					29 01 00 00 00 00 02 EB 03
+					29 01 00 00 00 00 02 EC B4
+					29 01 00 00 00 00 02 ED 03
+					29 01 00 00 00 00 02 EE CB
+					29 01 00 00 00 00 02 EF 00
+					29 01 00 00 00 00 02 F0 ED
+					29 01 00 00 00 00 02 F1 00
+					29 01 00 00 00 00 02 F2 F3
+					29 01 00 00 00 00 02 F3 00
+					29 01 00 00 00 00 02 F4 FE
+					29 01 00 00 00 00 02 F5 01
+					29 01 00 00 00 00 02 F6 09
+					29 01 00 00 00 00 02 F7 01
+					29 01 00 00 00 00 02 F8 13
+					29 01 00 00 00 00 02 F9 01
+					29 01 00 00 00 00 02 FA 1D
+					29 01 00 00 00 00 02 FF 02
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 00 01
+					29 01 00 00 00 00 02 01 26
+					29 01 00 00 00 00 02 02 01
+					29 01 00 00 00 00 02 03 2F
+					29 01 00 00 00 00 02 04 01
+					29 01 00 00 00 00 02 05 37
+					29 01 00 00 00 00 02 06 01
+					29 01 00 00 00 00 02 07 56
+					29 01 00 00 00 00 02 08 01
+					29 01 00 00 00 00 02 09 70
+					29 01 00 00 00 00 02 0A 01
+					29 01 00 00 00 00 02 0B 9D
+					29 01 00 00 00 00 02 0C 01
+					29 01 00 00 00 00 02 0D C2
+					29 01 00 00 00 00 02 0E 01
+					29 01 00 00 00 00 02 0F FF
+					29 01 00 00 00 00 02 10 02
+					29 01 00 00 00 00 02 11 31
+					29 01 00 00 00 00 02 12 02
+					29 01 00 00 00 00 02 13 32
+					29 01 00 00 00 00 02 14 02
+					29 01 00 00 00 00 02 15 60
+					29 01 00 00 00 00 02 16 02
+					29 01 00 00 00 00 02 17 94
+					29 01 00 00 00 00 02 18 02
+					29 01 00 00 00 00 02 19 B5
+					29 01 00 00 00 00 02 1A 02
+					29 01 00 00 00 00 02 1B E3
+					29 01 00 00 00 00 02 1C 03
+					29 01 00 00 00 00 02 1D 03
+					29 01 00 00 00 00 02 1E 03
+					29 01 00 00 00 00 02 1F 2D
+					29 01 00 00 00 00 02 20 03
+					29 01 00 00 00 00 02 21 3A
+					29 01 00 00 00 00 02 22 03
+					29 01 00 00 00 00 02 23 48
+					29 01 00 00 00 00 02 24 03
+					29 01 00 00 00 00 02 25 57
+					29 01 00 00 00 00 02 26 03
+					29 01 00 00 00 00 02 27 68
+					29 01 00 00 00 00 02 28 03
+					29 01 00 00 00 00 02 29 7B
+					29 01 00 00 00 00 02 2A 03
+					29 01 00 00 00 00 02 2B 90
+					29 01 00 00 00 00 02 2D 03
+					29 01 00 00 00 00 02 2F A0
+					29 01 00 00 00 00 02 30 03
+					29 01 00 00 00 00 02 31 CB
+					29 01 00 00 00 00 02 32 00
+					29 01 00 00 00 00 02 33 ED
+					29 01 00 00 00 00 02 34 00
+					29 01 00 00 00 00 02 35 F3
+					29 01 00 00 00 00 02 36 00
+					29 01 00 00 00 00 02 37 FE
+					29 01 00 00 00 00 02 38 01
+					29 01 00 00 00 00 02 39 09
+					29 01 00 00 00 00 02 3A 01
+					29 01 00 00 00 00 02 3B 13
+					29 01 00 00 00 00 02 3D 01
+					29 01 00 00 00 00 02 3F 1D
+					29 01 00 00 00 00 02 40 01
+					29 01 00 00 00 00 02 41 26
+					29 01 00 00 00 00 02 42 01
+					29 01 00 00 00 00 02 43 2F
+					29 01 00 00 00 00 02 44 01
+					29 01 00 00 00 00 02 45 37
+					29 01 00 00 00 00 02 46 01
+					29 01 00 00 00 00 02 47 56
+					29 01 00 00 00 00 02 48 01
+					29 01 00 00 00 00 02 49 70
+					29 01 00 00 00 00 02 4A 01
+					29 01 00 00 00 00 02 4B 9D
+					29 01 00 00 00 00 02 4C 01
+					29 01 00 00 00 00 02 4D C2
+					29 01 00 00 00 00 02 4E 01
+					29 01 00 00 00 00 02 4F FF
+					29 01 00 00 00 00 02 50 02
+					29 01 00 00 00 00 02 51 31
+					29 01 00 00 00 00 02 52 02
+					29 01 00 00 00 00 02 53 32
+					29 01 00 00 00 00 02 54 02
+					29 01 00 00 00 00 02 55 60
+					29 01 00 00 00 00 02 56 02
+					29 01 00 00 00 00 02 58 94
+					29 01 00 00 00 00 02 59 02
+					29 01 00 00 00 00 02 5A B5
+					29 01 00 00 00 00 02 5B 02
+					29 01 00 00 00 00 02 5C E3
+					29 01 00 00 00 00 02 5D 03
+					29 01 00 00 00 00 02 5E 03
+					29 01 00 00 00 00 02 5F 03
+					29 01 00 00 00 00 02 60 2D
+					29 01 00 00 00 00 02 61 03
+					29 01 00 00 00 00 02 62 3A
+					29 01 00 00 00 00 02 63 03
+					29 01 00 00 00 00 02 64 48
+					29 01 00 00 00 00 02 65 03
+					29 01 00 00 00 00 02 66 57
+					29 01 00 00 00 00 02 67 03
+					29 01 00 00 00 00 02 68 68
+					29 01 00 00 00 00 02 69 03
+					29 01 00 00 00 00 02 6A 7B
+					29 01 00 00 00 00 02 6B 03
+					29 01 00 00 00 00 02 6C 90
+					29 01 00 00 00 00 02 6D 03
+					29 01 00 00 00 00 02 6E A0
+					29 01 00 00 00 00 02 6F 03
+					29 01 00 00 00 00 02 70 CB
+					29 01 00 00 00 00 02 71 00
+					29 01 00 00 00 00 02 72 19
+					29 01 00 00 00 00 02 73 00
+					29 01 00 00 00 00 02 74 36
+					29 01 00 00 00 00 02 75 00
+					29 01 00 00 00 00 02 76 55
+					29 01 00 00 00 00 02 77 00
+					29 01 00 00 00 00 02 78 70
+					29 01 00 00 00 00 02 79 00
+					29 01 00 00 00 00 02 7A 83
+					29 01 00 00 00 00 02 7B 00
+					29 01 00 00 00 00 02 7C 99
+					29 01 00 00 00 00 02 7D 00
+					29 01 00 00 00 00 02 7E A8
+					29 01 00 00 00 00 02 7F 00
+					29 01 00 00 00 00 02 80 B7
+					29 01 00 00 00 00 02 81 00
+					29 01 00 00 00 00 02 82 C5
+					29 01 00 00 00 00 02 83 00
+					29 01 00 00 00 00 02 84 F7
+					29 01 00 00 00 00 02 85 01
+					29 01 00 00 00 00 02 86 1E
+					29 01 00 00 00 00 02 87 01
+					29 01 00 00 00 00 02 88 60
+					29 01 00 00 00 00 02 89 01
+					29 01 00 00 00 00 02 8A 95
+					29 01 00 00 00 00 02 8B 01
+					29 01 00 00 00 00 02 8C E1
+					29 01 00 00 00 00 02 8D 02
+					29 01 00 00 00 00 02 8E 20
+					29 01 00 00 00 00 02 8F 02
+					29 01 00 00 00 00 02 90 23
+					29 01 00 00 00 00 02 91 02
+					29 01 00 00 00 00 02 92 59
+					29 01 00 00 00 00 02 93 02
+					29 01 00 00 00 00 02 94 94
+					29 01 00 00 00 00 02 95 02
+					29 01 00 00 00 00 02 96 B4
+					29 01 00 00 00 00 02 97 02
+					29 01 00 00 00 00 02 98 E1
+					29 01 00 00 00 00 02 99 03
+					29 01 00 00 00 00 02 9A 01
+					29 01 00 00 00 00 02 9B 03
+					29 01 00 00 00 00 02 9C 28
+					29 01 00 00 00 00 02 9D 03
+					29 01 00 00 00 00 02 9E 30
+					29 01 00 00 00 00 02 9F 03
+					29 01 00 00 00 00 02 A0 37
+					29 01 00 00 00 00 02 A2 03
+					29 01 00 00 00 00 02 A3 3B
+					29 01 00 00 00 00 02 A4 03
+					29 01 00 00 00 00 02 A5 40
+					29 01 00 00 00 00 02 A6 03
+					29 01 00 00 00 00 02 A7 50
+					29 01 00 00 00 00 02 A9 03
+					29 01 00 00 00 00 02 AA 6D
+					29 01 00 00 00 00 02 AB 03
+					29 01 00 00 00 00 02 AC 80
+					29 01 00 00 00 00 02 AD 03
+					29 01 00 00 00 00 02 AE CB
+					29 01 00 00 00 00 02 AF 00
+					29 01 00 00 00 00 02 B0 19
+					29 01 00 00 00 00 02 B1 00
+					29 01 00 00 00 00 02 B2 36
+					29 01 00 00 00 00 02 B3 00
+					29 01 00 00 00 00 02 B4 55
+					29 01 00 00 00 00 02 B5 00
+					29 01 00 00 00 00 02 B6 70
+					29 01 00 00 00 00 02 B7 00
+					29 01 00 00 00 00 02 B8 83
+					29 01 00 00 00 00 02 B9 00
+					29 01 00 00 00 00 02 BA 99
+					29 01 00 00 00 00 02 BB 00
+					29 01 00 00 00 00 02 BC A8
+					29 01 00 00 00 00 02 BD 00
+					29 01 00 00 00 00 02 BE B7
+					29 01 00 00 00 00 02 BF 00
+					29 01 00 00 00 00 02 C0 C5
+					29 01 00 00 00 00 02 C1 00
+					29 01 00 00 00 00 02 C2 F7
+					29 01 00 00 00 00 02 C3 01
+					29 01 00 00 00 00 02 C4 1E
+					29 01 00 00 00 00 02 C5 01
+					29 01 00 00 00 00 02 C6 60
+					29 01 00 00 00 00 02 C7 01
+					29 01 00 00 00 00 02 C8 95
+					29 01 00 00 00 00 02 C9 01
+					29 01 00 00 00 00 02 CA E1
+					29 01 00 00 00 00 02 CB 02
+					29 01 00 00 00 00 02 CC 20
+					29 01 00 00 00 00 02 CD 02
+					29 01 00 00 00 00 02 CE 23
+					29 01 00 00 00 00 02 CF 02
+					29 01 00 00 00 00 02 D0 59
+					29 01 00 00 00 00 02 D1 02
+					29 01 00 00 00 00 02 D2 94
+					29 01 00 00 00 00 02 D3 02
+					29 01 00 00 00 00 02 D4 B4
+					29 01 00 00 00 00 02 D5 02
+					29 01 00 00 00 00 02 D6 E1
+					29 01 00 00 00 00 02 D7 03
+					29 01 00 00 00 00 02 D8 01
+					29 01 00 00 00 00 02 D9 03
+					29 01 00 00 00 00 02 DA 28
+					29 01 00 00 00 00 02 DB 03
+					29 01 00 00 00 00 02 DC 30
+					29 01 00 00 00 00 02 DD 03
+					29 01 00 00 00 00 02 DE 37
+					29 01 00 00 00 00 02 DF 03
+					29 01 00 00 00 00 02 E0 3B
+					29 01 00 00 00 00 02 E1 03
+					29 01 00 00 00 00 02 E2 40
+					29 01 00 00 00 00 02 E3 03
+					29 01 00 00 00 00 02 E4 50
+					29 01 00 00 00 00 02 E5 03
+					29 01 00 00 00 00 02 E6 6D
+					29 01 00 00 00 00 02 E7 03
+					29 01 00 00 00 00 02 E8 80
+					29 01 00 00 00 00 02 E9 03
+					29 01 00 00 00 00 02 EA CB
+					29 01 00 00 00 00 02 FF 01
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 FF 02
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 FF 04
+					29 01 00 00 00 00 02 FB 01
+					29 01 00 00 00 00 02 FF 00
+					29 01 00 00 64 00 02 11 00
+					29 01 00 00 00 00 02 FF EE
+					29 01 00 00 00 00 02 12 50
+					29 01 00 00 00 00 02 13 02
+					29 01 00 00 00 00 02 6A 60
+					29 01 00 00 00 00 02 FF 00
+					29 01 00 00 78 00 02 29 00];
 
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
-		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
-					05 01 00 00 78 02 10 00];
+		qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
 		qcom,off-cmds-dsi-state = "DSI_HS_MODE";
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
index a27a88a..478541f 100644
--- a/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-orise-720p-video.dtsi
@@ -50,11 +50,11 @@
 					     00 c2 45 00 00 00 00 01 75 /* lane3 config */
 					     00 02 45 00 00 00 00 01 97]; /* Clk ln config */
 
-		qcom,panel-on-cmds = [05 01 00 00 78 02 11 00
-					05 01 00 00 78 02 29 00];
+		qcom,panel-on-cmds = [05 01 00 00 78 00 02 11 00
+					05 01 00 00 78 00 02 29 00];
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
-		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
-					05 01 00 00 78 02 10 00];
+		qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
 		qcom,off-cmds-dsi-state = "DSI_LP_MODE";
 	};
 };
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 d182bac..45d396c 100644
--- a/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sharp-qhd-video.dtsi
@@ -52,16 +52,16 @@
 					     00 00 00 00 0a 00 00 01 97 /* lane2 config */
 					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
 					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
-		qcom,panel-on-cmds = [05 01 00 00 32 02 01 00 /* sw reset */
-					05 01 00 00 0a 02 11 00 /* exit sleep */
-					15 01 00 00 0a 02 53 2c /* backlight on */
-					15 01 00 00 0a 02 51 ff /* brightness max */
-					05 01 00 00 0a 02 29 00 /* display on */
-					15 01 00 00 0a 02 ae 03 /* set num of lanes */
-					15 01 00 00 0a 02 3a 77 /* rgb_888 */];
+		qcom,panel-on-cmds = [05 01 00 00 32 00 02 01 00 /* sw reset */
+					05 01 00 00 0a 00 02 11 00 /* exit sleep */
+					15 01 00 00 0a 00 02 53 2c /* backlight on */
+					15 01 00 00 0a 00 02 51 ff /* brightness max */
+					05 01 00 00 0a 00 02 29 00 /* display on */
+					15 01 00 00 0a 00 02 ae 03 /* set num of lanes */
+					15 01 00 00 0a 00 02 3a 77 /* rgb_888 */];
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
-		qcom,panel-off-cmds = [05 01 00 00 0a 02 28 00 /* display off */
-					05 01 00 00 78 02 10 00 /* enter sleep */];
+		qcom,panel-off-cmds = [05 01 00 00 0a 00 02 28 00 /* display off */
+					05 01 00 00 78 00 02 10 00 /* enter sleep */];
 		qcom,off-cmds-dsi-state = "DSI_HS_MODE";
 	};
 };
diff --git a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
index 3b39dea..271e373 100644
--- a/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-sim-video.dtsi
@@ -38,9 +38,9 @@
 		qcom,mdss-pan-dsi-mdp-tr = <0x04>;
 		qcom,mdss-pan-dsi-dma-tr = <0x04>;
 		qcom,mdss-pan-dsi-frame-rate = <60>;
-		qcom,panel-on-cmds = [32 01 00 00 00 02 00 00];
+		qcom,panel-on-cmds = [32 01 00 00 00 00 02 00 00];
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
-		qcom,panel-off-cmds = [22 01 00 00 00 02 00 00];
+		qcom,panel-off-cmds = [22 01 00 00 00 00 02 00 00];
 		qcom,off-cmds-dsi-state = "DSI_LP_MODE";
 	};
 };
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 82b57cd..5c37cf8 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -54,71 +54,71 @@
 					     00 00 00 00 0f 00 00 01 97 /* lane3 config */
 					     00 c0 00 00 00 00 00 01 bb]; /* Clk ln config */
 
-		qcom,panel-on-cmds = [23 01 00 00 0a 02 b0 00
-					23 01 00 00 0a 02 b2 00
-					23 01 00 00 0a 02 b3 0c
-					23 01 00 00 0a 02 b4 02
-					29 01 00 00 00 06
+		qcom,panel-on-cmds = [23 01 00 00 0a 00 02 b0 00
+					23 01 00 00 0a 00 02 b2 00
+					23 01 00 00 0a 00 02 b3 0c
+					23 01 00 00 0a 00 02 b4 02
+					29 01 00 00 00 00 06
 						c0 40 02 7f c8 08
-					29 01 00 00 00 10
+					29 01 00 00 00 00 10
 						c1 00 a8 00 00 00
 						00 00 9d 08 27 00
 						00 00 00 00
-					29 01 00 00 00 06
+					29 01 00 00 00 00 06
 						c2 00 00 09 00 00
-					23 01 00 00 0a 02 c3 04
-					29 01 00 00 00 04
+					23 01 00 00 0a 00 02 c3 04
+					29 01 00 00 00 00 04
 						c4 4d 83 00
-					29 01 00 00 00 0b
+					29 01 00 00 00 00 0b
 						c6 12 00 08 71 00
 						00 00 80 00 04
-					23 01 00 00 0a 02 c7 22
-					29 01 00 00 00 05
+					23 01 00 00 0a 00 02 c7 22
+					29 01 00 00 00 00 05
 						c8 4c 0c 0c 0c
-					29 01 00 00 00 0e
+					29 01 00 00 00 00 0e
 						c9 00 40 00 16 32
 						2e 3a 43 3e 3c 45
 						79 3f
-					29 01 00 00 00 0e
+					29 01 00 00 00 00 0e
 						ca 00 46 1a 23 21
 						1c 25 31 2d 49 5f
 						7f 3f
-					29 01 00 00 00 0e
+					29 01 00 00 00 00 0e
 						cb 00 4c 20 3a 42
 						40 47 4b 42 3e 46
 						7e 3f
-					29 01 00 00 00 0e
+					29 01 00 00 00 00 0e
 						cc 00 41 19 21 1d
 						14 18 1f 1d 25 3f
 						73 3f
-					29 01 00 00 00 0e
+					29 01 00 00 00 00 0e
 						cd 23 79 5a 5f 57
 						4c 51 51 45 3f 4b
 						7f 3f
-					29 01 00 00 00 0e
+					29 01 00 00 00 00 0e
 						ce 00 40 14 20 1a
 						0e 0e 13 08 00 05
 						46 1c
-					29 01 00 00 00 04
+					29 01 00 00 00 00 04
 						d0 6a 64 01
-					29 01 00 00 00 03 d1 77 d4
-					23 01 00 00 0a 02 d3 33
-					29 01 00 00 00 03 d5 0f 0f
-					29 01 00 00 00 07
+					29 01 00 00 00 00 03 d1 77 d4
+					23 01 00 00 0a 00 02 d3 33
+					29 01 00 00 00 00 03 d5 0f 0f
+					29 01 00 00 00 00 07
 						d8 34 64 23 25 62
 						32
-					29 01 00 00 00 0c
+					29 01 00 00 00 00 0c
 						de 10 7b 11 0a 00
 						00 00 00 00 00 00
-					29 01 00 00 00 09
+					29 01 00 00 00 00 09
 						fd 04 55 53 00 70
 						ff 10 73
-					23 01 00 00 0a 02 e2 00
-					05 01 00 00 78 02 11 00
-					05 01 00 00 32 02 29 00];
+					23 01 00 00 0a 00 02 e2 00
+					05 01 00 00 78 00 02 11 00
+					05 01 00 00 32 00 02 29 00];
 		qcom,on-cmds-dsi-state = "DSI_LP_MODE";
-		qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
-					05 01 00 00 78 02 10 00];
+		qcom,panel-off-cmds = [05 01 00 00 32 00 02 28 00
+					05 01 00 00 78 00 02 10 00];
 		qcom,off-cmds-dsi-state = "DSI_HS_MODE";
 	};
 };
diff --git a/arch/arm/boot/dts/mpq8092-ion.dtsi b/arch/arm/boot/dts/mpq8092-ion.dtsi
index ee3fbc4..f9f5985 100644
--- a/arch/arm/boot/dts/mpq8092-ion.dtsi
+++ b/arch/arm/boot/dts/mpq8092-ion.dtsi
@@ -20,58 +20,14 @@
 			reg = <30>;
 		};
 
-		qcom,ion-heap@8 { /* CP_MM HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <8>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x7800000>;
-		};
-
-		qcom,ion-heap@29 { /* FIRMWARE HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <29>;
-			qcom,heap-align = <0x20000>;
-			qcom,heap-adjacent = <8>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0xA00000>;
-		};
-
-		qcom,ion-heap@12 { /* MFC HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <12>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x2000>;
-		};
-
-		qcom,ion-heap@24 { /* SF HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <24>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x2800000>;
+		qcom,ion-heap@21 { /* SYSTEM CONTIG HEAP */
+			reg = <21>;
 		};
 
 		qcom,ion-heap@25 { /* IOMMU HEAP */
 			reg = <25>;
 		};
 
-		qcom,ion-heap@27 { /* QSECOM HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <27>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x600000>;
-		};
-
-		qcom,ion-heap@28 { /* AUDIO HEAP */
-			compatible = "qcom,msm-ion-reserve";
-			reg = <28>;
-			qcom,heap-align = <0x1000>;
-			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x2B4000>;
-		};
 	};
 };
 
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index ce97d4d..676ef3b 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -16,7 +16,7 @@
 
 / {
 	model = "Qualcomm MPQ8092 Simulator";
-	compatible = "qcom,mpq8092-sim", "qcom,mpq8092";
+	compatible = "qcom,mpq8092-sim", "qcom,mpq8092", "qcom,sim";
 	qcom,msm-id = <126 16 0>;
 };
 
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index e22e398..e1f0e61 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -286,6 +286,7 @@
 			qcom,chg-term-ua = <100000>;
 			qcom,batt-type = <0>;
 			qcom,low-voltage-threshold = <3420000>;
+			qcom,tm-temp-margin = <5000>;
 			qcom,low-ocv-correction-limit-uv = <100>;
 			qcom,high-ocv-correction-limit-uv = <50>;
 			qcom,hold-soc-est = <3>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 4d6751c..0db886b 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -173,6 +173,7 @@
 			qcom,calculate-soc-ms = <20000>;
 			qcom,chg-term-ua = <100000>;
 			qcom,batt-type = <0>;
+			qcom,tm-temp-margin = <5000>;
 			qcom,low-ocv-correction-limit-uv = <100>;
 			qcom,high-ocv-correction-limit-uv = <50>;
 			qcom,hold-soc-est = <3>;
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index ce6bc63..34ea33d 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -116,6 +116,7 @@
 			qcom,chg-term-ua = <100000>;
 			qcom,batt-type = <0>;
 			qcom,low-voltage-threshold = <3420000>;
+			qcom,tm-temp-margin = <5000>;
 			qcom,low-ocv-correction-limit-uv = <100>;
 			qcom,high-ocv-correction-limit-uv = <50>;
 			qcom,hold-soc-est = <3>;
@@ -173,7 +174,7 @@
 
 			qcom,vddmax-mv = <4200>;
 			qcom,vddsafe-mv = <4200>;
-			qcom,vinmin-mv = <4200>;
+			qcom,vinmin-mv = <4300>;
 			qcom,ibatmax-ma = <1500>;
 			qcom,ibatterm-ma = <100>;
 			qcom,ibatsafe-ma = <1500>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index 07f16b9..41d6b7e 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -73,7 +73,7 @@
 		reg = <0x6d>;
 		qcom,slave-id = <0x20 0x0 0x9724>;
 		qcom,csiphy-sd-index = <1>;
-		qcom,csid-sd-index = <0>;
+		qcom,csid-sd-index = <1>;
 		qcom,mount-angle = <0>;
 		qcom,sensor-name = "ov9724";
 		cam_vdig-supply = <&pm8226_l5>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index f06033e..53860ac 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -73,8 +73,8 @@
 		reg = <0x6d>;
 		qcom,slave-id = <0x20 0x0 0x9724>;
 		qcom,csiphy-sd-index = <1>;
-		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <90>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
 		qcom,sensor-name = "ov9724";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 47f4049..3935dbb 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -73,8 +73,8 @@
 		reg = <0x6d>;
 		qcom,slave-id = <0x20 0x0 0x9724>;
 		qcom,csiphy-sd-index = <1>;
-		qcom,csid-sd-index = <0>;
-		qcom,mount-angle = <90>;
+		qcom,csid-sd-index = <1>;
+		qcom,mount-angle = <270>;
 		qcom,sensor-name = "ov9724";
 		cam_vdig-supply = <&pm8226_l5>;
 		cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera.dtsi b/arch/arm/boot/dts/msm8226-camera.dtsi
index 0dae162..ec0092d 100644
--- a/arch/arm/boot/dts/msm8226-camera.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera.dtsi
@@ -21,8 +21,9 @@
 	qcom,csiphy@fda0ac00 {
 		cell-index = <0>;
 		compatible = "qcom,csiphy";
-		reg = <0xfda0ac00 0x200>;
-		reg-names = "csiphy";
+		reg = <0xfda0ac00 0x200>,
+			<0xfda00030 0x4>;
+		reg-names = "csiphy", "csiphy_clk_mux";
 		interrupts = <0 78 0>;
 		interrupt-names = "csiphy";
 	};
@@ -30,8 +31,9 @@
 	qcom,csiphy@fda0b000 {
 		cell-index = <1>;
 		compatible = "qcom,csiphy";
-		reg = <0xfda0b000 0x200>;
-		reg-names = "csiphy";
+		reg = <0xfda0b000 0x200>,
+			<0xfda00038 0x4>;
+		reg-names = "csiphy", "csiphy_clk_mux";
 		interrupts = <0 79 0>;
 		interrupt-names = "csiphy";
 	};
@@ -61,8 +63,9 @@
 	qcom,ispif@fda0a000 {
 		cell-index = <0>;
 		compatible = "qcom,ispif";
-		reg = <0xfda0a000 0x500>;
-		reg-names = "ispif";
+		reg = <0xfda0a000 0x500>,
+			<0xfda00020 0x10>;
+		reg-names = "ispif", "csi_clk_mux";
 		interrupts = <0 55 0>;
 		interrupt-names = "ispif";
 	};
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 0d9ae9a..516522e 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -340,4 +340,18 @@
 		coresight-name = "coresight-cti-cpu3";
 		coresight-nr-inports = <0>;
 	};
+
+	hwevent: hwevent@fd820018 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0xfd820018 0x80>,
+		      <0xf9011080 0x80>,
+		      <0xfd4ab160 0x80>;
+		reg-names = "mmss-mux", "apcs-mux", "ppss-mux";
+
+		coresight-id = <27>;
+		coresight-name = "coresight-hwevent";
+		coresight-nr-inports = <0>;
+
+		qcom,hwevent-clks = "core_mmss_clk";
+	};
 };
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
index b574a31..efd9c32 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-cdp.dtsi
@@ -89,11 +89,15 @@
 		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
 		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>;
+			<&msmgpio 90 0>,
+			<&msmgpio 89 0>;
 		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+					  "CAM_RESET1",
+					  "CAM_STANDBY";
 		qcom,gpio-set-tbl-num = <1 1>;
 		qcom,gpio-set-tbl-flags = <0 2>;
 		qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
index 748d5f7..9cbd45c 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-fluid.dtsi
@@ -90,11 +90,15 @@
 		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
 		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>;
+			<&msmgpio 90 0>,
+			<&msmgpio 89 0>;
 		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+					  "CAM_RESET1",
+					  "CAM_STANDBY";
 		qcom,gpio-set-tbl-num = <1 1>;
 		qcom,gpio-set-tbl-flags = <0 2>;
 		qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index 5a97a11..e9d3d75 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -86,11 +86,15 @@
 		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
 		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>;
+			<&msmgpio 90 0>,
+			<&msmgpio 89 0>;
 		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+					  "CAM_RESET1",
+					  "CAM_STANDBY";
 		qcom,gpio-set-tbl-num = <1 1>;
 		qcom,gpio-set-tbl-flags = <0 2>;
 		qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
index 53f6e9e..68af4a6 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-mtp.dtsi
@@ -90,11 +90,15 @@
 		qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
 		qcom,gpio-no-mux = <0>;
 		gpios = <&msmgpio 15 0>,
-			<&msmgpio 90 0>;
+			<&msmgpio 90 0>,
+			<&msmgpio 89 0>;
 		qcom,gpio-reset = <1>;
-		qcom,gpio-req-tbl-num = <0 1>;
-		qcom,gpio-req-tbl-flags = <1 0>;
-		qcom,gpio-req-tbl-label = "CAMIF_MCLK", "CAM_RESET1";
+		qcom,gpio-standby = <2>;
+		qcom,gpio-req-tbl-num = <0 1 2>;
+		qcom,gpio-req-tbl-flags = <1 0 0>;
+		qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+					  "CAM_RESET1",
+					  "CAM_STANDBY";
 		qcom,gpio-set-tbl-num = <1 1>;
 		qcom,gpio-set-tbl-flags = <0 2>;
 		qcom,gpio-set-tbl-delay = <1000 30000>;
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 5fa7c08..3e65b8a 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -247,7 +247,7 @@
 				<85 512 40000 160000>,
 				<85 512 40000 320000>,
 				<85 512 40000 480000>,
-				<85 512 40000 640000>;
+				<85 512 40000 800000>;
 	};
 };
 
diff --git a/arch/arm/configs/mpq8092_defconfig b/arch/arm/configs/mpq8092_defconfig
index 28ca32f..c06161d 100644
--- a/arch/arm/configs/mpq8092_defconfig
+++ b/arch/arm/configs/mpq8092_defconfig
@@ -54,6 +54,7 @@
 CONFIG_MSM_RUN_QUEUE_STATS=y
 CONFIG_MSM_SPM_V2=y
 CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_MULTIMEDIA_USE_ION=y
 CONFIG_MSM_OCMEM=y
 CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
 CONFIG_MSM_OCMEM_DEBUG=y
@@ -268,6 +269,8 @@
 CONFIG_REGULATOR_QPNP=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CONTROLLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
@@ -299,6 +302,16 @@
 CONFIG_USB_STORAGE_KARMA=y
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=m
+CONFIG_MMC_MSM=y
 CONFIG_LEDS_QPNP=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_BACKLIGHT=y
@@ -319,6 +332,7 @@
 CONFIG_QPNP_POWER_ON=y
 CONFIG_QPNP_CLKDIV=y
 CONFIG_MSM_IOMMU=y
+CONFIG_IOMMU_PGTABLES_L2=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index aea092e..ba36df1 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -370,6 +370,7 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SHIRQ=y
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index dda9bd3..5885c6e 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -428,6 +428,7 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index f90e5f3..6c18a97 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -510,6 +510,7 @@
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index bae4ee9..72032dc 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -459,6 +459,7 @@
 CONFIG_PRINTK_TIME=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_TIMER_STATS=y
+CONFIG_SCHEDSTATS=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_MEMORY_INIT=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 662d555..f434199 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -258,6 +258,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_MMC=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 7891990..2a1215d 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -258,6 +258,7 @@
 CONFIG_USB_STORAGE_CYPRESS_ATACB=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_CI13XXX_MSM=y
 CONFIG_USB_G_ANDROID=y
 CONFIG_MMC=y
@@ -319,8 +320,8 @@
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_TWOFISH=y
 CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_DEV_QCRYPTO=m
-CONFIG_CRYPTO_DEV_QCE=m
-CONFIG_CRYPTO_DEV_QCEDEV=m
+#CONFIG_CRYPTO_DEV_QCRYPTO is not set
+#CONFIG_CRYPTO_DEV_QCE is not set
+#CONFIG_CRYPTO_DEV_QCEDEV is not set
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index 2a46914..07a09b5 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -196,7 +196,7 @@
 
 struct membank {
 	phys_addr_t start;
-	unsigned long size;
+	phys_addr_t size;
 	unsigned int highmem;
 };
 
@@ -218,7 +218,7 @@
 #define bank_phys_end(bank)	((bank)->start + (bank)->size)
 #define bank_phys_size(bank)	(bank)->size
 
-extern int arm_add_memory(phys_addr_t start, unsigned long size);
+extern int arm_add_memory(phys_addr_t start, phys_addr_t size);
 extern void early_print(const char *str, ...);
 extern void dump_machine_table(void);
 
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 4aabf0e..28b114f 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -510,7 +510,7 @@
 		/* can't use cpu_relax() here as it may require MMU setup */;
 }
 
-int __init arm_add_memory(phys_addr_t start, unsigned long size)
+int __init arm_add_memory(phys_addr_t start, phys_addr_t size)
 {
 	struct membank *bank = &meminfo.bank[meminfo.nr_banks];
 
@@ -540,7 +540,7 @@
 	}
 #endif
 
-	bank->size = size & PAGE_MASK;
+	bank->size = size & ~(phys_addr_t)(PAGE_SIZE - 1);
 
 	/*
 	 * Check whether this memory region has non-zero size or
@@ -560,7 +560,7 @@
 static int __init early_mem(char *p)
 {
 	static int usermem __initdata = 0;
-	unsigned long size;
+	phys_addr_t size;
 	phys_addr_t start;
 	char *endp;
 
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 0eecffd..be0daf3 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -145,7 +145,7 @@
 	select CPU_V7
 	select GPIO_MSM_V2
 	select MSM_GPIOMUX
-	select MSM_SCM if SMP
+	select MSM_SCM
 	select MSM_DIRECT_SCLK_ACCESS
 	select REGULATOR
 	select MSM_RPM_REGULATOR
@@ -187,7 +187,7 @@
 	select CPU_V7
 	select GPIO_MSM_V2
 	select MSM_GPIOMUX
-	select MSM_SCM if SMP
+	select MSM_SCM
 	select MSM_DIRECT_SCLK_ACCESS
 	select REGULATOR
 	select MSM_RPM_REGULATOR
@@ -223,7 +223,7 @@
 	select GPIO_MSM_V2
 	select ARM_GIC
 	select CPU_V7
-	select MSM_SCM if SMP
+	select MSM_SCM
 	select MSM_GPIOMUX
 	select MSM_REMOTE_SPINLOCK_SFPB
 	select MSM_PIL
@@ -257,7 +257,7 @@
 	select GPIO_MSM_V3
 	select ARM_GIC
 	select CPU_V7
-	select MSM_SCM if SMP
+	select MSM_SCM
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
 	select MSM_MULTIMEDIA_USE_ION
@@ -292,7 +292,7 @@
 	select GPIO_MSM_V3
 	select ARM_GIC
 	select CPU_V7
-	select MSM_SCM if SMP
+	select MSM_SCM
 	select MSM_GPIOMUX
 	select MULTI_IRQ_HANDLER
 	select MSM_NATIVE_RESTART
@@ -317,6 +317,25 @@
 	select SPARSE_IRQ
 	select MSM_NOPM
 
+config ARCH_FSM9900
+	bool "FSM9900"
+	select ARCH_MSM_KRAITMP
+	select GPIO_MSM_V3
+	select ARM_GIC
+	select CPU_V7
+	select MSM_SCM
+	select MSM_GPIOMUX
+	select MULTI_IRQ_HANDLER
+	select MSM_PIL
+	select MSM_NATIVE_RESTART
+	select MSM_RESTART_V2
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select REGULATOR
+	select ARM_HAS_SG_CHAIN
+	select MSM_RUN_QUEUE_STATS
+	select MSM_NOPM
+
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
 	select ARCH_MSM_SCORPION
@@ -378,7 +397,6 @@
 	select MSM_RESTART_V2
 	select MSM_SPM_V2
 	select MSM_PM8X60 if PM
-	select MSM_SCM if SMP
 	select MULTI_IRQ_HANDLER
 	select GPIO_MSM_V3
 	select MAY_HAVE_SPARSE_IRQ
@@ -414,7 +432,7 @@
 	select GIC_SECURE
 	select ARCH_MSM_CORTEXMP
 	select CPU_V7
-	select MSM_SCM if SMP
+	select MSM_SCM
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select MULTI_IRQ_HANDLER
@@ -456,7 +474,7 @@
 	select GIC_SECURE
 	select ARCH_MSM_CORTEXMP
 	select CPU_V7
-	select MSM_SCM if SMP
+	select MSM_SCM
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
 	select MULTI_IRQ_HANDLER
@@ -1094,6 +1112,7 @@
 	default "0x00000000" if ARCH_MSM8226
 	default "0x00000000" if ARCH_MSM8610
 	default "0x10000000" if ARCH_FSM9XXX
+	default "0x00000000" if ARCH_FSM9900
 	default "0x00200000" if ARCH_MSM9625
 	default "0x00000000" if ARCH_MSMKRYPTON
 	default "0x00200000" if !MSM_STACKED_MEMORY
@@ -1257,6 +1276,14 @@
                 help
                   Say Y here if you want the debug print routines to direct
                   their output to the serial port on MSM9625 devices.
+
+	config DEBUG_FSM9900_UART
+		bool "Kernel low-level debugging messages via FSM9900 UART"
+		depends on ARCH_FSM9900
+		select MSM_HAS_DEBUG_UART_HS_V14
+		help
+		  Say Y here if you want the debug print routines to direct
+		  their output to the serial port on FSM9900 devices.
 endchoice
 
 choice
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 321040e..f53b7fe 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -75,7 +75,7 @@
 $(obj)/smd_rpc_sym.c: $(src)/smd_rpc_sym $(src)/mkrpcsym.pl
 	$(call if_changed,mkrpcsym)
 
-obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o
+obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o remote_spinlock.o smd_private.o smem.o
 obj-$(CONFIG_MSM_SMP2P) += smp2p.o smp2p_debug.o smp2p_gpio.o
 obj-$(CONFIG_MSM_SMP2P_TEST) += smp2p_loopback.o smp2p_test.o smp2p_gpio_test.o smp2p_spinlock_test.o
 obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o
@@ -121,6 +121,7 @@
 ifndef CONFIG_ARCH_MSM8610
 ifndef CONFIG_ARCH_APQ8084
 ifndef CONFIG_ARCH_MSMKRYPTON
+ifndef CONFIG_ARCH_FSM9900
 	obj-y += nand_partitions.o
 endif
 endif
@@ -132,6 +133,7 @@
 endif
 endif
 endif
+endif
 obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
 obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
 obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -230,6 +232,7 @@
 obj-$(CONFIG_ARCH_FSM9XXX) += clock-fsm9xxx.o clock-local.o acpuclock-fsm9xxx.o
 obj-$(CONFIG_ARCH_FSM9XXX) += dfe-fsm9xxx.o rfic-fsm9xxx.o
 obj-$(CONFIG_ARCH_FSM9XXX) += restart-fsm9xxx.o xo-fsm9xxx.o
+obj-$(CONFIG_ARCH_FSM9900) += board-fsm9900.o board-fsm9900-gpiomux.o
 
 obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog.o
 obj-$(CONFIG_MSM_WATCHDOG) += msm_watchdog_asm.o
@@ -377,6 +380,7 @@
 obj-$(CONFIG_ARCH_MSM8226) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8610) += gpiomux-v2.o gpiomux.o
 obj-$(CONFIG_ARCH_APQ8084) += gpiomux-v2.o gpiomux.o
+obj-$(CONFIG_ARCH_FSM9900) += gpiomux-v2.o gpiomux.o
 
 obj-$(CONFIG_MSM_SLEEP_STATS_DEVICE) += idle_stats_device.o
 obj-$(CONFIG_MSM_DCVS) += msm_dcvs_scm.o msm_dcvs.o msm_mpdecision.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 2827e65..07969e0 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -93,6 +93,11 @@
 params_phys-$(CONFIG_ARCH_FSM9XXX)	:= 0x10000100
 initrd_phys-$(CONFIG_ARCH_FSM9XXX)	:= 0x12000000
 
+# FSM9900
+   zreladdr-$(CONFIG_ARCH_FSM9900)	:= 0x00008000
+        dtb-$(CONFIG_ARCH_FSM9900)	:= fsm9900-rumi.dtb
+        dtb-$(CONFIG_ARCH_FSM9900)	:= fsm9900-sim.dtb
+
 # MPQ8092
    zreladdr-$(CONFIG_ARCH_MPQ8092)	:= 0x00008000
 
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index 6adff30..cd95bf3 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -38,6 +38,11 @@
 static struct clk_lookup msm_clocks_dummy[] = {
 	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
 	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+	CLK_DUMMY("core_clk",	SDC1_CLK,	"msm_sdcc.1", OFF),
+	CLK_DUMMY("iface_clk",	SDC1_P_CLK,	"msm_sdcc.1", OFF),
+	CLK_DUMMY("core_clk",	SDC2_CLK,	"msm_sdcc.2", OFF),
+	CLK_DUMMY("iface_clk",	SDC2_P_CLK,	"msm_sdcc.2", OFF),
+
 };
 
 struct clock_init_data mpq8092_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/board-fsm9900-gpiomux.c b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
new file mode 100644
index 0000000..dede706
--- /dev/null
+++ b/arch/arm/mach-msm/board-fsm9900-gpiomux.c
@@ -0,0 +1,29 @@
+/* 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/gpio.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+
+void __init fsm9900_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init_dt();
+	if (rc) {
+		pr_err("%s failed %d\n", __func__, rc);
+		return;
+	}
+}
diff --git a/arch/arm/mach-msm/board-fsm9900.c b/arch/arm/mach-msm/board-fsm9900.c
new file mode 100644
index 0000000..7177355
--- /dev/null
+++ b/arch/arm/mach-msm/board-fsm9900.c
@@ -0,0 +1,102 @@
+/* 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/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/memory.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smd.h>
+#include <mach/restart.h>
+#include <mach/socinfo.h>
+#include <mach/clk-provider.h>
+#include "board-dt.h"
+#include "clock.h"
+#include "devices.h"
+#include "platsmp.h"
+
+void __init fsm9900_reserve(void)
+{
+}
+
+static void __init fsm9900_early_memory(void)
+{
+}
+
+static struct clk_lookup msm_clocks_dummy[] = {
+	CLK_DUMMY("core_clk",   BLSP2_UART_CLK, "f9960000.serial", OFF),
+	CLK_DUMMY("iface_clk",  BLSP2_UART_CLK, "f9960000.serial", OFF),
+	CLK_DUMMY("core_clk",   BLSP1_UART_CLK, "f991f000.serial", OFF),
+	CLK_DUMMY("iface_clk",  BLSP1_UART_CLK, "f991f000.serial", OFF),
+};
+
+static struct clock_init_data msm_dummy_clock_init_data __initdata = {
+	.table = msm_clocks_dummy,
+	.size = ARRAY_SIZE(msm_clocks_dummy),
+};
+
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init fsm9900_add_drivers(void)
+{
+	msm_smd_init();
+	msm_clock_init(&msm_dummy_clock_init_data);
+}
+
+static void __init fsm9900_map_io(void)
+{
+	msm_map_fsm9900_io();
+}
+
+void __init fsm9900_init(void)
+{
+	if (socinfo_init() < 0)
+		pr_err("%s: socinfo_init() failed\n", __func__);
+
+	fsm9900_init_gpiomux();
+	board_dt_populate(NULL);
+	fsm9900_add_drivers();
+}
+
+void __init fsm9900_init_very_early(void)
+{
+	fsm9900_early_memory();
+}
+
+static const char *fsm9900_dt_match[] __initconst = {
+	"qcom,fsm9900",
+	NULL
+};
+
+DT_MACHINE_START(FSM9900_DT, "Qualcomm FSM 9900 (Flattened Device Tree)")
+	.map_io = fsm9900_map_io,
+	.init_irq = msm_dt_init_irq,
+	.init_machine = fsm9900_init,
+	.handle_irq = gic_handle_irq,
+	.timer = &msm_dt_timer,
+	.dt_compat = fsm9900_dt_match,
+	.reserve = fsm9900_reserve,
+	.init_very_early = fsm9900_init_very_early,
+	.restart = msm_restart,
+	.smp = &msm8974_smp_ops,
+MACHINE_END
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index ac5efc1..7fe3f97 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3327,31 +3327,40 @@
 		"fda0b000.qcom,csiphy"),
 
 	/* CSID clocks */
-	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
-		"fda08000.qcom,csid"),
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
-		"fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c,       "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c,  "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_clk", camss_csi0_clk.c,         "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c,  "fda08000.qcom,csid"),
-	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c,  "fda08000.qcom,csid"),
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi0_ahb_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi0_clk_src.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi0phy_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi0_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi0pix_clk.c,
+					"fda08000.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi0rdi_clk.c,
+					"fda08000.qcom,csid"),
 
-	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
-		"fda08400.qcom,csid"),
+
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
-		"fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_ahb_clk", camss_csi0_ahb_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_ahb_clk", camss_csi1_ahb_clk.c, "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_src_clk", csi0_clk_src.c,       "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_src_clk", csi1_clk_src.c,       "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_phy_clk", camss_csi0phy_clk.c,  "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_phy_clk", camss_csi1phy_clk.c,  "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_pix_clk", camss_csi0pix_clk.c,  "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_pix_clk", camss_csi1pix_clk.c,  "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi0_rdi_clk", camss_csi0rdi_clk.c,  "fda08400.qcom,csid"),
-	CLK_LOOKUP("csi1_rdi_clk", camss_csi1rdi_clk.c,  "fda08400.qcom,csid"),
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("camss_top_ahb_clk", camss_top_ahb_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_ahb_clk", camss_csi1_ahb_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_src_clk", csi1_clk_src.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_phy_clk", camss_csi1phy_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_clk", camss_csi1_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_pix_clk", camss_csi1pix_clk.c,
+					"fda08400.qcom,csid"),
+	CLK_LOOKUP("csi_rdi_clk", camss_csi1rdi_clk.c,
+					"fda08400.qcom,csid"),
 
 	/* ISPIF clocks */
 	CLK_LOOKUP("ispif_ahb_clk", camss_ispif_ahb_clk.c,
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index aa9368d..17468d2 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -2819,6 +2819,7 @@
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34d000.jtagmm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34e000.jtagmm"),
 	CLK_LOOKUP("core_clk", qdss_clk.c, "fc34f000.jtagmm"),
+	CLK_LOOKUP("core_clk", qdss_clk.c, "fd820018.hwevent"),
 
 
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc326000.tmc"),
@@ -2852,8 +2853,9 @@
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34d000.jtagmm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34e000.jtagmm"),
 	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc34f000.jtagmm"),
+	CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fd820018.hwevent"),
 
-
+	CLK_LOOKUP("core_mmss_clk", mmss_misc_ahb_clk.c, "fd820018.hwevent"),
 
 	CLK_LOOKUP("core_clk_src", blsp1_qup1_spi_apps_clk_src.c, ""),
 	CLK_LOOKUP("core_clk_src", blsp1_qup2_spi_apps_clk_src.c, ""),
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index bf95615..17a6801 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -409,9 +409,9 @@
 static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
 {
 	if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
-		c->rate = 53000000;
-		dsi_pll_rate = 53000000;
-		pll_byte_clk_rate = 53000000;
+		c->rate = 52954560;
+		dsi_pll_rate = 52954560;
+		pll_byte_clk_rate = 52954560;
 		pll_pclk_rate = 105000000;
 		dsipll_refcount++;
 		return HANDOFF_ENABLED_CLK;
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index d2be1f9..8d99ad1 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,10 +19,10 @@
 
 #include <mach/scm-io.h>
 #include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
 
 #include "clock.h"
 #include "clock-pll.h"
-#include "smd_private.h"
 
 #ifdef CONFIG_MSM_SECURE_IO
 #undef readl_relaxed
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 22f74c8..690e52a 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -599,6 +599,8 @@
 void msm_map_apq8064_io(void);
 void msm_map_msm7x30_io(void);
 void msm_map_fsm9xxx_io(void);
+void msm_map_fsm9900_io(void);
+void fsm9900_init_gpiomux(void);
 void msm_map_8974_io(void);
 void msm_map_8084_io(void);
 void msm_map_msmkrypton_io(void);
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h
new file mode 100644
index 0000000..02b8917
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-fsm9900.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_FSM9900_H
+#define __ASM_ARCH_MSM_IOMAP_FSM9900_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define FSM9900_SHARED_RAM_PHYS 0x98000000
+
+#define FSM9900_QGIC_DIST_PHYS	0xF9000000
+#define FSM9900_QGIC_DIST_SIZE	SZ_4K
+
+#define FSM9900_TLMM_PHYS	0xFD510000
+#define FSM9900_TLMM_SIZE	SZ_16K
+
+#ifdef CONFIG_DEBUG_FSM9900_UART
+#define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS	0xF9960000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 8f48e94..185958c 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -136,7 +136,7 @@
 #include "msm_iomap-8226.h"
 #include "msm_iomap-8610.h"
 #include "msm_iomap-krypton.h"
-
+#include "msm_iomap-fsm9900.h"
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index d155c6f..2cc7b10 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -19,7 +19,9 @@
 #define __ASM_ARCH_MSM_SMD_H
 
 #include <linux/io.h>
-#include <mach/msm_smsm.h>
+#include <linux/notifier.h>
+
+#include <mach/msm_smem.h>
 
 typedef struct smd_channel smd_channel_t;
 
@@ -40,13 +42,13 @@
  * SMD, the entry will only exist in this enum.
  */
 enum {
-	SMD_APPS = SMSM_APPS,
-	SMD_MODEM = SMSM_MODEM,
-	SMD_Q6 = SMSM_Q6,
-	SMD_WCNSS = SMSM_WCNSS,
-	SMD_DSPS = SMSM_DSPS,
-	SMD_MODEM_Q6_FW,
-	SMD_RPM,
+	SMD_APPS = SMEM_APPS,
+	SMD_MODEM = SMEM_MODEM,
+	SMD_Q6 = SMEM_Q6,
+	SMD_DSPS = SMEM_DSPS,
+	SMD_WCNSS = SMEM_WCNSS,
+	SMD_MODEM_Q6_FW = SMEM_MODEM_Q6_FW,
+	SMD_RPM = SMEM_RPM,
 	NUM_SMD_SUBSYSTEMS,
 };
 
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
new file mode 100644
index 0000000..57f22cc
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -0,0 +1,180 @@
+/* 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 _ARCH_ARM_MACH_MSM_SMEM_H_
+#define _ARCH_ARM_MACH_MSM_SMEM_H_
+
+#include <linux/types.h>
+
+enum {
+	SMEM_APPS,
+	SMEM_MODEM,
+	SMEM_Q6,
+	SMEM_DSPS,
+	SMEM_WCNSS,
+	SMEM_MODEM_Q6_FW,
+	SMEM_RPM,
+	NUM_SMEM_SUBSYSTEMS,
+};
+
+#define SMEM_NUM_SMD_STREAM_CHANNELS        64
+#define SMEM_NUM_SMD_BLOCK_CHANNELS         64
+
+enum {
+	/* fixed items */
+	SMEM_PROC_COMM = 0,
+	SMEM_HEAP_INFO,
+	SMEM_ALLOCATION_TABLE,
+	SMEM_VERSION_INFO,
+	SMEM_HW_RESET_DETECT,
+	SMEM_AARM_WARM_BOOT,
+	SMEM_DIAG_ERR_MESSAGE,
+	SMEM_SPINLOCK_ARRAY,
+	SMEM_MEMORY_BARRIER_LOCATION,
+	SMEM_FIXED_ITEM_LAST = SMEM_MEMORY_BARRIER_LOCATION,
+
+	/* dynamic items */
+	SMEM_AARM_PARTITION_TABLE,
+	SMEM_AARM_BAD_BLOCK_TABLE,
+	SMEM_RESERVE_BAD_BLOCKS,
+	SMEM_WM_UUID,
+	SMEM_CHANNEL_ALLOC_TBL,
+	SMEM_SMD_BASE_ID,
+	SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS,
+	SMEM_SMEM_LOG_EVENTS,
+	SMEM_SMEM_STATIC_LOG_IDX,
+	SMEM_SMEM_STATIC_LOG_EVENTS,
+	SMEM_SMEM_SLOW_CLOCK_SYNC,
+	SMEM_SMEM_SLOW_CLOCK_VALUE,
+	SMEM_BIO_LED_BUF,
+	SMEM_SMSM_SHARED_STATE,
+	SMEM_SMSM_INT_INFO,
+	SMEM_SMSM_SLEEP_DELAY,
+	SMEM_SMSM_LIMIT_SLEEP,
+	SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
+	SMEM_KEYPAD_KEYS_PRESSED,
+	SMEM_KEYPAD_STATE_UPDATED,
+	SMEM_KEYPAD_STATE_IDX,
+	SMEM_GPIO_INT,
+	SMEM_MDDI_LCD_IDX,
+	SMEM_MDDI_HOST_DRIVER_STATE,
+	SMEM_MDDI_LCD_DISP_STATE,
+	SMEM_LCD_CUR_PANEL,
+	SMEM_MARM_BOOT_SEGMENT_INFO,
+	SMEM_AARM_BOOT_SEGMENT_INFO,
+	SMEM_SLEEP_STATIC,
+	SMEM_SCORPION_FREQUENCY,
+	SMEM_SMD_PROFILES,
+	SMEM_TSSC_BUSY,
+	SMEM_HS_SUSPEND_FILTER_INFO,
+	SMEM_BATT_INFO,
+	SMEM_APPS_BOOT_MODE,
+	SMEM_VERSION_FIRST,
+	SMEM_VERSION_SMD = SMEM_VERSION_FIRST,
+	SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
+	SMEM_OSS_RRCASN1_BUF1,
+	SMEM_OSS_RRCASN1_BUF2,
+	SMEM_ID_VENDOR0,
+	SMEM_ID_VENDOR1,
+	SMEM_ID_VENDOR2,
+	SMEM_HW_SW_BUILD_ID,
+	SMEM_SMD_BLOCK_PORT_BASE_ID,
+	SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
+						SMEM_NUM_SMD_BLOCK_CHANNELS,
+	SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
+						SMEM_NUM_SMD_BLOCK_CHANNELS,
+	SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
+						SMEM_NUM_SMD_BLOCK_CHANNELS,
+	SMEM_SCLK_CONVERSION,
+	SMEM_SMD_SMSM_INTR_MUX,
+	SMEM_SMSM_CPU_INTR_MASK,
+	SMEM_APPS_DEM_SLAVE_DATA,
+	SMEM_QDSP6_DEM_SLAVE_DATA,
+	SMEM_CLKREGIM_BSP,
+	SMEM_CLKREGIM_SOURCES,
+	SMEM_SMD_FIFO_BASE_ID,
+	SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID +
+						SMEM_NUM_SMD_STREAM_CHANNELS,
+	SMEM_POWER_ON_STATUS_INFO,
+	SMEM_DAL_AREA,
+	SMEM_SMEM_LOG_POWER_IDX,
+	SMEM_SMEM_LOG_POWER_WRAP,
+	SMEM_SMEM_LOG_POWER_EVENTS,
+	SMEM_ERR_CRASH_LOG,
+	SMEM_ERR_F3_TRACE_LOG,
+	SMEM_SMD_BRIDGE_ALLOC_TABLE,
+	SMEM_SMDLITE_TABLE,
+	SMEM_SD_IMG_UPGRADE_STATUS,
+	SMEM_SEFS_INFO,
+	SMEM_RESET_LOG,
+	SMEM_RESET_LOG_SYMBOLS,
+	SMEM_MODEM_SW_BUILD_ID,
+	SMEM_SMEM_LOG_MPROC_WRAP,
+	SMEM_BOOT_INFO_FOR_APPS,
+	SMEM_SMSM_SIZE_INFO,
+	SMEM_SMD_LOOPBACK_REGISTER,
+	SMEM_SSR_REASON_MSS0,
+	SMEM_SSR_REASON_WCNSS0,
+	SMEM_SSR_REASON_LPASS0,
+	SMEM_SSR_REASON_DSPS0,
+	SMEM_SSR_REASON_VCODEC0,
+	SMEM_SMP2P_APPS_BASE = 427,
+	SMEM_SMP2P_MODEM_BASE = SMEM_SMP2P_APPS_BASE + 8,    /* 435 */
+	SMEM_SMP2P_AUDIO_BASE = SMEM_SMP2P_MODEM_BASE + 8,   /* 443 */
+	SMEM_SMP2P_WIRLESS_BASE = SMEM_SMP2P_AUDIO_BASE + 8, /* 451 */
+	SMEM_SMP2P_POWER_BASE = SMEM_SMP2P_WIRLESS_BASE + 8, /* 459 */
+	SMEM_FLASH_DEVICE_INFO = SMEM_SMP2P_POWER_BASE + 8,  /* 467 */
+	SMEM_BAM_PIPE_MEMORY,     /* 468 */
+	SMEM_IMAGE_VERSION_TABLE, /* 469 */
+	SMEM_LC_DEBUGGER, /* 470 */
+	SMEM_NUM_ITEMS,
+};
+
+#ifdef CONFIG_MSM_SMD
+void *smem_alloc(unsigned id, unsigned size);
+void *smem_alloc2(unsigned id, unsigned size_in);
+void *smem_get_entry(unsigned id, unsigned *size);
+void *smem_find(unsigned id, unsigned size);
+/**
+ * smem_virt_to_phys() - Convert SMEM address to physical address.
+ *
+ * @smem_address: Virtual address returned by smem_alloc()/smem_alloc2()
+ * @returns: Physical address (or NULL if there is a failure)
+ *
+ * This function should only be used if an SMEM item needs to be handed
+ * off to a DMA engine.
+ */
+phys_addr_t smem_virt_to_phys(void *smem_address);
+
+#else
+static inline void *smem_alloc(unsigned id, unsigned size)
+{
+	return NULL;
+}
+static inline void *smem_alloc2(unsigned id, unsigned size_in)
+{
+	return NULL;
+}
+static inline void *smem_get_entry(unsigned id, unsigned *size)
+{
+	return NULL;
+}
+static inline void *smem_find(unsigned id, unsigned size)
+{
+	return NULL;
+}
+static inline phys_addr_t smem_virt_to_phys(void *smem_address)
+{
+	return (phys_addr_t) NULL;
+}
+#endif /* CONFIG_MSM_SMD  */
+#endif /* _ARCH_ARM_MACH_MSM_SMEM_H_ */
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 81a6399..733f5a9 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -14,6 +14,9 @@
 #define _ARCH_ARM_MACH_MSM_SMSM_H_
 
 #include <linux/notifier.h>
+
+#include <mach/msm_smem.h>
+
 #if defined(CONFIG_MSM_N_WAY_SMSM)
 enum {
 	SMSM_APPS_STATE,
@@ -37,11 +40,11 @@
 #endif
 
 enum {
-	SMSM_APPS,
-	SMSM_MODEM,
-	SMSM_Q6,
-	SMSM_WCNSS,
-	SMSM_DSPS,
+	SMSM_APPS = SMEM_APPS,
+	SMSM_MODEM = SMEM_MODEM,
+	SMSM_Q6 = SMEM_Q6,
+	SMSM_DSPS = SMEM_DSPS,
+	SMSM_WCNSS = SMEM_WCNSS,
 };
 extern uint32_t SMSM_NUM_HOSTS;
 
@@ -97,119 +100,6 @@
 #define SMSM_SUBSYS2AP_STATUS         0x00008000
 
 
-#define SMEM_NUM_SMD_STREAM_CHANNELS        64
-#define SMEM_NUM_SMD_BLOCK_CHANNELS         64
-
-enum {
-	/* fixed items */
-	SMEM_PROC_COMM = 0,
-	SMEM_HEAP_INFO,
-	SMEM_ALLOCATION_TABLE,
-	SMEM_VERSION_INFO,
-	SMEM_HW_RESET_DETECT,
-	SMEM_AARM_WARM_BOOT,
-	SMEM_DIAG_ERR_MESSAGE,
-	SMEM_SPINLOCK_ARRAY,
-	SMEM_MEMORY_BARRIER_LOCATION,
-	SMEM_FIXED_ITEM_LAST = SMEM_MEMORY_BARRIER_LOCATION,
-
-	/* dynamic items */
-	SMEM_AARM_PARTITION_TABLE,
-	SMEM_AARM_BAD_BLOCK_TABLE,
-	SMEM_RESERVE_BAD_BLOCKS,
-	SMEM_WM_UUID,
-	SMEM_CHANNEL_ALLOC_TBL,
-	SMEM_SMD_BASE_ID,
-	SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_STREAM_CHANNELS,
-	SMEM_SMEM_LOG_EVENTS,
-	SMEM_SMEM_STATIC_LOG_IDX,
-	SMEM_SMEM_STATIC_LOG_EVENTS,
-	SMEM_SMEM_SLOW_CLOCK_SYNC,
-	SMEM_SMEM_SLOW_CLOCK_VALUE,
-	SMEM_BIO_LED_BUF,
-	SMEM_SMSM_SHARED_STATE,
-	SMEM_SMSM_INT_INFO,
-	SMEM_SMSM_SLEEP_DELAY,
-	SMEM_SMSM_LIMIT_SLEEP,
-	SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
-	SMEM_KEYPAD_KEYS_PRESSED,
-	SMEM_KEYPAD_STATE_UPDATED,
-	SMEM_KEYPAD_STATE_IDX,
-	SMEM_GPIO_INT,
-	SMEM_MDDI_LCD_IDX,
-	SMEM_MDDI_HOST_DRIVER_STATE,
-	SMEM_MDDI_LCD_DISP_STATE,
-	SMEM_LCD_CUR_PANEL,
-	SMEM_MARM_BOOT_SEGMENT_INFO,
-	SMEM_AARM_BOOT_SEGMENT_INFO,
-	SMEM_SLEEP_STATIC,
-	SMEM_SCORPION_FREQUENCY,
-	SMEM_SMD_PROFILES,
-	SMEM_TSSC_BUSY,
-	SMEM_HS_SUSPEND_FILTER_INFO,
-	SMEM_BATT_INFO,
-	SMEM_APPS_BOOT_MODE,
-	SMEM_VERSION_FIRST,
-	SMEM_VERSION_SMD = SMEM_VERSION_FIRST,
-	SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
-	SMEM_OSS_RRCASN1_BUF1,
-	SMEM_OSS_RRCASN1_BUF2,
-	SMEM_ID_VENDOR0,
-	SMEM_ID_VENDOR1,
-	SMEM_ID_VENDOR2,
-	SMEM_HW_SW_BUILD_ID,
-	SMEM_SMD_BLOCK_PORT_BASE_ID,
-	SMEM_SMD_BLOCK_PORT_PROC0_HEAP = SMEM_SMD_BLOCK_PORT_BASE_ID +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
-	SMEM_SMD_BLOCK_PORT_PROC1_HEAP = SMEM_SMD_BLOCK_PORT_PROC0_HEAP +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
-	SMEM_I2C_MUTEX = SMEM_SMD_BLOCK_PORT_PROC1_HEAP +
-						SMEM_NUM_SMD_BLOCK_CHANNELS,
-	SMEM_SCLK_CONVERSION,
-	SMEM_SMD_SMSM_INTR_MUX,
-	SMEM_SMSM_CPU_INTR_MASK,
-	SMEM_APPS_DEM_SLAVE_DATA,
-	SMEM_QDSP6_DEM_SLAVE_DATA,
-	SMEM_CLKREGIM_BSP,
-	SMEM_CLKREGIM_SOURCES,
-	SMEM_SMD_FIFO_BASE_ID,
-	SMEM_USABLE_RAM_PARTITION_TABLE = SMEM_SMD_FIFO_BASE_ID +
-						SMEM_NUM_SMD_STREAM_CHANNELS,
-	SMEM_POWER_ON_STATUS_INFO,
-	SMEM_DAL_AREA,
-	SMEM_SMEM_LOG_POWER_IDX,
-	SMEM_SMEM_LOG_POWER_WRAP,
-	SMEM_SMEM_LOG_POWER_EVENTS,
-	SMEM_ERR_CRASH_LOG,
-	SMEM_ERR_F3_TRACE_LOG,
-	SMEM_SMD_BRIDGE_ALLOC_TABLE,
-	SMEM_SMDLITE_TABLE,
-	SMEM_SD_IMG_UPGRADE_STATUS,
-	SMEM_SEFS_INFO,
-	SMEM_RESET_LOG,
-	SMEM_RESET_LOG_SYMBOLS,
-	SMEM_MODEM_SW_BUILD_ID,
-	SMEM_SMEM_LOG_MPROC_WRAP,
-	SMEM_BOOT_INFO_FOR_APPS,
-	SMEM_SMSM_SIZE_INFO,
-	SMEM_SMD_LOOPBACK_REGISTER,
-	SMEM_SSR_REASON_MSS0,
-	SMEM_SSR_REASON_WCNSS0,
-	SMEM_SSR_REASON_LPASS0,
-	SMEM_SSR_REASON_DSPS0,
-	SMEM_SSR_REASON_VCODEC0,
-	SMEM_SMP2P_APPS_BASE = 427,
-	SMEM_SMP2P_MODEM_BASE = SMEM_SMP2P_APPS_BASE + 8,    /* 435 */
-	SMEM_SMP2P_AUDIO_BASE = SMEM_SMP2P_MODEM_BASE + 8,   /* 443 */
-	SMEM_SMP2P_WIRLESS_BASE = SMEM_SMP2P_AUDIO_BASE + 8, /* 451 */
-	SMEM_SMP2P_POWER_BASE = SMEM_SMP2P_WIRLESS_BASE + 8, /* 459 */
-	SMEM_FLASH_DEVICE_INFO = SMEM_SMP2P_POWER_BASE + 8,  /* 467 */
-	SMEM_BAM_PIPE_MEMORY,     /* 468 */
-	SMEM_IMAGE_VERSION_TABLE, /* 469 */
-	SMEM_LC_DEBUGGER, /* 470 */
-	SMEM_NUM_ITEMS,
-};
-
 enum {
 	SMEM_APPS_Q6_SMSM = 3,
 	SMEM_Q6_APPS_SMSM = 5,
@@ -217,9 +107,6 @@
 };
 
 #ifdef CONFIG_MSM_SMD
-void *smem_alloc(unsigned id, unsigned size);
-void *smem_alloc2(unsigned id, unsigned size_in);
-void *smem_get_entry(unsigned id, unsigned *size);
 int smsm_change_state(uint32_t smsm_entry,
 		      uint32_t clear_mask, uint32_t set_mask);
 
@@ -254,36 +141,8 @@
 
 
 int smsm_check_for_modem_crash(void);
-void *smem_find(unsigned id, unsigned size);
-void *smem_get_entry(unsigned id, unsigned *size);
-
-/**
- * smem_virt_to_phys() - Convert SMEM address to physical address.
- *
- * @smem_address: Virtual address returned by smem_alloc()/smem_alloc2()
- * @returns: Physical address (or NULL if there is a failure)
- *
- * This function should only be used if an SMEM item needs to be handed
- * off to a DMA engine.
- */
-phys_addr_t smem_virt_to_phys(void *smem_address);
 
 #else
-static inline void *smem_alloc(unsigned id, unsigned size)
-{
-	return NULL;
-}
-
-static inline void *smem_alloc2(unsigned id, unsigned size_in)
-{
-	return NULL;
-}
-
-static inline void *smem_get_entry(unsigned id, unsigned *size)
-{
-	return NULL;
-}
-
 static inline int smsm_change_state(uint32_t smsm_entry,
 		      uint32_t clear_mask, uint32_t set_mask)
 {
@@ -347,13 +206,5 @@
 {
 	return -ENODEV;
 }
-static inline void *smem_find(unsigned id, unsigned size)
-{
-	return NULL;
-}
-static inline phys_addr_t smem_virt_to_phys(void *smem_address)
-{
-	return NULL;
-}
 #endif
 #endif
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 64531f0..dc8cbaa 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -53,6 +53,8 @@
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8084")
 #define early_machine_is_msmkrypton()	\
 	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmkrypton")
+#define early_machine_is_fsm9900()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,fsm9900")
 #else
 #define of_board_is_sim()		0
 #define of_board_is_rumi()		0
@@ -70,6 +72,7 @@
 #define early_machine_is_mpq8092()	0
 #define early_machine_is_apq8084()	0
 #define early_machine_is_msmkrypton()	0
+#define early_machine_is_fsm9900()	0
 #endif
 
 #define PLATFORM_SUBTYPE_MDM	1
@@ -110,6 +113,7 @@
 	MSM_CPU_8625Q,
 	MSM_CPU_8084,
 	MSM_CPU_KRYPTON,
+	FSM_CPU_9900,
 };
 
 enum pmic_model {
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index da7c039..5ecc63b 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -101,6 +101,7 @@
 * @desc_mem_buf: descriptor fifo buffer.
 * @event: event for wakeup.
 * @enabled: true if pipe is enabled.
+* @ipa_clnt_hdl : pipe handle to ipa api.
 * @priv: private data to return upon activity_notify
 *	or inactivity_notify callbacks.
 * @activity_notify: callback to invoke on activity on one of the in pipes.
@@ -125,6 +126,7 @@
 	struct sps_mem_buffer desc_mem_buf;
 	struct usb_bam_event_info event;
 	bool enabled;
+	int ipa_clnt_hdl;
 	void *priv;
 	int (*activity_notify)(void *priv);
 	int (*inactivity_notify)(void *priv);
@@ -195,6 +197,14 @@
 		struct usb_bam_connect_ipa_params *ipa_params);
 
 /**
+ * Wait for Consumer granted from Resource Manager.
+ *
+ * @ipa_params - in/out parameters
+ *
+ */
+void usb_bam_wait_for_cons_granted(
+	struct usb_bam_connect_ipa_params *ipa_params);
+/**
  * Register a wakeup callback from peer BAM.
  *
  * @idx - Connection index.
@@ -221,6 +231,39 @@
 int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param);
 
 /**
+ * Register callbacks for start/stop of transfers.
+ *
+ * @start - the callback function that will be called in USB
+ *				driver to start transfers
+ * @stop - the callback function that will be called in USB
+ *				driver to stop transfers
+ *
+ * @param - context that the caller can supply
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int usb_bam_register_start_stop_cbs(
+	void (*start)(void *, enum usb_bam_pipe_dir),
+	void (*stop)(void *, enum usb_bam_pipe_dir),
+	void *param);
+
+/**
+ * Start usb suspend sequence
+ *
+ * @ipa_params -  in/out parameters
+ *
+ */
+void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params);
+
+/**
+ * Start usb resume sequence
+ *
+ * @ipa_params -  in/out parameters
+ *
+ */
+void usb_bam_resume(struct usb_bam_connect_ipa_params *ipa_params);
+/**
  * Disconnect USB-to-Periperal SPS connection.
  *
  * @idx - Connection index.
@@ -315,6 +358,12 @@
 	return -ENODEV;
 }
 
+static inline void usb_bam_wait_for_cons_granted(
+			struct usb_bam_connect_ipa_params *ipa_params)
+{
+	return;
+}
+
 static inline int usb_bam_register_wake_cb(u8 idx,
 	int (*callback)(void *), void* param)
 {
@@ -327,6 +376,20 @@
 	return -ENODEV;
 }
 
+static inline int usb_bam_register_start_stop_cbs(
+	void (*start)(void *, enum usb_bam_pipe_dir),
+	void (*stop)(void *, enum usb_bam_pipe_dir),
+	void *param)
+{
+	return -ENODEV;
+}
+
+static inline void usb_bam_suspend(
+	struct usb_bam_connect_ipa_params *ipa_params){}
+
+static inline void usb_bam_resume(
+	struct usb_bam_connect_ipa_params *ipa_params) {}
+
 static inline int usb_bam_disconnect_pipe(u8 idx)
 {
 	return -ENODEV;
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 1c4a317..099862f 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -406,6 +406,28 @@
 }
 #endif /* CONFIG_ARCH_FSM9XXX */
 
+#ifdef CONFIG_ARCH_FSM9900
+static struct map_desc fsm9900_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(QGIC_DIST, FSM9900),
+	MSM_CHIP_DEVICE(TLMM, FSM9900),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+#ifdef CONFIG_DEBUG_FSM9900_UART
+	MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_fsm9900_io(void)
+{
+	msm_shared_ram_phys = FSM9900_SHARED_RAM_PHYS;
+	msm_map_io(fsm9900_io_desc, ARRAY_SIZE(fsm9900_io_desc));
+	of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
+}
+#endif /* CONFIG_ARCH_FSM9900 */
+
 #ifdef CONFIG_ARCH_MSM9615
 static struct map_desc msm9615_io_desc[] __initdata = {
 	MSM_CHIP_DEVICE(QGIC_DIST, MSM9615),
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index a328b2b..aee691f 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -2253,12 +2253,11 @@
 		return ret;
 	}
 
-	/* Achieve Flow control */
 	rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
 						      dst_port_id);
 	if (!rport_ptr) {
-		pr_err("%s: Could not create remote port\n", __func__);
-		return -ENOMEM;
+		pr_err("%s: Remote port not found\n", __func__);
+		return -ENODEV;
 	}
 
 	if (src->check_send_permissions) {
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index f0e5ebd..624a27c 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -429,7 +429,7 @@
 	trace_lpm_resources(rs->sleep_value, rs->name);
 }
 
-static void msm_lpm_set_l2_mode(int sleep_mode, int notify_rpm)
+static void msm_lpm_set_l2_mode(int sleep_mode)
 {
 	int lpm, rc;
 
@@ -453,7 +453,7 @@
 		break;
 	}
 
-	rc = msm_spm_l2_set_low_power_mode(lpm, notify_rpm);
+	rc = msm_spm_l2_set_low_power_mode(lpm, true);
 
 	if (rc < 0)
 		pr_err("%s: Failed to set L2 low power mode %d",
@@ -474,7 +474,7 @@
 {
 	struct msm_lpm_resource *rs = &msm_lpm_l2;
 
-	msm_lpm_set_l2_mode(rs->sleep_value, notify_rpm);
+	msm_lpm_set_l2_mode(rs->sleep_value);
 }
 
 int msm_lpm_get_l2_cache_value(struct device_node *node,
@@ -786,7 +786,7 @@
 		msm_mpm_exit_sleep(from_idle);
 
 	if (msm_lpm_l2.valid)
-		msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value, false);
+		msm_lpm_set_l2_mode(msm_lpm_l2.rs_data.default_value);
 }
 
 static int msm_lpm_cpu_callback(struct notifier_block *cpu_nb,
diff --git a/arch/arm/mach-msm/memory_topology.c b/arch/arm/mach-msm/memory_topology.c
index 781cd69..97195e3 100644
--- a/arch/arm/mach-msm/memory_topology.c
+++ b/arch/arm/mach-msm/memory_topology.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
 #include <linux/memory.h>
 #include <mach/msm_memtypes.h>
 #include <mach/socinfo.h>
+#include <mach/msm_smem.h>
 #include "smd_private.h"
 
 #if defined(CONFIG_ARCH_MSM8960)
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 2c7ceab..62da5ac 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -364,7 +364,7 @@
 {
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
 	void *sel_cdata;
-	int i;
+	long rounded_rate;
 
 	sel_cdata = fabric->cdata[ctx];
 
@@ -379,8 +379,17 @@
 	}
 
 	/* Enable clocks before accessing QoS registers */
-	for (i = 0; i < NUM_CTX; i++)
-		clk_prepare_enable(fabric->info.nodeclk[i].clk);
+	if (fabric->info.nodeclk[DUAL_CTX].clk)
+		if (fabric->info.nodeclk[DUAL_CTX].rate == 0) {
+			rounded_rate = clk_round_rate(fabric->
+				info.nodeclk[DUAL_CTX].clk, 1);
+		if (clk_set_rate(fabric->info.nodeclk[DUAL_CTX].clk,
+				rounded_rate))
+			MSM_BUS_ERR("Error: clk: en: Node: %d rate: %ld",
+				fabric->fabdev.id, rounded_rate);
+
+		clk_prepare_enable(fabric->info.nodeclk[DUAL_CTX].clk);
+	}
 
 	if (info->iface_clk.clk)
 		clk_prepare_enable(info->iface_clk.clk);
@@ -392,8 +401,9 @@
 		master_tiers, add_bw);
 
 	/* Disable clocks after accessing QoS registers */
-	for (i = 0; i < NUM_CTX; i++)
-		clk_disable_unprepare(fabric->info.nodeclk[i].clk);
+	if (fabric->info.nodeclk[DUAL_CTX].clk &&
+			fabric->info.nodeclk[DUAL_CTX].rate == 0)
+		clk_disable_unprepare(fabric->info.nodeclk[DUAL_CTX].clk);
 
 	if (info->iface_clk.clk) {
 		MSM_BUS_DBG("Commented: Will disable clock for info: %d\n",
diff --git a/arch/arm/mach-msm/msm_smem_iface.h b/arch/arm/mach-msm/msm_smem_iface.h
index bc3e73b..c9c56d9 100644
--- a/arch/arm/mach-msm/msm_smem_iface.h
+++ b/arch/arm/mach-msm/msm_smem_iface.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
 #define __ARCH_ARM_MACH_MSM_SMEM_IFACE_H
 
 #include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
 
 #define MAX_KEY_EVENTS 10
 #define MAX_SEC_KEY_PAYLOAD 32
diff --git a/arch/arm/mach-msm/nand_partitions.c b/arch/arm/mach-msm/nand_partitions.c
index ea5fb9c..ad2a10e 100644
--- a/arch/arm/mach-msm/nand_partitions.c
+++ b/arch/arm/mach-msm/nand_partitions.c
@@ -4,7 +4,7 @@
  * bootloader.
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2009,2011 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2009,2011,2013 The Linux Foundation. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -34,7 +34,7 @@
 
 #include <mach/board.h>
 #ifdef CONFIG_MSM_SMD
-#include "smd_private.h"
+#include <mach/msm_smem.h>
 #endif
 
 /* configuration tags specific to msm */
diff --git a/arch/arm/mach-msm/pil-dsps.c b/arch/arm/mach-msm/pil-dsps.c
index df5ea35..73b58ab 100644
--- a/arch/arm/mach-msm/pil-dsps.c
+++ b/arch/arm/mach-msm/pil-dsps.c
@@ -22,6 +22,7 @@
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
 #include <mach/ramdump.h>
+#include <mach/msm_smem.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 65f86bc..840c90f 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -30,6 +30,7 @@
 #include <mach/msm_bus.h>
 #include <mach/subsystem_restart.h>
 #include <mach/ramdump.h>
+#include <mach/msm_smem.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pil-pronto.c b/arch/arm/mach-msm/pil-pronto.c
index b186a4d..098cbd5 100644
--- a/arch/arm/mach-msm/pil-pronto.c
+++ b/arch/arm/mach-msm/pil-pronto.c
@@ -30,6 +30,7 @@
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
 #include <mach/ramdump.h>
+#include <mach/msm_smem.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -329,12 +330,13 @@
 
 	drv->crash = true;
 
+	disable_irq_nosync(drv->irq);
+
 	if (drv->restart_inprogress) {
 		pr_err("Ignoring wcnss bite irq, restart in progress\n");
 		return IRQ_HANDLED;
 	}
 
-	disable_irq_nosync(drv->irq);
 	drv->restart_inprogress = true;
 	restart_wcnss(drv);
 
diff --git a/arch/arm/mach-msm/pil-q6v4-lpass.c b/arch/arm/mach-msm/pil-q6v4-lpass.c
index f05bcdb..7acb599 100644
--- a/arch/arm/mach-msm/pil-q6v4-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v4-lpass.c
@@ -25,6 +25,7 @@
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 #include <mach/ramdump.h>
+#include <mach/msm_smem.h>
 
 #include "smd_private.h"
 #include "sysmon.h"
diff --git a/arch/arm/mach-msm/pil-q6v4-mss.c b/arch/arm/mach-msm/pil-q6v4-mss.c
index 1821ab1..c4b6038 100644
--- a/arch/arm/mach-msm/pil-q6v4-mss.c
+++ b/arch/arm/mach-msm/pil-q6v4-mss.c
@@ -23,6 +23,7 @@
 #include <mach/subsystem_restart.h>
 #include <mach/msm_smsm.h>
 #include <mach/ramdump.h>
+#include <mach/msm_smem.h>
 
 #include "smd_private.h"
 #include "peripheral-loader.h"
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 6e8e79e..19b5671 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -29,6 +29,7 @@
 #include <mach/subsystem_notif.h>
 #include <mach/scm.h>
 #include <mach/ramdump.h>
+#include <mach/msm_smem.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
@@ -409,12 +410,6 @@
 	drv->err_fatal_irq = ret;
 
 	ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
-					    "qcom,gpio-err-ready", 0));
-	if (ret < 0)
-		return ret;
-	drv->subsys_desc.err_ready_irq = ret;
-
-	ret = gpio_to_irq(of_get_named_gpio(pdev->dev.of_node,
 					    "qcom,gpio-proxy-unvote", 0));
 	if (ret < 0)
 		return ret;
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
index 979458e..5ef6638 100644
--- a/arch/arm/mach-msm/pil-q6v5-mss.c
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -31,6 +31,7 @@
 #include <mach/clk.h>
 #include <mach/msm_smsm.h>
 #include <mach/ramdump.h>
+#include <mach/msm_smem.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index d72b848..5419bf0 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -24,6 +24,7 @@
 
 #include <mach/subsystem_restart.h>
 #include <mach/ramdump.h>
+#include <mach/msm_smem.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 33ad83f..afb2b84 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -671,7 +671,7 @@
 	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_ABS);
+	hrtimer_start(&pm_hrtimer, modified_ktime, HRTIMER_MODE_REL);
 }
 
 /******************************************************************************
@@ -1283,7 +1283,7 @@
 	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_ABS);
+	hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	msm_cpuidle_init();
 
 	if (msm_pm_pc_reset_timer) {
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index a2da8b0..9f97a59 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -3,7 +3,7 @@
  * MSM Power Management Routines
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2013 The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -44,9 +44,10 @@
 #endif
 #include <mach/socinfo.h>
 #include <mach/proc_comm.h>
+#include <mach/msm_smem.h>
+#include <mach/msm_smsm.h>
 #include <asm/smp_scu.h>
 
-#include "smd_private.h"
 #include "smd_rpcrouter.h"
 #include "acpuclock.h"
 #include "clock.h"
diff --git a/arch/arm/mach-msm/remote_spinlock.c b/arch/arm/mach-msm/remote_spinlock.c
index 62e3e05..a9ebd7c 100644
--- a/arch/arm/mach-msm/remote_spinlock.c
+++ b/arch/arm/mach-msm/remote_spinlock.c
@@ -25,6 +25,7 @@
 #include <mach/msm_iomap.h>
 #include <mach/remote_spinlock.h>
 #include <mach/dal.h>
+#include <mach/msm_smem.h>
 #include "smd_private.h"
 
 
diff --git a/arch/arm/mach-msm/rmt_storage_client.c b/arch/arm/mach-msm/rmt_storage_client.c
index a4562e9..550624c 100644
--- a/arch/arm/mach-msm/rmt_storage_client.c
+++ b/arch/arm/mach-msm/rmt_storage_client.c
@@ -35,7 +35,7 @@
 #ifdef CONFIG_MSM_SDIO_SMEM
 #include <mach/sdio_smem.h>
 #endif
-#include "smd_private.h"
+#include <mach/msm_smem.h>
 
 enum {
 	RMT_STORAGE_EVNT_OPEN = 0,
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 3590e6b..a177593 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -47,11 +47,13 @@
 #include <mach/msm_ipc_logging.h>
 #include <mach/ramdump.h>
 #include <mach/board.h>
+#include <mach/msm_smem.h>
 
 #include <asm/cacheflush.h>
 
 #include "smd_private.h"
 #include "modem_notifier.h"
+#include "smem_private.h"
 
 #if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM8X60) \
 	|| defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_FSM9XXX) \
@@ -175,16 +177,6 @@
 	},
 };
 
-struct smem_area {
-	phys_addr_t phys_addr;
-	resource_size_t size;
-	void __iomem *virt_addr;
-};
-static uint32_t num_smem_areas;
-static struct smem_area *smem_areas;
-static struct ramdump_segment *smem_ramdump_segments;
-static void *smem_ramdump_dev;
-static void *smem_phys_to_virt(phys_addr_t base, unsigned offset);
 static void *smd_dev;
 
 struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
@@ -380,9 +372,6 @@
 
 #define SMD_LOOPBACK_CID 100
 
-#define SMEM_SPINLOCK_SMEM_ALLOC       "S:3"
-static remote_spinlock_t remote_spinlock;
-
 static LIST_HEAD(smd_ch_list_loopback);
 static void smd_fake_irq_handler(unsigned long arg);
 static void smsm_cb_snapshot(uint32_t use_wakelock);
@@ -392,7 +381,6 @@
 static DECLARE_WORK(smsm_cb_work, notify_smsm_cb_clients_worker);
 static DEFINE_MUTEX(smsm_lock);
 static struct smsm_state_info *smsm_states;
-static int spinlocks_initialized;
 
 /**
  * Variables to indicate smd module initialization.
@@ -2408,222 +2396,6 @@
 }
 EXPORT_SYMBOL(smd_is_pkt_avail);
 
-
-/* -------------------------------------------------------------------------- */
-
-/**
- * smem_phys_to_virt() - Convert a physical base and offset to virtual address
- *
- * @base: physical base address to check
- * @offset: offset from the base to get the final address
- * @returns: virtual SMEM address; NULL for failure
- *
- * Takes a physical address and an offset and checks if the resulting physical
- * address would fit into one of the smem regions.  If so, returns the
- * corresponding virtual address.  Otherwise returns NULL.
- */
-static void *smem_phys_to_virt(phys_addr_t base, unsigned offset)
-{
-	int i;
-	phys_addr_t phys_addr;
-	resource_size_t size;
-
-	if (OVERFLOW_ADD_UNSIGNED(phys_addr_t, base, offset))
-		return NULL;
-
-	if (!smem_areas) {
-		/*
-		 * Early boot - no area configuration yet, so default
-		 * to using the main memory region.
-		 *
-		 * To remove the MSM_SHARED_RAM_BASE and the static
-		 * mapping of SMEM in the future, add dump_stack()
-		 * to identify the early callers of smem_get_entry()
-		 * (which calls this function) and replace those calls
-		 * with a new function that knows how to lookup the
-		 * SMEM base address before SMEM has been probed.
-		 */
-		phys_addr = msm_shared_ram_phys;
-		size = MSM_SHARED_RAM_SIZE;
-
-		if (base >= phys_addr && base + offset < phys_addr + size) {
-			if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
-				(uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
-				pr_err("%s: overflow %p %x\n", __func__,
-					MSM_SHARED_RAM_BASE, offset);
-				return NULL;
-			}
-
-			return MSM_SHARED_RAM_BASE + offset;
-		} else {
-			return NULL;
-		}
-	}
-	for (i = 0; i < num_smem_areas; ++i) {
-		phys_addr = smem_areas[i].phys_addr;
-		size = smem_areas[i].size;
-
-		if (base < phys_addr || base + offset >= phys_addr + size)
-			continue;
-
-		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
-				(uintptr_t)smem_areas[i].virt_addr, offset)) {
-			pr_err("%s: overflow %p %x\n", __func__,
-				smem_areas[i].virt_addr, offset);
-			return NULL;
-		}
-
-		return smem_areas[i].virt_addr + offset;
-	}
-
-	return NULL;
-}
-
-/**
- * smem_virt_to_phys() - Convert SMEM address to physical address.
- *
- * @smem_address: Address of SMEM item (returned by smem_alloc(), etc)
- * @returns: Physical address (or NULL if there is a failure)
- *
- * This function should only be used if an SMEM item needs to be handed
- * off to a DMA engine.
- */
-phys_addr_t smem_virt_to_phys(void *smem_address)
-{
-	phys_addr_t phys_addr = 0;
-	int i;
-	void *vend;
-
-	if (!smem_areas)
-		return phys_addr;
-
-	for (i = 0; i < num_smem_areas; ++i) {
-		vend = (void *)(smem_areas[i].virt_addr + smem_areas[i].size);
-
-		if (smem_address >= smem_areas[i].virt_addr &&
-				smem_address < vend) {
-			phys_addr = smem_address - smem_areas[i].virt_addr;
-			phys_addr +=  smem_areas[i].phys_addr;
-			break;
-		}
-	}
-
-	return phys_addr;
-}
-EXPORT_SYMBOL(smem_virt_to_phys);
-
-/* smem_alloc returns the pointer to smem item if it is already allocated.
- * Otherwise, it returns NULL.
- */
-void *smem_alloc(unsigned id, unsigned size)
-{
-	return smem_find(id, size);
-}
-EXPORT_SYMBOL(smem_alloc);
-
-/* smem_alloc2 returns the pointer to smem item.  If it is not allocated,
- * it allocates it and then returns the pointer to it.
- */
-void *smem_alloc2(unsigned id, unsigned size_in)
-{
-	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
-	struct smem_heap_entry *toc = shared->heap_toc;
-	unsigned long flags;
-	void *ret = NULL;
-
-	if (!shared->heap_info.initialized) {
-		pr_err("%s: smem heap info not initialized\n", __func__);
-		return NULL;
-	}
-
-	if (id >= SMEM_NUM_ITEMS)
-		return NULL;
-
-	size_in = ALIGN(size_in, 8);
-	remote_spin_lock_irqsave(&remote_spinlock, flags);
-	if (toc[id].allocated) {
-		SMD_DBG("%s: %u already allocated\n", __func__, id);
-		if (size_in != toc[id].size)
-			pr_err("%s: wrong size %u (expected %u)\n",
-			       __func__, toc[id].size, size_in);
-		else
-			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
-	} else if (id > SMEM_FIXED_ITEM_LAST) {
-		SMD_DBG("%s: allocating %u\n", __func__, id);
-		if (shared->heap_info.heap_remaining >= size_in) {
-			toc[id].offset = shared->heap_info.free_offset;
-			toc[id].size = size_in;
-			wmb();
-			toc[id].allocated = 1;
-
-			shared->heap_info.free_offset += size_in;
-			shared->heap_info.heap_remaining -= size_in;
-			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
-		} else
-			pr_err("%s: not enough memory %u (required %u)\n",
-			       __func__, shared->heap_info.heap_remaining,
-			       size_in);
-	}
-	wmb();
-	remote_spin_unlock_irqrestore(&remote_spinlock, flags);
-	return ret;
-}
-EXPORT_SYMBOL(smem_alloc2);
-
-void *smem_get_entry(unsigned id, unsigned *size)
-{
-	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
-	struct smem_heap_entry *toc = shared->heap_toc;
-	int use_spinlocks = spinlocks_initialized;
-	void *ret = 0;
-	unsigned long flags = 0;
-
-	if (id >= SMEM_NUM_ITEMS)
-		return ret;
-
-	if (use_spinlocks)
-		remote_spin_lock_irqsave(&remote_spinlock, flags);
-	/* toc is in device memory and cannot be speculatively accessed */
-	if (toc[id].allocated) {
-		phys_addr_t phys_base;
-
-		*size = toc[id].size;
-		barrier();
-
-		phys_base = toc[id].reserved & BASE_ADDR_MASK;
-		if (!phys_base)
-			phys_base = (phys_addr_t)msm_shared_ram_phys;
-		ret = smem_phys_to_virt(phys_base, toc[id].offset);
-	} else {
-		*size = 0;
-	}
-	if (use_spinlocks)
-		remote_spin_unlock_irqrestore(&remote_spinlock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(smem_get_entry);
-
-void *smem_find(unsigned id, unsigned size_in)
-{
-	unsigned size;
-	void *ptr;
-
-	ptr = smem_get_entry(id, &size);
-	if (!ptr)
-		return 0;
-
-	size_in = ALIGN(size_in, 8);
-	if (size_in != size) {
-		pr_err("smem_find(%d, %d): wrong size %d\n",
-		       id, size_in, size);
-		return 0;
-	}
-
-	return ptr;
-}
-EXPORT_SYMBOL(smem_find);
-
 static int smsm_cb_init(void)
 {
 	struct smsm_state_info *state_info;
@@ -3313,17 +3085,6 @@
 }
 EXPORT_SYMBOL(smsm_state_cb_deregister);
 
-/**
- * smem_get_remote_spinlock - Remote spinlock pointer for unit testing.
- *
- * @returns: pointer to SMEM remote spinlock
- */
-remote_spinlock_t *smem_get_remote_spinlock(void)
-{
-	return &remote_spinlock;
-}
-EXPORT_SYMBOL(smem_get_remote_spinlock);
-
 int smd_module_init_notifier_register(struct notifier_block *nb)
 {
 	int ret;
@@ -4126,23 +3887,6 @@
 		remote_spin_release(&remote_spinlock, notifier->processor);
 		remote_spin_release_all(notifier->processor);
 
-		if (smem_ramdump_dev) {
-			int ret;
-
-			SMD_INFO("%s: saving ramdump\n", __func__);
-			/*
-			 * XPU protection does not currently allow the
-			 * auxiliary memory regions to be dumped.  If this
-			 * changes, then num_smem_areas + 1 should be passed
-			 * into do_elf_ramdump() to dump all regions.
-			 */
-			ret = do_elf_ramdump(smem_ramdump_dev,
-					smem_ramdump_segments, 1);
-			if (ret < 0)
-				pr_err("%s: unable to dump smem %d\n", __func__,
-						ret);
-		}
-
 		smd_channel_reset(notifier->processor);
 	}
 
@@ -4155,13 +3899,6 @@
 	void *handle;
 	struct restart_notifier_block *nb;
 
-	smem_ramdump_dev = create_ramdump_device("smem-smd", smd_dev);
-	if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
-		pr_err("%s: Unable to create smem ramdump device.\n",
-			__func__);
-		smem_ramdump_dev = NULL;
-	}
-
 	for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
 		nb = &restart_notifiers[i];
 		handle = subsys_notif_register_notifier(nb->name, &nb->nb);
@@ -4202,12 +3939,11 @@
 	}
 
 	registered = true;
-	rc = remote_spin_lock_init(&remote_spinlock, SMEM_SPINLOCK_SMEM_ALLOC);
+	rc = init_smem_remote_spinlock();
 	if (rc) {
 		pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
 		return rc;
 	}
-	spinlocks_initialized = 1;
 
 	rc = platform_driver_register(&msm_smd_driver);
 	if (rc) {
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index 4dcf72f..b66e258 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -21,8 +21,10 @@
 #include <linux/jiffies.h>
 
 #include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
 
 #include "smd_private.h"
+#include "smem_private.h"
 
 #if defined(CONFIG_DEBUG_FS)
 
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 4a6a509..4fe9592 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -34,37 +34,6 @@
 #define VERSION_MODEM     9
 #define VERSION_DSPS      10
 
-#define SMD_HEAP_SIZE 512
-
-struct smem_heap_info {
-	unsigned initialized;
-	unsigned free_offset;
-	unsigned heap_remaining;
-	unsigned reserved;
-};
-
-struct smem_heap_entry {
-	unsigned allocated;
-	unsigned offset;
-	unsigned size;
-	unsigned reserved; /* bits 1:0 reserved, bits 31:2 aux smem base addr */
-};
-#define BASE_ADDR_MASK 0xfffffffc
-
-struct smem_proc_comm {
-	unsigned command;
-	unsigned status;
-	unsigned data1;
-	unsigned data2;
-};
-
-struct smem_shared {
-	struct smem_proc_comm proc_comm[4];
-	unsigned version[32];
-	struct smem_heap_info heap_info;
-	struct smem_heap_entry heap_toc[SMD_HEAP_SIZE];
-};
-
 #if defined(CONFIG_MSM_SMD_PKG4)
 struct smsm_interrupt_info {
 	uint32_t aArm_en_mask;
@@ -313,7 +282,4 @@
 	uint32_t smsm_interrupt_id;
 };
 extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
-
-/* used for unit testing spinlocks */
-remote_spinlock_t *smem_get_remote_spinlock(void);
 #endif
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
new file mode 100644
index 0000000..2204609
--- /dev/null
+++ b/arch/arm/mach-msm/smem.c
@@ -0,0 +1,403 @@
+/* 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/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/printk.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_smem.h>
+#include <mach/ramdump.h>
+#include <mach/subsystem_notif.h>
+
+#include "smem_private.h"
+
+/**
+ * OVERFLOW_ADD_UNSIGNED() - check for unsigned overflow
+ *
+ * @type: type to check for overflow
+ * @a: left value to use
+ * @b: right value to use
+ * @returns: true if a + b will result in overflow; false otherwise
+ */
+#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
+	(((type)~0 - (a)) < (b) ? true : false)
+
+enum {
+	MSM_SMEM_DEBUG = 1U << 0,
+	MSM_SMEM_INFO = 1U << 1,
+};
+
+static int msm_smem_debug_mask;
+module_param_named(debug_mask, msm_smem_debug_mask,
+			int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+#define SMEM_DBG(x...) do {                               \
+		if (msm_smem_debug_mask & MSM_SMEM_DEBUG) \
+			pr_debug(x);                      \
+	} while (0)
+
+remote_spinlock_t remote_spinlock;
+int spinlocks_initialized;
+uint32_t num_smem_areas;
+struct smem_area *smem_areas;
+struct ramdump_segment *smem_ramdump_segments;
+
+static void *smem_ramdump_dev;
+static DEFINE_MUTEX(spinlock_init_lock);
+
+struct restart_notifier_block {
+	unsigned processor;
+	char *name;
+	struct notifier_block nb;
+};
+
+static int restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data);
+
+static struct restart_notifier_block restart_notifiers[] = {
+	{SMEM_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
+	{SMEM_Q6, "lpass", .nb.notifier_call = restart_notifier_cb},
+	{SMEM_WCNSS, "wcnss", .nb.notifier_call = restart_notifier_cb},
+	{SMEM_DSPS, "dsps", .nb.notifier_call = restart_notifier_cb},
+	{SMEM_MODEM, "gss", .nb.notifier_call = restart_notifier_cb},
+	{SMEM_Q6, "adsp", .nb.notifier_call = restart_notifier_cb},
+};
+
+/**
+ * smem_phys_to_virt() - Convert a physical base and offset to virtual address
+ *
+ * @base: physical base address to check
+ * @offset: offset from the base to get the final address
+ * @returns: virtual SMEM address; NULL for failure
+ *
+ * Takes a physical address and an offset and checks if the resulting physical
+ * address would fit into one of the smem regions.  If so, returns the
+ * corresponding virtual address.  Otherwise returns NULL.
+ */
+static void *smem_phys_to_virt(phys_addr_t base, unsigned offset)
+{
+	int i;
+	phys_addr_t phys_addr;
+	resource_size_t size;
+
+	if (OVERFLOW_ADD_UNSIGNED(phys_addr_t, base, offset))
+		return NULL;
+
+	if (!smem_areas) {
+		/*
+		 * Early boot - no area configuration yet, so default
+		 * to using the main memory region.
+		 *
+		 * To remove the MSM_SHARED_RAM_BASE and the static
+		 * mapping of SMEM in the future, add dump_stack()
+		 * to identify the early callers of smem_get_entry()
+		 * (which calls this function) and replace those calls
+		 * with a new function that knows how to lookup the
+		 * SMEM base address before SMEM has been probed.
+		 */
+		phys_addr = msm_shared_ram_phys;
+		size = MSM_SHARED_RAM_SIZE;
+
+		if (base >= phys_addr && base + offset < phys_addr + size) {
+			if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+				(uintptr_t)MSM_SHARED_RAM_BASE, offset)) {
+				pr_err("%s: overflow %p %x\n", __func__,
+					MSM_SHARED_RAM_BASE, offset);
+				return NULL;
+			}
+
+			return MSM_SHARED_RAM_BASE + offset;
+		} else {
+			return NULL;
+		}
+	}
+	for (i = 0; i < num_smem_areas; ++i) {
+		phys_addr = smem_areas[i].phys_addr;
+		size = smem_areas[i].size;
+
+		if (base < phys_addr || base + offset >= phys_addr + size)
+			continue;
+
+		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
+				(uintptr_t)smem_areas[i].virt_addr, offset)) {
+			pr_err("%s: overflow %p %x\n", __func__,
+				smem_areas[i].virt_addr, offset);
+			return NULL;
+		}
+
+		return smem_areas[i].virt_addr + offset;
+	}
+
+	return NULL;
+}
+
+/**
+ * smem_virt_to_phys() - Convert SMEM address to physical address.
+ *
+ * @smem_address: Address of SMEM item (returned by smem_alloc(), etc)
+ * @returns: Physical address (or NULL if there is a failure)
+ *
+ * This function should only be used if an SMEM item needs to be handed
+ * off to a DMA engine.
+ */
+phys_addr_t smem_virt_to_phys(void *smem_address)
+{
+	phys_addr_t phys_addr = 0;
+	int i;
+	void *vend;
+
+	if (!smem_areas)
+		return phys_addr;
+
+	for (i = 0; i < num_smem_areas; ++i) {
+		vend = (void *)(smem_areas[i].virt_addr + smem_areas[i].size);
+
+		if (smem_address >= smem_areas[i].virt_addr &&
+				smem_address < vend) {
+			phys_addr = smem_address - smem_areas[i].virt_addr;
+			phys_addr +=  smem_areas[i].phys_addr;
+			break;
+		}
+	}
+
+	return phys_addr;
+}
+EXPORT_SYMBOL(smem_virt_to_phys);
+
+/* smem_alloc returns the pointer to smem item if it is already allocated.
+ * Otherwise, it returns NULL.
+ */
+void *smem_alloc(unsigned id, unsigned size)
+{
+	return smem_find(id, size);
+}
+EXPORT_SYMBOL(smem_alloc);
+
+void *smem_find(unsigned id, unsigned size_in)
+{
+	unsigned size;
+	void *ptr;
+
+	ptr = smem_get_entry(id, &size);
+	if (!ptr)
+		return 0;
+
+	size_in = ALIGN(size_in, 8);
+	if (size_in != size) {
+		pr_err("smem_find(%d, %d): wrong size %d\n",
+			id, size_in, size);
+		return 0;
+	}
+
+	return ptr;
+}
+EXPORT_SYMBOL(smem_find);
+
+/* smem_alloc2 returns the pointer to smem item.  If it is not allocated,
+ * it allocates it and then returns the pointer to it.
+ */
+void *smem_alloc2(unsigned id, unsigned size_in)
+{
+	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+	struct smem_heap_entry *toc = shared->heap_toc;
+	unsigned long flags;
+	void *ret = NULL;
+	int rc;
+
+	if (!shared->heap_info.initialized) {
+		pr_err("%s: smem heap info not initialized\n", __func__);
+		return NULL;
+	}
+
+	if (id >= SMEM_NUM_ITEMS)
+		return NULL;
+
+	if (unlikely(!spinlocks_initialized)) {
+		rc = init_smem_remote_spinlock();
+		if (unlikely(rc)) {
+			pr_err("%s: remote spinlock init failed %d\n",
+								__func__, rc);
+			return NULL;
+		}
+	}
+
+	size_in = ALIGN(size_in, 8);
+	remote_spin_lock_irqsave(&remote_spinlock, flags);
+	if (toc[id].allocated) {
+		SMEM_DBG("%s: %u already allocated\n", __func__, id);
+		if (size_in != toc[id].size)
+			pr_err("%s: wrong size %u (expected %u)\n",
+				__func__, toc[id].size, size_in);
+		else
+			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
+	} else if (id > SMEM_FIXED_ITEM_LAST) {
+		SMEM_DBG("%s: allocating %u\n", __func__, id);
+		if (shared->heap_info.heap_remaining >= size_in) {
+			toc[id].offset = shared->heap_info.free_offset;
+			toc[id].size = size_in;
+			wmb();
+			toc[id].allocated = 1;
+
+			shared->heap_info.free_offset += size_in;
+			shared->heap_info.heap_remaining -= size_in;
+			ret = (void *)(MSM_SHARED_RAM_BASE + toc[id].offset);
+		} else
+			pr_err("%s: not enough memory %u (required %u)\n",
+				__func__, shared->heap_info.heap_remaining,
+				size_in);
+	}
+	wmb();
+	remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(smem_alloc2);
+
+void *smem_get_entry(unsigned id, unsigned *size)
+{
+	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+	struct smem_heap_entry *toc = shared->heap_toc;
+	int use_spinlocks = spinlocks_initialized;
+	void *ret = 0;
+	unsigned long flags = 0;
+
+	if (id >= SMEM_NUM_ITEMS)
+		return ret;
+
+	if (use_spinlocks)
+		remote_spin_lock_irqsave(&remote_spinlock, flags);
+	/* toc is in device memory and cannot be speculatively accessed */
+	if (toc[id].allocated) {
+		phys_addr_t phys_base;
+
+		*size = toc[id].size;
+		barrier();
+
+		phys_base = toc[id].reserved & BASE_ADDR_MASK;
+		if (!phys_base)
+			phys_base = (phys_addr_t)msm_shared_ram_phys;
+		ret = smem_phys_to_virt(phys_base, toc[id].offset);
+	} else {
+		*size = 0;
+	}
+	if (use_spinlocks)
+		remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(smem_get_entry);
+
+
+/**
+ * smem_get_remote_spinlock - Remote spinlock pointer for unit testing.
+ *
+ * @returns: pointer to SMEM remote spinlock
+ */
+remote_spinlock_t *smem_get_remote_spinlock(void)
+{
+	return &remote_spinlock;
+}
+EXPORT_SYMBOL(smem_get_remote_spinlock);
+
+/**
+ * init_smem_remote_spinlock - Reentrant remote spinlock initialization
+ *
+ * @returns: sucess or error code for failure
+ */
+int init_smem_remote_spinlock(void)
+{
+	int rc = 0;
+
+	/*
+	 * Optimistic locking.  Init only needs to be done once by the first
+	 * caller.  After that, serializing inits between different callers
+	 * is unnecessary.  The second check after the lock ensures init
+	 * wasn't previously completed by someone else before the lock could
+	 * be grabbed.
+	 */
+	if (!spinlocks_initialized) {
+		mutex_lock(&spinlock_init_lock);
+		if (!spinlocks_initialized) {
+			rc = remote_spin_lock_init(&remote_spinlock,
+						SMEM_SPINLOCK_SMEM_ALLOC);
+			if (!rc)
+				spinlocks_initialized = 1;
+		}
+		mutex_unlock(&spinlock_init_lock);
+	}
+	return rc;
+}
+
+static int restart_notifier_cb(struct notifier_block *this,
+				unsigned long code,
+				void *data)
+{
+	if (code == SUBSYS_AFTER_SHUTDOWN) {
+		struct restart_notifier_block *notifier;
+
+		notifier = container_of(this,
+					struct restart_notifier_block, nb);
+		SMEM_DBG("%s: ssrestart for processor %d ('%s')\n",
+				__func__, notifier->processor,
+				notifier->name);
+
+		remote_spin_release(&remote_spinlock, notifier->processor);
+		remote_spin_release_all(notifier->processor);
+
+		if (smem_ramdump_dev) {
+			int ret;
+
+			SMEM_DBG("%s: saving ramdump\n", __func__);
+			/*
+			 * XPU protection does not currently allow the
+			 * auxiliary memory regions to be dumped.  If this
+			 * changes, then num_smem_areas + 1 should be passed
+			 * into do_elf_ramdump() to dump all regions.
+			 */
+			ret = do_elf_ramdump(smem_ramdump_dev,
+					smem_ramdump_segments, 1);
+			if (ret < 0)
+				pr_err("%s: unable to dump smem %d\n", __func__,
+						ret);
+		}
+	}
+
+	return NOTIFY_DONE;
+}
+
+static __init int modem_restart_late_init(void)
+{
+	int i;
+	void *handle;
+	struct restart_notifier_block *nb;
+
+	smem_ramdump_dev = create_ramdump_device("smem", NULL);
+	if (IS_ERR_OR_NULL(smem_ramdump_dev)) {
+		pr_err("%s: Unable to create smem ramdump device.\n",
+			__func__);
+		smem_ramdump_dev = NULL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
+		nb = &restart_notifiers[i];
+		handle = subsys_notif_register_notifier(nb->name, &nb->nb);
+		SMEM_DBG("%s: registering notif for '%s', handle=%p\n",
+				__func__, nb->name, handle);
+	}
+
+	return 0;
+}
+late_initcall(modem_restart_late_init);
diff --git a/arch/arm/mach-msm/smem_log.c b/arch/arm/mach-msm/smem_log.c
index 361df33..87f141d2 100644
--- a/arch/arm/mach-msm/smem_log.c
+++ b/arch/arm/mach-msm/smem_log.c
@@ -32,6 +32,7 @@
 
 #include <mach/msm_iomap.h>
 #include <mach/smem_log.h>
+#include <mach/msm_smem.h>
 
 #include <asm/arch_timer.h>
 
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
new file mode 100644
index 0000000..b631e7c
--- /dev/null
+++ b/arch/arm/mach-msm/smem_private.h
@@ -0,0 +1,74 @@
+/* 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 _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_
+#define _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_
+
+#include <linux/remote_spinlock.h>
+
+#include <mach/ramdump.h>
+
+#define SMEM_SPINLOCK_SMEM_ALLOC       "S:3"
+extern remote_spinlock_t remote_spinlock;
+extern int spinlocks_initialized; /* only modify in init_smem_remote_spinlock */
+
+#define SMD_HEAP_SIZE 512
+
+struct smem_heap_info {
+	unsigned initialized;
+	unsigned free_offset;
+	unsigned heap_remaining;
+	unsigned reserved;
+};
+
+struct smem_heap_entry {
+	unsigned allocated;
+	unsigned offset;
+	unsigned size;
+	unsigned reserved; /* bits 1:0 reserved, bits 31:2 aux smem base addr */
+};
+#define BASE_ADDR_MASK 0xfffffffc
+
+struct smem_proc_comm {
+	unsigned command;
+	unsigned status;
+	unsigned data1;
+	unsigned data2;
+};
+
+struct smem_shared {
+	struct smem_proc_comm proc_comm[4];
+	unsigned version[32];
+	struct smem_heap_info heap_info;
+	struct smem_heap_entry heap_toc[SMD_HEAP_SIZE];
+};
+
+struct smem_area {
+	phys_addr_t phys_addr;
+	resource_size_t size;
+	void __iomem *virt_addr;
+};
+
+extern uint32_t num_smem_areas;
+extern struct smem_area *smem_areas;
+
+extern struct ramdump_segment *smem_ramdump_segments;
+
+/* used for unit testing spinlocks */
+remote_spinlock_t *smem_get_remote_spinlock(void);
+
+/*
+ * used to ensure the remote spinlock is only inited once since local
+ * spinlock init code appears non-reentrant
+ */
+int init_smem_remote_spinlock(void);
+#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index 7bdcce9..ee262b0 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -19,7 +19,7 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
 #include <mach/msm_ipc_logging.h>
 #include "smp2p_private_api.h"
 #include "smp2p_private.h"
diff --git a/arch/arm/mach-msm/smp2p_loopback.c b/arch/arm/mach-msm/smp2p_loopback.c
index d95c93f..5df3d70 100644
--- a/arch/arm/mach-msm/smp2p_loopback.c
+++ b/arch/arm/mach-msm/smp2p_loopback.c
@@ -21,7 +21,7 @@
 #include <linux/termios.h>
 #include <linux/module.h>
 #include <linux/remote_spinlock.h>
-#include "smd_private.h"
+#include "smem_private.h"
 #include "smp2p_private.h"
 
 /**
diff --git a/arch/arm/mach-msm/smp2p_spinlock_test.c b/arch/arm/mach-msm/smp2p_spinlock_test.c
index 09d7c0d..c14bac0 100644
--- a/arch/arm/mach-msm/smp2p_spinlock_test.c
+++ b/arch/arm/mach-msm/smp2p_spinlock_test.c
@@ -17,8 +17,8 @@
 #include <linux/delay.h>
 #include <linux/completion.h>
 #include <linux/remote_spinlock.h>
-#include <mach/msm_smsm.h>
-#include "smd_private.h"
+#include <mach/msm_smem.h>
+#include "smem_private.h"
 #include "smp2p_private.h"
 #include "smp2p_test_common.h"
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index d316496..0c02b51 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -27,8 +27,8 @@
 #include <asm/mach-types.h>
 
 #include <mach/socinfo.h>
+#include <mach/msm_smem.h>
 
-#include "smd_private.h"
 #include "boot_stats.h"
 
 #define BUILD_ID_LENGTH 32
@@ -361,6 +361,9 @@
 	/* krypton IDs */
 	[187] = MSM_CPU_KRYPTON,
 
+	/* FSM9900 ID */
+	[188] = FSM_CPU_9900,
+
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
 	   considered as unknown CPU. */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 8e94b3a..fc05fce 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -392,7 +392,7 @@
 	};
 
 	struct mode_of of_l2_modes[] = {
-		{"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 0},
+		{"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
 		{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
 		{"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
 	};
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 26f0210..c971896 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -938,6 +938,10 @@
 	struct subsys_device *subsys_dev = subsys;
 	pr_info("Error ready interrupt occured for %s\n",
 		 subsys_dev->desc->name);
+
+	if (subsys_dev->desc->is_not_loadable)
+		return IRQ_HANDLED;
+
 	complete(&subsys_dev->err_ready);
 	return IRQ_HANDLED;
 }
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 06a4c29..1ea0f2d 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -36,7 +36,8 @@
 #include <mach/socinfo.h>
 
 #if defined(CONFIG_MSM_SMD)
-#include "smd_private.h"
+#include <mach/msm_smem.h>
+#include <mach/msm_smsm.h>
 #endif
 #include "timer.h"
 
diff --git a/drivers/coresight/Makefile b/drivers/coresight/Makefile
index 0e2e2d9..2b14f86 100644
--- a/drivers/coresight/Makefile
+++ b/drivers/coresight/Makefile
@@ -2,7 +2,6 @@
 # Makefile for CoreSight drivers.
 #
 obj-$(CONFIG_CORESIGHT) += coresight.o
-obj-$(CONFIG_OF) += of_coresight.o
 obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
 obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
 obj-$(CONFIG_CORESIGHT_TMC) += coresight-tmc.o
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index 8597e29..53df0f9 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -548,7 +548,6 @@
 
 		prop = of_get_property(node, "qcom,vdd-voltage-level", &len);
 		if (!prop || (len != (2 * sizeof(__be32)))) {
-			of_node_put(reg_node);
 			dev_err(dev, "sdc voltage levels not specified\n");
 		} else {
 			drvdata->reg_low = be32_to_cpup(&prop[0]);
@@ -557,7 +556,6 @@
 
 		prop = of_get_property(node, "qcom,vdd-current-level", &len);
 		if (!prop || (len != (2 * sizeof(__be32)))) {
-			of_node_put(reg_node);
 			dev_err(dev, "sdc current levels not specified\n");
 		} else {
 			drvdata->reg_lpm = be32_to_cpup(&prop[0]);
@@ -633,6 +631,8 @@
 
 		for (i = 0; i < drvdata->seta_gpiocnt; i++)
 			drvdata->seta_cfgs[i].dir = seta_cfgs[i];
+
+		devm_kfree(dev, seta_cfgs);
 	} else {
 		dev_err(dev, "seta gpios not specified\n");
 	}
@@ -699,6 +699,8 @@
 
 		for (i = 0; i < drvdata->setb_gpiocnt; i++)
 			drvdata->setb_cfgs[i].dir = setb_cfgs[i];
+
+		devm_kfree(dev, setb_cfgs);
 	} else {
 		dev_err(dev, "setb gpios not specified\n");
 	}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index bf022ac..a506aa8 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -878,9 +878,10 @@
 				freq_next = dbs_tuners_ins.sync_freq;
 
 			if (max_load_freq >
-				 (dbs_tuners_ins.up_threshold_multi_core -
+				 ((dbs_tuners_ins.up_threshold_multi_core -
 				  dbs_tuners_ins.down_differential_multi_core) *
-				  policy->cur)
+				  policy->cur) &&
+				freq_next < dbs_tuners_ins.optimal_freq)
 				freq_next = dbs_tuners_ins.optimal_freq;
 
 		}
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 58fa5c9..2b70d3f 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -717,6 +717,9 @@
 	bool sha1 = false;
 	uint32_t auth_cfg = 0;
 
+	/* clear status */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
 	writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
 							CRYPTO_CONFIG_REG));
 	/*
@@ -896,6 +899,9 @@
 	uint32_t ivsize = creq->ivsize;
 	int i;
 
+	/* clear status */
+	writel_relaxed(0, pce_dev->iobase + CRYPTO_STATUS_REG);
+
 	writel_relaxed(pce_dev->reg.crypto_cfg_be, (pce_dev->iobase +
 							CRYPTO_CONFIG_REG));
 	/*
@@ -1213,6 +1219,7 @@
 {
 	struct aead_request *areq;
 	unsigned char mac[SHA256_DIGEST_SIZE];
+	uint32_t status;
 
 	areq = (struct aead_request *) pce_dev->areq;
 	if (areq->src != areq->dst) {
@@ -1227,16 +1234,55 @@
 	/* check MAC */
 	memcpy(mac, (char *)(&pce_dev->ce_sps.result->auth_iv[0]),
 						SHA256_DIGEST_SIZE);
+
+	/* read status before unlock */
+	status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
 	if (_qce_unlock_other_pipes(pce_dev))
 		return -EINVAL;
 
 	if (pce_dev->mode == QCE_MODE_CCM) {
-		uint32_t result_status;
+		int32_t result_status;
+
+		/*
+		 * Don't use result dump status. The operation may not
+		 * be complete.
+		 * Instead, use the status we just read of device.
+		 * In case, we need to use result_status from result
+		 * dump the result_status needs to be byte swapped,
+		 * since we set the device to little endian.
+		 */
+
 		result_status = pce_dev->ce_sps.result->status;
-		result_status &= (1 << CRYPTO_MAC_FAILED);
-		result_status |= (pce_dev->ce_sps.consumer_status |
-					pce_dev->ce_sps.producer_status);
+		pce_dev->ce_sps.result->status = 0;
+
+		if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+			| (1 <<  CRYPTO_HSD_ERR))) {
+
+			pr_err("aead operation error. Status %x\n",
+				status);
+			result_status = -ENXIO;
+		} else if (pce_dev->ce_sps.consumer_status |
+				pce_dev->ce_sps.producer_status)  {
+			pr_err("aead sps operation error. sps status %x %x\n",
+				pce_dev->ce_sps.consumer_status,
+				pce_dev->ce_sps.producer_status);
+			result_status = -ENXIO;
+		} else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+			pr_err("aead operation not done? Status %x, sps status %x %x\n",
+				status,
+				pce_dev->ce_sps.consumer_status,
+				pce_dev->ce_sps.producer_status);
+			result_status = -ENXIO;
+
+		} else if (status & (1 << CRYPTO_MAC_FAILED)) {
+			result_status = -EBADMSG;
+		} else {
+			result_status = 0;
+		}
+
 		pce_dev->qce_cb(areq, mac, NULL, result_status);
+
 	} else {
 		uint32_t ivsize = 0;
 		struct crypto_aead *aead;
@@ -1260,6 +1306,8 @@
 	struct ahash_request *areq;
 	unsigned char digest[SHA256_DIGEST_SIZE];
 	uint32_t bytecount32[2];
+	int32_t result_status = pce_dev->ce_sps.result->status;
+	uint32_t status;
 
 	areq = (struct ahash_request *) pce_dev->areq;
 	qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
@@ -1269,10 +1317,39 @@
 	_byte_stream_to_net_words(bytecount32,
 		(unsigned char *)pce_dev->ce_sps.result->auth_byte_count,
 					2 * CRYPTO_REG_SIZE);
+
+	/* read status before unlock */
+	status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
 	if (_qce_unlock_other_pipes(pce_dev))
 		return -EINVAL;
+
+	/*
+	 * Don't use result dump status. The operation may not be complete.
+	 * Instead, use the status we just read of device.
+	 * In case, we need to use result_status from result
+	 * dump the result_status needs to be byte swapped,
+	 * since we set the device to little endian.
+	 */
+
+	if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+			| (1 <<  CRYPTO_HSD_ERR))) {
+
+		pr_err("sha operation error. Status %x\n", status);
+		result_status = -ENXIO;
+	} else if (pce_dev->ce_sps.consumer_status) {
+		pr_err("sha sps operation error. sps status %x\n",
+			pce_dev->ce_sps.consumer_status);
+		result_status = -ENXIO;
+	} else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+		pr_err("sha operation not done? Status %x, sps status %x\n",
+			status, pce_dev->ce_sps.consumer_status);
+		result_status = -ENXIO;
+	} else {
+		result_status = 0;
+	}
 	pce_dev->qce_cb(areq, digest, (char *)bytecount32,
-				pce_dev->ce_sps.consumer_status);
+				result_status);
 	return 0;
 };
 
@@ -1280,6 +1357,8 @@
 {
 	struct ablkcipher_request *areq;
 	unsigned char iv[NUM_OF_CRYPTO_CNTR_IV_REG * CRYPTO_REG_SIZE];
+	uint32_t status;
+	int32_t result_status;
 
 	areq = (struct ablkcipher_request *) pce_dev->areq;
 
@@ -1290,13 +1369,46 @@
 	qce_dma_unmap_sg(pce_dev->pdev, areq->src, pce_dev->src_nents,
 		(areq->src == areq->dst) ? DMA_BIDIRECTIONAL :
 						DMA_TO_DEVICE);
+
+	/* read status before unlock */
+	status = readl_relaxed(pce_dev->iobase + CRYPTO_STATUS_REG);
+
 	if (_qce_unlock_other_pipes(pce_dev))
 		return -EINVAL;
 
+	/*
+	 * Don't use result dump status. The operation may not be complete.
+	 * Instead, use the status we just read of device.
+	 * In case, we need to use result_status from result
+	 * dump the result_status needs to be byte swapped,
+	 * since we set the device to little endian.
+	 */
+	if (status & ((1 << CRYPTO_SW_ERR) | (1 << CRYPTO_AXI_ERR)
+			| (1 <<  CRYPTO_HSD_ERR))) {
+		pr_err("ablk_cipher operation error. Status %x\n",
+				status);
+		result_status = -ENXIO;
+	} else if (pce_dev->ce_sps.consumer_status |
+				pce_dev->ce_sps.producer_status)  {
+		pr_err("ablk_cipher sps operation error. sps status %x %x\n",
+				pce_dev->ce_sps.consumer_status,
+				pce_dev->ce_sps.producer_status);
+		result_status = -ENXIO;
+	} else if ((status & (1 << CRYPTO_OPERATION_DONE)) == 0) {
+		pr_err("ablk_cipher operation not done? Status %x, sps status %x %x\n",
+			status,
+			pce_dev->ce_sps.consumer_status,
+			pce_dev->ce_sps.producer_status);
+		result_status = -ENXIO;
+
+	} else {
+		result_status = 0;
+	}
+
 	if (pce_dev->mode == QCE_MODE_ECB) {
 		pce_dev->qce_cb(areq, NULL, NULL,
 					pce_dev->ce_sps.consumer_status |
-					pce_dev->ce_sps.producer_status);
+					result_status);
 	} else {
 		if (pce_dev->ce_sps.minor_version == 0) {
 			if (pce_dev->mode == QCE_MODE_CBC) {
@@ -1342,9 +1454,7 @@
 				(char *)(pce_dev->ce_sps.result->encr_cntr_iv),
 				sizeof(iv));
 		}
-		pce_dev->qce_cb(areq, NULL, iv,
-			pce_dev->ce_sps.consumer_status |
-			pce_dev->ce_sps.producer_status);
+		pce_dev->qce_cb(areq, NULL, iv, result_status);
 	}
 	return 0;
 };
@@ -1993,6 +2103,9 @@
 	break;
 	}
 
+	/* clear status register */
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 
@@ -2037,13 +2150,9 @@
 	if (mode == QCE_MODE_XTS) {
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
 						0, &pcl_info->auth_seg_size);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-						0, &pcl_info->auth_seg_size);
 	} else {
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
 						0, &pcl_info->auth_seg_size);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-						0, &pcl_info->auth_seg_size);
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_START_REG,
 						0, &pcl_info->auth_seg_size);
 	}
@@ -2130,6 +2239,9 @@
 	break;
 	}
 
+	/* clear status register */
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 
@@ -2156,13 +2268,7 @@
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CNTR1_IV1_REG, 0,
 								NULL);
 	}
-	/* Add dummy to  align size to burst-size multiple */
-	if (!mode_cbc) {
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_SIZE_REG,
-						0, &pcl_info->auth_seg_size);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-						0, &pcl_info->auth_seg_size);
-	}
+
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_le, NULL);
 
@@ -2206,10 +2312,13 @@
 
 		auth_cfg = pdev->reg.auth_cfg_sha1;
 		iv_reg = 5;
+
+		/* clear status register */
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+					0, NULL);
+
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-							0, NULL);
 
 	break;
 	case QCE_HASH_SHA256:
@@ -2218,13 +2327,16 @@
 
 		auth_cfg = pdev->reg.auth_cfg_sha256;
 		iv_reg = 8;
+
+		/* clear status register */
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+					0, NULL);
+
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-								0, NULL);
 	break;
 	case QCE_HASH_SHA1_HMAC:
 		cmdlistptr->auth_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2233,10 +2345,13 @@
 		auth_cfg = pdev->reg.auth_cfg_hmac_sha1;
 		key_reg = 16;
 		iv_reg = 5;
+
+		/* clear status register */
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+					0, NULL);
+
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-							0, NULL);
 	break;
 	case QCE_AEAD_SHA1_HMAC:
 		cmdlistptr->aead_sha1_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2245,13 +2360,16 @@
 		auth_cfg = pdev->reg.auth_cfg_aead_sha1_hmac;
 		key_reg = 16;
 		iv_reg = 5;
+
+		/* clear status register */
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG,
+					0, NULL);
+
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-							0, NULL);
 	break;
 	case QCE_HASH_SHA256_HMAC:
 		cmdlistptr->auth_sha256_hmac.cmdlist = (uint32_t)ce_vaddr;
@@ -2261,13 +2379,15 @@
 		key_reg = 16;
 		iv_reg = 8;
 
+		/* clear status register */
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0,
+					NULL);
+
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-								0, NULL);
 	break;
 	case QCE_HASH_AES_CMAC:
 		if (key_128 == true) {
@@ -2285,13 +2405,16 @@
 			auth_cfg = pdev->reg.auth_cfg_cmac_256;
 			key_reg = 8;
 		}
+
+		/* clear status register */
+		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0,
+					NULL);
+
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 		/* 1 dummy write */
 		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG,
 								0, NULL);
-		qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_AUTH_SEG_CFG_REG,
-								0, NULL);
 	break;
 	default:
 		pr_err("Unknown algorithms %d received, exiting now\n", alg);
@@ -2395,10 +2518,13 @@
 
 		key_reg = 8;
 	}
+
+	/* clear status register */
+	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_STATUS_REG, 0, NULL);
+
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_CONFIG_REG,
 			pdev->reg.crypto_cfg_be, &pcl_info->crypto_cfg);
 
-	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_SIZE_REG, 0, NULL);
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_CFG_REG, 0, NULL);
 	qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_ENCR_SEG_START_REG, 0,
 									NULL);
diff --git a/drivers/crypto/msm/qcryptohw_50.h b/drivers/crypto/msm/qcryptohw_50.h
index 1be2702..e93e25c 100644
--- a/drivers/crypto/msm/qcryptohw_50.h
+++ b/drivers/crypto/msm/qcryptohw_50.h
@@ -297,6 +297,7 @@
 #define CRYPTO_DOUT_SIZE_AVAIL_MASK		(0x1F << CRYPTO_DOUT_SIZE_AVAIL)
 #define CRYPTO_DIN_SIZE_AVAIL			21 /* bit 21-25 */
 #define CRYPTO_DIN_SIZE_AVAIL_MASK		(0x1F << CRYPTO_DIN_SIZE_AVAIL)
+#define CRYPTO_HSD_ERR				20
 #define CRYPTO_ACCESS_VIOL			19
 #define CRYPTO_PIPE_ACTIVE_ERR			18
 #define CRYPTO_CFG_CHNG_ERR			17
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
index f28ebb4..058a3f9 100644
--- a/drivers/gpio/gpio-msm-v1.c
+++ b/drivers/gpio/gpio-msm-v1.c
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/gpio.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -24,7 +24,7 @@
 #include <asm/mach/irq.h>
 #include <mach/gpiomux.h>
 #include <mach/msm_iomap.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
 #include <mach/proc_comm.h>
 
 
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index e80721a..3ee9e4e 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -194,6 +194,7 @@
 	int snapshot_maxsize;   /* Max size of the snapshot region */
 	int snapshot_size;      /* Current size of the snapshot region */
 	u32 snapshot_timestamp;	/* Timestamp of the last valid snapshot */
+	u32 snapshot_faultcount;	/* Total number of faults since boot */
 	int snapshot_frozen;	/* 1 if the snapshot output is frozen until
 				   it gets read by the user.  This avoids
 				   losing the output on multiple hangs  */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index e071650..52340cc 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1454,6 +1454,8 @@
 	}
 	if (ret == 0)
 		device->active_cnt++;
+	trace_kgsl_active_count(device,
+		(unsigned long) __builtin_return_address(0));
 	return ret;
 }
 EXPORT_SYMBOL(kgsl_active_count_get);
@@ -1482,6 +1484,8 @@
 	}
 
 	device->active_cnt++;
+	trace_kgsl_active_count(device,
+		(unsigned long) __builtin_return_address(0));
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_active_count_get_light);
@@ -1504,6 +1508,8 @@
 	kgsl_pwrscale_idle(device);
 	if (device->active_cnt > 1) {
 		device->active_cnt--;
+		trace_kgsl_active_count(device,
+			(unsigned long) __builtin_return_address(0));
 		return;
 	}
 
@@ -1520,6 +1526,8 @@
 	}
 	device->active_cnt--;
 
+	trace_kgsl_active_count(device,
+		(unsigned long) __builtin_return_address(0));
 	if (device->active_cnt == 0)
 		complete(&device->suspend_gate);
 }
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index f09c623..6fcd912 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -536,6 +536,10 @@
 	void *snapshot;
 	struct timespec boot;
 
+	/* increment the hang count (on hang) for good book keeping */
+	if (hang)
+		device->snapshot_faultcount++;
+
 	/*
 	 * The first hang is always the one we are interested in. To
 	 * avoid a subsequent hang blowing away the first, the snapshot
@@ -674,6 +678,22 @@
 	return itr.write;
 }
 
+/* Show the total number of hangs since device boot */
+static ssize_t faultcount_show(struct kgsl_device *device, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", device->snapshot_faultcount);
+}
+
+/* Reset the total number of hangs since device boot */
+static ssize_t faultcount_store(struct kgsl_device *device, const char *buf,
+	size_t count)
+{
+	if (device && count > 0)
+		device->snapshot_faultcount = 0;
+
+	return count;
+}
+
 /* Show the timestamp of the last collected snapshot */
 static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
 {
@@ -709,6 +729,7 @@
 
 SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
 SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
+SNAPSHOT_ATTR(faultcount, 0644, faultcount_show, faultcount_store);
 
 static void snapshot_sysfs_release(struct kobject *kobj)
 {
@@ -774,6 +795,7 @@
 
 	device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
 	device->snapshot_timestamp = 0;
+	device->snapshot_faultcount = 0;
 
 	INIT_LIST_HEAD(&device->snapshot_obj_list);
 
@@ -791,6 +813,10 @@
 		goto done;
 
 	ret  = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
+	if (ret)
+		goto done;
+
+	ret  = sysfs_create_file(&device->snapshot_kobj, &attr_faultcount.attr);
 
 done:
 	return ret;
@@ -817,5 +843,6 @@
 	device->snapshot = NULL;
 	device->snapshot_maxsize = 0;
 	device->snapshot_timestamp = 0;
+	device->snapshot_faultcount = 0;
 }
 EXPORT_SYMBOL(kgsl_device_snapshot_close);
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 5f7ee3c..08677ef 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -739,6 +739,30 @@
 			__entry->id, __entry->ts, __entry->age)
 );
 
+TRACE_EVENT(kgsl_active_count,
+
+	TP_PROTO(struct kgsl_device *device, unsigned long ip),
+
+	TP_ARGS(device, ip),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, count)
+		__field(unsigned long, ip)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->count = device->active_cnt;
+		__entry->ip = ip;
+	),
+
+	TP_printk(
+		"d_name=%s active_cnt=%x func=%pf",
+		__get_str(device_name), __entry->count, (void *) __entry->ip
+	)
+);
+
 #endif /* _KGSL_TRACE_H */
 
 /* This part must be outside protection */
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index 09fcd0e..f6ab3c2 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -305,8 +305,9 @@
 static int32_t qpnp_iadc_comp(int64_t *result, struct qpnp_iadc_comp comp,
 							int64_t die_temp)
 {
-	int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0;
+	int64_t temp_var = 0, sign_coeff = 0, sys_gain_coeff = 0, old;
 
+	old = *result;
 	*result = *result * 1000000;
 
 	if (comp.revision == QPNP_IADC_VER_3_1) {
@@ -315,9 +316,12 @@
 			sys_gain_coeff = -QPNP_COEFF_6 * (comp.sys_gain - 128);
 		else
 			sys_gain_coeff = QPNP_COEFF_6 * comp.sys_gain;
+	} else if (comp.revision != QPNP_IADC_VER_3_0) {
+		/* unsupported revision, do not compensate */
+		*result = old;
+		return 0;
 	}
 
-	comp.id = 0;
 	if (!comp.ext_rsense) {
 		/* internal rsense */
 		switch (comp.id) {
@@ -335,8 +339,8 @@
 		if (comp.revision == QPNP_IADC_VER_3_0)
 			temp_var = QPNP_COEFF_1 * (1000000 - temp_var);
 		else if (comp.revision == QPNP_IADC_VER_3_1)
-			temp_var = (1000000 - temp_var);
-		*result = div64_s64(*result, temp_var);
+			temp_var = 1000000 * (1000000 - temp_var);
+		*result = div64_s64(*result * 1000000, temp_var);
 	}
 
 	sign_coeff = *result < 0 ? QPNP_COEFF_7 : QPNP_COEFF_5;
@@ -353,6 +357,7 @@
 		}
 		*result = div64_s64(*result, temp_var);
 	}
+	pr_debug("%lld compensated into %lld\n", old, *result);
 
 	return 0;
 }
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index cc7073e..4306b1d 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -83,6 +83,14 @@
 #define QPNP_VADC_M1_LOW_THR_MSB					0x6a
 #define QPNP_VADC_M1_HIGH_THR_LSB				0x6b
 #define QPNP_VADC_M1_HIGH_THR_MSB				0x6c
+#define QPNP_VADC_ACCESS					0xd0
+#define QPNP_VADC_ACCESS_DATA					0xa5
+#define QPNP_VADC_PERH_RESET_CTL3				0xda
+#define QPNP_FOLLOW_OTST2_RB					BIT(3)
+#define QPNP_FOLLOW_WARM_RB					BIT(2)
+#define QPNP_FOLLOW_SHUTDOWN1_RB				BIT(1)
+#define QPNP_FOLLOW_SHUTDOWN2_RB				BIT(0)
+
 #define QPNP_INT_TEST_VAL					0xE1
 
 #define QPNP_VADC_DATA0						0x60
@@ -150,6 +158,40 @@
 	return 0;
 }
 
+static int32_t qpnp_vadc_warm_rst_configure(void)
+{
+	int rc = 0;
+	u8 data = 0;
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+	if (rc < 0) {
+		pr_err("VADC write access failed\n");
+		return rc;
+	}
+
+	rc = qpnp_vadc_read_reg(QPNP_VADC_PERH_RESET_CTL3, &data);
+	if (rc < 0) {
+		pr_err("VADC perh reset ctl3 read failed\n");
+		return rc;
+	}
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA);
+	if (rc < 0) {
+		pr_err("VADC write access failed\n");
+		return rc;
+	}
+
+	data |= QPNP_FOLLOW_WARM_RB;
+
+	rc = qpnp_vadc_write_reg(QPNP_VADC_PERH_RESET_CTL3, data);
+	if (rc < 0) {
+		pr_err("VADC perh reset ctl3 write failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
 static int32_t qpnp_vadc_enable(bool state)
 {
 	int rc = 0;
@@ -437,6 +479,7 @@
 static int32_t qpnp_vbat_sns_comp(int64_t *result, u8 id, int64_t die_temp)
 {
 	int64_t temp_var = 0;
+	int64_t old = *result;
 
 	if (die_temp < 25000)
 		return 0;
@@ -462,6 +505,7 @@
 	*result = *result * temp_var;
 
 	*result = div64_s64(*result, 1000000);
+	pr_debug("%lld compensated into %lld\n", old, *result);
 
 	return 0;
 }
@@ -1124,6 +1168,12 @@
 	}
 	vadc->id = fab_id;
 
+	rc = qpnp_vadc_warm_rst_configure();
+	if (rc < 0) {
+		pr_err("Setting perp reset on warm reset failed %d\n", rc);
+		return rc;
+	}
+
 	vadc->vadc_initialized = true;
 	vadc->vadc_iadc_sync_lock = false;
 
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index b92ec7f..06f4a0f 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -31,7 +31,7 @@
 #include <mach/iommu_hw-v0.h>
 #include <mach/msm_iommu_priv.h>
 #include <mach/iommu.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
 
 #define MRC(reg, processor, op1, crn, crm, op2)				\
 __asm__ __volatile__ (							\
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index fcade49..2c2b339 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -75,7 +75,8 @@
 	DMX_FIFO_ERROR, /* Receiver FIFO overrun */
 	DMX_MISSED_ERROR, /* Receiver missed packet */
 	DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */
-	DMX_OK_IDX /* Received OK, new index event */
+	DMX_OK_IDX, /* Received OK, new index event */
+	DMX_OK_SCRAMBLING_STATUS, /* Received OK, new scrambling status */
 } ;
 
 
@@ -135,6 +136,7 @@
 		} marker;
 
 		struct dmx_index_event_info idx_event;
+		struct dmx_scrambling_status_event_info scrambling_bits;
 	};
 };
 
@@ -250,6 +252,7 @@
 	int (*ts_insertion_terminate)(struct dmx_ts_feed *feed);
 	int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed,
 			char *data, size_t size);
+	int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value);
 };
 
 /*--------------------------------------------------------------------------*/
@@ -300,6 +303,7 @@
 				struct dmx_secure_mode *sec_mode);
 	int (*oob_command) (struct dmx_section_feed *feed,
 				struct dmx_oob_command *cmd);
+	int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value);
 };
 
 /*--------------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 2a750a6..6734da8 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -1796,6 +1796,35 @@
 	return 0;
 }
 
+static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter,
+	struct dmx_scrambling_bits *scrambling_bits)
+{
+	struct dmxdev_feed *feed;
+
+	if (!scrambling_bits ||
+		(filter->state != DMXDEV_STATE_GO))
+		return -EINVAL;
+
+	if (filter->type == DMXDEV_TYPE_SEC) {
+		if (filter->feed.sec.feed->get_scrambling_bits)
+			return filter->feed.sec.feed->get_scrambling_bits(
+						filter->feed.sec.feed,
+						&scrambling_bits->value);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(feed, &filter->feed.ts, next) {
+		if (feed->pid == scrambling_bits->pid) {
+			if (feed->ts->get_scrambling_bits)
+				return feed->ts->get_scrambling_bits(feed->ts,
+						&scrambling_bits->value);
+			return -EINVAL;
+		}
+	}
+
+	return -EINVAL;
+}
+
 static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker)
 {
 	struct ts_insertion_buffer *ts_buffer =
@@ -2519,6 +2548,13 @@
 			dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
 			spin_unlock(&dmxdevfilter->dev->lock);
 			wake_up_all(&dmxdevfilter->buffer.queue);
+		} else if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+			event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+			event.params.scrambling_status =
+				dmx_data_ready->scrambling_bits;
+			dvb_dmxdev_add_event(&dmxdevfilter->events, &event);
+			spin_unlock(&dmxdevfilter->dev->lock);
+			wake_up_all(&dmxdevfilter->buffer.queue);
 		} else {
 			spin_unlock(&dmxdevfilter->dev->lock);
 		}
@@ -2635,6 +2671,16 @@
 		return 0;
 	}
 
+	if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) {
+		event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE;
+		event.params.scrambling_status =
+			dmx_data_ready->scrambling_bits;
+		dvb_dmxdev_add_event(events, &event);
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up_all(&buffer->queue);
+		return 0;
+	}
+
 	if (dmx_data_ready->status == DMX_OK_DECODER_BUF) {
 		event.type = DMX_EVENT_NEW_ES_DATA;
 		event.params.es_data.buf_handle = dmx_data_ready->buf.handle;
@@ -3938,6 +3984,15 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
+	case DMX_GET_SCRAMBLING_BITS:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_get_scrambling_bits(dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
 	default:
 		ret = -EINVAL;
 		break;
@@ -4193,6 +4248,7 @@
 	struct dmxdev_filter *filter;
 	int active_count = 0;
 	struct dmx_buffer_status buffer_status;
+	struct dmx_scrambling_bits scrambling_bits;
 	const char *pes_feeds[] = {"DEC", "PES", "DVR", "REC"};
 
 	if (!dmxdev)
@@ -4209,23 +4265,32 @@
 				seq_printf(s, "type: SEC, ");
 				seq_printf(s, "PID %04d ",
 						filter->params.sec.pid);
+				scrambling_bits.pid = filter->params.sec.pid;
 			} else {
 				seq_printf(s, "type: %s, ",
 					pes_feeds[filter->params.pes.output]);
 				seq_printf(s, "PID: %04d ",
 						filter->params.pes.pid);
+				scrambling_bits.pid = filter->params.pes.pid;
 			}
 
+			dvb_dmxdev_get_scrambling_bits(filter,
+				&scrambling_bits);
+
 			if (0 == dvb_dmxdev_get_buffer_status(
 						filter, &buffer_status)) {
 				seq_printf(s, "size: %08d, ",
 					buffer_status.size);
 				seq_printf(s, "fullness: %08d, ",
 					buffer_status.fullness);
-				seq_printf(s, "error: %d\n",
+				seq_printf(s, "error: %d, ",
 					buffer_status.error);
+				seq_printf(s, "scramble: %d\n",
+					scrambling_bits.value);
+
 			} else {
-				seq_printf(s, "\n");
+				seq_printf(s, "scramble: %d\n",
+					scrambling_bits.value);
 			}
 		}
 	}
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 9844c64..8caa9dd 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -164,6 +164,11 @@
 	return ((buf[1] & 0x1f) << 8) + buf[2];
 }
 
+static inline u16 ts_scrambling_ctrl(const u8 *buf)
+{
+	return (buf[3] >> 6) & 0x3;
+}
+
 static inline u8 payload(const u8 *tsp)
 {
 	if (!(tsp[3] & 0x10))	// no payload?
@@ -1287,6 +1292,32 @@
 static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
 			const u8 *buf, const u8 timestamp[TIMESTAMP_LEN])
 {
+	u16 pid = ts_pid(buf);
+	u8 scrambling_bits = ts_scrambling_ctrl(buf);
+	struct dmx_data_ready dmx_data_ready;
+
+	/*
+	 * Notify on scrambling status change only when we move
+	 * from clear (0) to non-clear and vise-versa
+	 */
+	if ((scrambling_bits && !feed->scrambling_bits) ||
+		(!scrambling_bits && feed->scrambling_bits)) {
+		dmx_data_ready.status = DMX_OK_SCRAMBLING_STATUS;
+		dmx_data_ready.data_length = 0;
+		dmx_data_ready.scrambling_bits.pid = pid;
+		dmx_data_ready.scrambling_bits.old_value =
+			feed->scrambling_bits;
+		dmx_data_ready.scrambling_bits.new_value = scrambling_bits;
+
+		if (feed->type == DMX_TYPE_SEC)
+			feed->data_ready_cb.sec(&feed->filter->filter,
+					&dmx_data_ready);
+		else
+			feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready);
+	}
+
+	feed->scrambling_bits = scrambling_bits;
+
 	switch (feed->type) {
 	case DMX_TYPE_TS:
 		if (!feed->feed.ts.is_filtering)
@@ -2047,6 +2078,7 @@
 	}
 
 	feed->first_cc = 1;
+	feed->scrambling_bits = 0;
 
 	if ((feed->ts_type & TS_PACKET) &&
 		!(feed->ts_type & TS_PAYLOAD_ONLY)) {
@@ -2302,6 +2334,25 @@
 	return ret;
 }
 
+static int dvbdmx_ts_get_scrambling_bits(struct dmx_ts_feed *ts_feed,
+			u8 *value)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+	struct dvb_demux *demux = feed->demux;
+
+	spin_lock(&demux->lock);
+
+	if (!ts_feed->is_filtering) {
+		spin_unlock(&demux->lock);
+		return -EINVAL;
+	}
+
+	*value = feed->scrambling_bits;
+	spin_unlock(&demux->lock);
+
+	return 0;
+}
+
 static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed,
 			char *data, size_t size)
 {
@@ -2391,6 +2442,7 @@
 	(*ts_feed)->notify_data_read = NULL;
 	(*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode;
 	(*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd;
+	(*ts_feed)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits;
 	(*ts_feed)->ts_insertion_init = NULL;
 	(*ts_feed)->ts_insertion_terminate = NULL;
 	(*ts_feed)->ts_insertion_insert_buffer =
@@ -2557,6 +2609,7 @@
 	dvbdmxfeed->feed.sec.secbufp = 0;
 	dvbdmxfeed->feed.sec.seclen = 0;
 	dvbdmxfeed->first_cc = 1;
+	dvbdmxfeed->scrambling_bits = 0;
 
 	if (!dvbdmx->start_feed) {
 		mutex_unlock(&dvbdmx->mutex);
@@ -2723,6 +2776,25 @@
 	return ret;
 }
 
+static int dvbdmx_section_get_scrambling_bits(
+	struct dmx_section_feed *section_feed, u8 *value)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed;
+	struct dvb_demux *demux = feed->demux;
+
+	spin_lock(&demux->lock);
+
+	if (!section_feed->is_filtering) {
+		spin_unlock(&demux->lock);
+		return -EINVAL;
+	}
+
+	*value = feed->scrambling_bits;
+	spin_unlock(&demux->lock);
+
+	return 0;
+}
+
 static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
 					struct dmx_section_feed **feed,
 					dmx_section_cb callback)
@@ -2763,6 +2835,7 @@
 	(*feed)->notify_data_read = NULL;
 	(*feed)->set_secure_mode = dmx_section_set_secure_mode;
 	(*feed)->oob_command = dvbdmx_section_feed_oob_cmd;
+	(*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits;
 
 	mutex_unlock(&dvbdmx->mutex);
 	return 0;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index 879aad2..9fb1a12 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -187,6 +187,8 @@
 	int first_cc;
 	int pusi_seen;		/* prevents feeding of garbage from previous section */
 
+	u8 scrambling_bits;
+
 	struct dvb_demux_rec_info *rec_info;
 	u64 prev_tsp_num;
 	u64 prev_stc;
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index d9552e2..52864ae 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -153,3 +153,8 @@
 	  This module serves as the common driver
 	  for the JPEG 1.0 encoder and decoder.
 
+config MSM_GEMINI
+	tristate "Qualcomm MSM Gemini JPEG engine support"
+	depends on MSMB_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960)
+	---help---
+	  Enables support for the Gemini JPEG encoder engine for 8x60.
diff --git a/drivers/media/platform/msm/camera_v2/Makefile b/drivers/media/platform/msm/camera_v2/Makefile
index a1c5ea5..02eb3dd 100644
--- a/drivers/media/platform/msm/camera_v2/Makefile
+++ b/drivers/media/platform/msm/camera_v2/Makefile
@@ -16,3 +16,4 @@
 obj-$(CONFIG_MSMB_JPEG) += jpeg_10/
 obj-$(CONFIG_MSMB_CAMERA) += msm_buf_mgr/
 obj-$(CONFIG_MSMB_CAMERA) += pproc/
+obj-$(CONFIG_MSMB_CAMERA) += gemini/
diff --git a/drivers/media/platform/msm/camera_v2/gemini/Makefile b/drivers/media/platform/msm/camera_v2/gemini/Makefile
new file mode 100644
index 0000000..74d7294
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/Makefile
@@ -0,0 +1,5 @@
+GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+ccflags-y += -Idrivers/media/video/msm
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+
+obj-$(CONFIG_MSM_GEMINI) += msm_gemini_dev.o msm_gemini_sync.o msm_gemini_core.o msm_gemini_hw.o msm_gemini_platform.o
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h
new file mode 100644
index 0000000..eefad6d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_common.h
@@ -0,0 +1,39 @@
+/* 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.
+ */
+
+#ifndef MSM_GEMINI_COMMON_H
+#define MSM_GEMINI_COMMON_H
+
+#define MSM_GEMINI_DEBUG
+#ifdef MSM_GEMINI_DEBUG
+#define GMN_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define GMN_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define GMN_PR_ERR   pr_err
+
+enum GEMINI_MODE {
+	GEMINI_MODE_DISABLE,
+	GEMINI_MODE_OFFLINE,
+	GEMINI_MODE_REALTIME,
+	GEMINI_MODE_REALTIME_ROTATION
+};
+
+enum GEMINI_ROTATION {
+	GEMINI_ROTATION_0,
+	GEMINI_ROTATION_90,
+	GEMINI_ROTATION_180,
+	GEMINI_ROTATION_270
+};
+
+#endif /* MSM_GEMINI_COMMON_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c
new file mode 100644
index 0000000..88fa9e7
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.c
@@ -0,0 +1,250 @@
+/* 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/module.h>
+#include <linux/sched.h>
+#include "msm_gemini_hw.h"
+#include "msm_gemini_core.h"
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+
+static struct msm_gemini_hw_pingpong fe_pingpong_buf;
+static struct msm_gemini_hw_pingpong we_pingpong_buf;
+static int we_pingpong_index;
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int msm_gemini_core_reset(uint8_t op_mode, void *base, int size)
+{
+	unsigned long flags;
+	int rc = 0;
+	int tm = 500;
+	memset(&fe_pingpong_buf, 0, sizeof(fe_pingpong_buf));
+	fe_pingpong_buf.is_fe = 1;
+	we_pingpong_index = 0;
+	memset(&we_pingpong_buf, 0, sizeof(we_pingpong_buf));
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 0;
+	msm_gemini_hw_reset(base, size);
+	spin_unlock_irqrestore(&reset_lock, flags);
+	rc = wait_event_interruptible_timeout(
+			reset_wait,
+			reset_done_ack,
+			msecs_to_jiffies(tm));
+
+	if (!reset_done_ack) {
+		GMN_DBG("%s: reset ACK failed %d", __func__, rc);
+		return -EBUSY;
+	}
+
+	GMN_DBG("%s: reset_done_ack rc %d", __func__, rc);
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 0;
+	spin_unlock_irqrestore(&reset_lock, flags);
+
+	if (op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+		/* Nothing needed for fe buffer cfg, config we only */
+		msm_gemini_hw_we_buffer_cfg(1);
+	} else {
+		/* Nothing needed for fe buffer cfg, config we only */
+		msm_gemini_hw_we_buffer_cfg(0);
+	}
+
+	/* @todo wait for reset done irq */
+
+	return 0;
+}
+
+void msm_gemini_core_release(int release_buf)
+{
+	int i = 0;
+	for (i = 0; i < 2; i++) {
+		if (we_pingpong_buf.buf_status[i] && release_buf)
+			msm_gemini_platform_p2v(we_pingpong_buf.buf[i].file,
+					&we_pingpong_buf.buf[i].handle);
+		we_pingpong_buf.buf_status[i] = 0;
+	}
+}
+
+void msm_gemini_core_init(void)
+{
+	init_waitqueue_head(&reset_wait);
+	spin_lock_init(&reset_lock);
+}
+
+int msm_gemini_core_fe_start(void)
+{
+	msm_gemini_hw_fe_start();
+	return 0;
+}
+
+/* fetch engine */
+int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf)
+{
+	GMN_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
+		(int) buf->y_buffer_addr, buf->y_len,
+		(int) buf->cbcr_buffer_addr, buf->cbcr_len);
+	return msm_gemini_hw_pingpong_update(&fe_pingpong_buf, buf);
+}
+
+void *msm_gemini_core_fe_pingpong_irq(int gemini_irq_status, void *context)
+{
+	return msm_gemini_hw_pingpong_irq(&fe_pingpong_buf);
+}
+
+/* write engine */
+int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf)
+{
+	int rc;
+	GMN_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
+		(int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
+		buf->y_len);
+	we_pingpong_buf.buf_status[we_pingpong_index] = 0;
+	we_pingpong_index = (we_pingpong_index + 1)%2;
+	rc = msm_gemini_hw_pingpong_update(&we_pingpong_buf, buf);
+	return 0;
+}
+
+int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf)
+{
+	int i;
+	for (i = 0; i < 2; i++) {
+		if (we_pingpong_buf.buf[i].y_buffer_addr
+					== buf->y_buffer_addr)
+			we_pingpong_buf.buf_status[i] = 0;
+	}
+	return 0;
+}
+
+void *msm_gemini_core_we_pingpong_irq(int gemini_irq_status, void *context)
+{
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+	return msm_gemini_hw_pingpong_irq(&we_pingpong_buf);
+}
+
+void *msm_gemini_core_framedone_irq(int gemini_irq_status, void *context)
+{
+	struct msm_gemini_hw_buf *buf_p;
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+	buf_p = msm_gemini_hw_pingpong_active_buffer(&we_pingpong_buf);
+	if (buf_p) {
+		buf_p->framedone_len = msm_gemini_hw_encode_output_size();
+		GMN_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
+			buf_p->framedone_len);
+	}
+
+	return buf_p;
+}
+
+void *msm_gemini_core_reset_ack_irq(int gemini_irq_status, void *context)
+{
+	/* @todo return the status back to msm_gemini_core_reset */
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+	return NULL;
+}
+
+void *msm_gemini_core_err_irq(int gemini_irq_status, void *context)
+{
+	GMN_PR_ERR("%s:%d]\n", __func__, gemini_irq_status);
+	return NULL;
+}
+
+static int (*msm_gemini_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_gemini_core_irq(int irq_num, void *context)
+{
+	void *data = NULL;
+	unsigned long flags;
+	int gemini_irq_status;
+
+	GMN_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
+
+	spin_lock_irqsave(&reset_lock, flags);
+	reset_done_ack = 1;
+	spin_unlock_irqrestore(&reset_lock, flags);
+	gemini_irq_status = msm_gemini_hw_irq_get_status();
+
+	GMN_DBG("%s:%d] gemini_irq_status = %0x\n", __func__, __LINE__,
+		gemini_irq_status);
+
+	/* For reset and framedone IRQs, clear all bits */
+	if (gemini_irq_status & 0x400) {
+		wake_up(&reset_wait);
+		msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+			JPEG_IRQ_CLEAR_ALL);
+	} else if (gemini_irq_status & 0x1) {
+		msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+			JPEG_IRQ_CLEAR_ALL);
+	} else {
+		msm_gemini_hw_irq_clear(HWIO_JPEG_IRQ_CLEAR_RMSK,
+			gemini_irq_status);
+	}
+
+	if (msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) {
+		data = msm_gemini_core_framedone_irq(gemini_irq_status,
+			context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(
+				MSM_GEMINI_HW_MASK_COMP_FRAMEDONE,
+				context, data);
+	}
+
+	if (msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status)) {
+		data = msm_gemini_core_fe_pingpong_irq(gemini_irq_status,
+			context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_FE,
+				context, data);
+	}
+
+	if (msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) &&
+	    !msm_gemini_hw_irq_is_frame_done(gemini_irq_status)) {
+		data = msm_gemini_core_we_pingpong_irq(gemini_irq_status,
+			context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_WE,
+				context, data);
+	}
+
+	if (msm_gemini_hw_irq_is_reset_ack(gemini_irq_status)) {
+		data = msm_gemini_core_reset_ack_irq(gemini_irq_status,
+			context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(
+				MSM_GEMINI_HW_MASK_COMP_RESET_ACK,
+				context, data);
+	}
+
+	/* Unexpected/unintended HW interrupt */
+	if (msm_gemini_hw_irq_is_err(gemini_irq_status)) {
+		data = msm_gemini_core_err_irq(gemini_irq_status, context);
+		if (msm_gemini_irq_handler)
+			msm_gemini_irq_handler(MSM_GEMINI_HW_MASK_COMP_ERR,
+				context, data);
+	}
+
+	return IRQ_HANDLED;
+}
+
+void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+	msm_gemini_irq_handler = irq_handler;
+}
+
+void msm_gemini_core_irq_remove(void)
+{
+	msm_gemini_irq_handler = NULL;
+}
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h
new file mode 100644
index 0000000..3aac25a
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_core.h
@@ -0,0 +1,35 @@
+/* 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.
+ */
+
+#ifndef MSM_GEMINI_CORE_H
+#define MSM_GEMINI_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_gemini_hw.h"
+
+#define msm_gemini_core_buf msm_gemini_hw_buf
+
+irqreturn_t msm_gemini_core_irq(int irq_num, void *context);
+
+void msm_gemini_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_gemini_core_irq_remove(void);
+
+int msm_gemini_core_fe_buf_update(struct msm_gemini_core_buf *buf);
+int msm_gemini_core_we_buf_update(struct msm_gemini_core_buf *buf);
+int msm_gemini_core_we_buf_reset(struct msm_gemini_hw_buf *buf);
+
+int msm_gemini_core_reset(uint8_t op_mode, void *base, int size);
+int msm_gemini_core_fe_start(void);
+
+void msm_gemini_core_release(int);
+void msm_gemini_core_init(void);
+#endif /* MSM_GEMINI_CORE_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c
new file mode 100644
index 0000000..13c1e11
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_dev.c
@@ -0,0 +1,265 @@
+/* Copyright (c) 2010-2011,2013 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/msm_gemini.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <mach/board.h>
+#include "../msm.h"
+#include "msm_gemini_sync.h"
+#include "msm_gemini_common.h"
+
+#define MSM_GEMINI_NAME "gemini"
+#define MSM_GEMINI_DRV_NAME "msm_gemini"
+
+static int msm_gemini_open(struct inode *inode, struct file *filp)
+{
+	int rc;
+
+	struct msm_gemini_device *pgmn_dev = container_of(inode->i_cdev,
+		struct msm_gemini_device, cdev);
+	filp->private_data = pgmn_dev;
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+	rc = __msm_gemini_open(pgmn_dev);
+
+	GMN_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+
+	return rc;
+}
+
+static int msm_gemini_release(struct inode *inode, struct file *filp)
+{
+	int rc;
+
+	struct msm_gemini_device *pgmn_dev = filp->private_data;
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+
+	rc = __msm_gemini_release(pgmn_dev);
+
+	GMN_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+		filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
+	return rc;
+}
+
+static long msm_gemini_ioctl(struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	int rc;
+	struct msm_gemini_device *pgmn_dev = filp->private_data;
+
+	GMN_DBG("%s:%d] cmd=%d pgmn_dev=0x%x arg=0x%x\n", __func__,
+		__LINE__, _IOC_NR(cmd), (uint32_t)pgmn_dev, (uint32_t)arg);
+
+	rc = __msm_gemini_ioctl(pgmn_dev, cmd, arg);
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+
+static const struct file_operations msm_gemini_fops = {
+	.owner	  = THIS_MODULE,
+	.open	   = msm_gemini_open,
+	.release	= msm_gemini_release,
+	.unlocked_ioctl = msm_gemini_ioctl,
+};
+
+static struct class *msm_gemini_class;
+static dev_t msm_gemini_devno;
+static struct msm_gemini_device *msm_gemini_device_p;
+
+int msm_gemini_subdev_init(struct v4l2_subdev *gemini_sd)
+{
+	int rc;
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *)gemini_sd->host_priv;
+
+	GMN_DBG("%s:%d: gemini_sd=0x%x pgmn_dev=0x%x\n",
+		__func__, __LINE__, (uint32_t)gemini_sd, (uint32_t)pgmn_dev);
+	rc = __msm_gemini_open(pgmn_dev);
+	GMN_DBG("%s:%d: rc=%d\n",
+		__func__, __LINE__, rc);
+	return rc;
+}
+
+static long msm_gemini_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	long rc;
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *)sd->host_priv;
+
+	GMN_DBG("%s: cmd=%d\n", __func__, cmd);
+
+	GMN_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev);
+
+	GMN_DBG("%s: Calling __msm_gemini_ioctl\n", __func__);
+
+	rc = __msm_gemini_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+	GMN_DBG("%s: X\n", __func__);
+	return rc;
+}
+
+void msm_gemini_subdev_release(struct v4l2_subdev *gemini_sd)
+{
+	int rc;
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *)gemini_sd->host_priv;
+	GMN_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev);
+	rc = __msm_gemini_release(pgmn_dev);
+	GMN_DBG("%s:rc=%d", __func__, rc);
+}
+
+static const struct v4l2_subdev_core_ops msm_gemini_subdev_core_ops = {
+	.ioctl = msm_gemini_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_gemini_subdev_ops = {
+	.core = &msm_gemini_subdev_core_ops,
+};
+
+static int msm_gemini_init(struct platform_device *pdev)
+{
+	int rc = -1;
+	struct device *dev;
+
+	GMN_DBG("%s:\n", __func__);
+	msm_gemini_device_p = __msm_gemini_init(pdev);
+	if (msm_gemini_device_p == NULL) {
+		GMN_PR_ERR("%s: initialization failed\n", __func__);
+		goto fail;
+	}
+
+	v4l2_subdev_init(&msm_gemini_device_p->subdev, &msm_gemini_subdev_ops);
+	v4l2_set_subdev_hostdata(&msm_gemini_device_p->subdev,
+		msm_gemini_device_p);
+	GMN_DBG("%s: msm_gemini_device_p 0x%x", __func__,
+			(uint32_t)msm_gemini_device_p);
+	GMN_DBG("%s:gemini: platform_set_drvdata\n", __func__);
+	platform_set_drvdata(pdev, &msm_gemini_device_p->subdev);
+
+	rc = alloc_chrdev_region(&msm_gemini_devno, 0, 1, MSM_GEMINI_NAME);
+	if (rc < 0) {
+		GMN_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+		goto fail_1;
+	}
+
+	if (!msm_gemini_class) {
+		msm_gemini_class = class_create(THIS_MODULE, MSM_GEMINI_NAME);
+		if (IS_ERR(msm_gemini_class)) {
+			rc = PTR_ERR(msm_gemini_class);
+			GMN_PR_ERR("%s: create device class failed\n",
+				__func__);
+			goto fail_2;
+		}
+	}
+
+	dev = device_create(msm_gemini_class, NULL,
+		MKDEV(MAJOR(msm_gemini_devno), MINOR(msm_gemini_devno)), NULL,
+		"%s%d", MSM_GEMINI_NAME, 0);
+
+	if (IS_ERR(dev)) {
+		GMN_PR_ERR("%s: error creating device\n", __func__);
+		rc = -ENODEV;
+		goto fail_3;
+	}
+
+	cdev_init(&msm_gemini_device_p->cdev, &msm_gemini_fops);
+	msm_gemini_device_p->cdev.owner = THIS_MODULE;
+	msm_gemini_device_p->cdev.ops   =
+		(const struct file_operations *) &msm_gemini_fops;
+	rc = cdev_add(&msm_gemini_device_p->cdev, msm_gemini_devno, 1);
+	if (rc < 0) {
+		GMN_PR_ERR("%s: error adding cdev\n", __func__);
+		rc = -ENODEV;
+		goto fail_4;
+	}
+
+	GMN_DBG("%s %s: success\n", __func__, MSM_GEMINI_NAME);
+
+	return rc;
+
+fail_4:
+	device_destroy(msm_gemini_class, msm_gemini_devno);
+
+fail_3:
+	class_destroy(msm_gemini_class);
+
+fail_2:
+	unregister_chrdev_region(msm_gemini_devno, 1);
+
+fail_1:
+	__msm_gemini_exit(msm_gemini_device_p);
+
+fail:
+	return rc;
+}
+
+static void msm_gemini_exit(void)
+{
+	cdev_del(&msm_gemini_device_p->cdev);
+	device_destroy(msm_gemini_class, msm_gemini_devno);
+	class_destroy(msm_gemini_class);
+	unregister_chrdev_region(msm_gemini_devno, 1);
+
+	__msm_gemini_exit(msm_gemini_device_p);
+}
+
+static int __msm_gemini_probe(struct platform_device *pdev)
+{
+	return msm_gemini_init(pdev);
+}
+
+static int __msm_gemini_remove(struct platform_device *pdev)
+{
+	msm_gemini_exit();
+	return 0;
+}
+
+static struct platform_driver msm_gemini_driver = {
+	.probe  = __msm_gemini_probe,
+	.remove = __msm_gemini_remove,
+	.driver = {
+		.name = MSM_GEMINI_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gemini_driver_init(void)
+{
+	int rc;
+	rc = platform_driver_register(&msm_gemini_driver);
+	return rc;
+}
+
+static void __exit msm_gemini_driver_exit(void)
+{
+	platform_driver_unregister(&msm_gemini_driver);
+}
+
+MODULE_DESCRIPTION("MSM Gemini JPEG driver");
+MODULE_VERSION("msm gemini 0.1");
+
+module_init(msm_gemini_driver_init);
+module_exit(msm_gemini_driver_exit);
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
new file mode 100644
index 0000000..96470fd
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.c
@@ -0,0 +1,520 @@
+/* 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/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include "msm_gemini_hw.h"
+#include "msm_gemini_common.h"
+
+
+static void *gemini_region_base;
+static uint32_t gemini_region_size;
+
+int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw,
+	struct msm_gemini_hw_buf *buf)
+{
+	int buf_free_index = -1;
+
+	if (!pingpong_hw->buf_status[0])
+		buf_free_index = 0;
+	else if (!pingpong_hw->buf_status[1])
+		buf_free_index = 1;
+	else {
+		GMN_PR_ERR("%s:%d: pingpong buffer busy\n", __func__, __LINE__);
+		return -EBUSY;
+	}
+
+	pingpong_hw->buf[buf_free_index] = *buf;
+	pingpong_hw->buf_status[buf_free_index] = 1;
+
+	if (pingpong_hw->is_fe)
+		msm_gemini_hw_fe_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index);
+	else
+		msm_gemini_hw_we_buffer_update(
+			&pingpong_hw->buf[buf_free_index], buf_free_index);
+	return 0;
+}
+
+void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw)
+{
+	struct msm_gemini_hw_buf *buf_p = NULL;
+
+	if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
+		buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+		pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
+	}
+
+	pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
+
+	return (void *) buf_p;
+}
+
+void *msm_gemini_hw_pingpong_active_buffer(
+	struct msm_gemini_hw_pingpong *pingpong_hw)
+{
+	struct msm_gemini_hw_buf *buf_p = NULL;
+
+	if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
+		buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
+
+	return (void *) buf_p;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_irq_get_status[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_READ, 1, HWIO_JPEG_IRQ_STATUS_ADDR,
+		HWIO_JPEG_IRQ_STATUS_RMSK, {0} },
+};
+
+int msm_gemini_hw_irq_get_status(void)
+{
+	uint32_t n_irq_status = 0;
+	n_irq_status = msm_gemini_hw_read(&hw_cmd_irq_get_status[0]);
+	return n_irq_status;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_encode_output_size[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_READ, 1,
+	HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR,
+	HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK, {0} },
+};
+
+long msm_gemini_hw_encode_output_size(void)
+{
+	long encode_output_size;
+
+	encode_output_size = msm_gemini_hw_read(&hw_cmd_encode_output_size[0]);
+
+	return encode_output_size;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_irq_clear[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR,
+	HWIO_JPEG_IRQ_CLEAR_RMSK, {JPEG_IRQ_CLEAR_ALL} },
+};
+
+void msm_gemini_hw_irq_clear(uint32_t mask, uint32_t data)
+{
+	GMN_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
+	hw_cmd_irq_clear[0].mask = mask;
+	hw_cmd_irq_clear[0].data = data;
+	msm_gemini_hw_write(&hw_cmd_irq_clear[0]);
+}
+
+struct msm_gemini_hw_cmd hw_cmd_fe_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR,
+		HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PING_ADDR_ADDR,
+		HWIO_JPEG_FE_Y_PING_ADDR_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR,
+		HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+		HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} },
+};
+
+struct msm_gemini_hw_cmd hw_cmd_fe_pong_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_BUFFER_CFG_ADDR,
+		HWIO_JPEG_FE_BUFFER_CFG_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_Y_PONG_ADDR_ADDR,
+		HWIO_JPEG_FE_Y_PONG_ADDR_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR,
+		HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+		HWIO_JPEG_FE_CMD_RMSK, {JPEG_FE_CMD_BUFFERRELOAD} },
+};
+
+void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input,
+	uint8_t pingpong_index)
+{
+	uint32_t n_reg_val = 0;
+
+	struct msm_gemini_hw_cmd *hw_cmd_p;
+
+	if (pingpong_index == 0) {
+		hw_cmd_p = &hw_cmd_fe_ping_update[0];
+		n_reg_val = ((((p_input->num_of_mcu_rows - 1) <<
+			HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) &
+			HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) |
+			(((p_input->num_of_mcu_rows - 1) <<
+			HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) &
+			HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK));
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = ((p_input->y_buffer_addr <<
+			HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT) &
+			HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = ((p_input->cbcr_buffer_addr<<
+		HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT) &
+		HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		msm_gemini_hw_write(hw_cmd_p);
+	} else if (pingpong_index == 1) {
+		hw_cmd_p = &hw_cmd_fe_pong_update[0];
+		n_reg_val = ((((p_input->num_of_mcu_rows - 1) <<
+			HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT) &
+			HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK) |
+			(((p_input->num_of_mcu_rows - 1) <<
+			HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT) &
+			HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK));
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = ((p_input->y_buffer_addr <<
+			HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT) &
+			HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = ((p_input->cbcr_buffer_addr<<
+		HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT) &
+		HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		msm_gemini_hw_write(hw_cmd_p);
+	} else {
+		/* shall not get to here */
+	}
+
+	return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_fe_start[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_FE_CMD_ADDR,
+		HWIO_JPEG_FE_CMD_RMSK, {JPEG_OFFLINE_CMD_START} },
+};
+
+void msm_gemini_hw_fe_start(void)
+{
+	msm_gemini_hw_write(&hw_cmd_fe_start[0]);
+
+	return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_we_buffer_cfg[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_THRESHOLD_ADDR,
+		HWIO_JPEG_WE_Y_THRESHOLD_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_UB_CFG_ADDR,
+		HWIO_JPEG_WE_Y_UB_CFG_RMSK, {JPEG_WE_YUB_ENCODE} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR,
+		HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK, {0} },
+};
+
+/*
+ * first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH
+ * second dimension is for offline and real-time settings
+ */
+static const uint32_t GEMINI_WE_Y_THRESHOLD[2][2] = {
+	{ 0x00000190, 0x000001ff },
+	{ 0x0000016a, 0x000001ff }
+};
+
+/*
+ * first dimension is WE_ASSERT_STALL_TH and WE_DEASSERT_STALL_TH
+ * second dimension is for offline and real-time settings
+ */
+static const uint32_t GEMINI_WE_CBCR_THRESHOLD[2][2] = {
+	{ 0x00000190, 0x000001ff },
+	{ 0x0000016a, 0x000001ff }
+};
+
+void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime)
+{
+	uint32_t n_reg_val = 0;
+
+	struct msm_gemini_hw_cmd *hw_cmd_p = &hw_cmd_we_buffer_cfg[0];
+
+	n_reg_val = (((GEMINI_WE_Y_THRESHOLD[1][is_realtime] <<
+		HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) &
+		HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) |
+		((GEMINI_WE_Y_THRESHOLD[0][is_realtime] <<
+		HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) &
+		HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK));
+	hw_cmd_p->data = n_reg_val;
+	msm_gemini_hw_write(hw_cmd_p++);
+
+	msm_gemini_hw_write(hw_cmd_p++);
+
+	/* @todo maybe not for realtime? */
+	n_reg_val = (((GEMINI_WE_CBCR_THRESHOLD[1][is_realtime] <<
+		HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT) &
+		HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK) |
+		((GEMINI_WE_CBCR_THRESHOLD[0][is_realtime] <<
+		HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT) &
+		HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK));
+	hw_cmd_p->data = n_reg_val;
+	msm_gemini_hw_write(hw_cmd_p);
+
+	return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_we_ping_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR,
+		HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PING_ADDR_ADDR,
+		HWIO_JPEG_WE_Y_PING_ADDR_RMSK, {0} },
+};
+
+struct msm_gemini_hw_cmd hw_cmd_we_pong_update[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR,
+		HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK, {0} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_WE_Y_PONG_ADDR_ADDR,
+		HWIO_JPEG_WE_Y_PONG_ADDR_RMSK, {0} },
+};
+
+void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input,
+	uint8_t pingpong_index)
+{
+	uint32_t n_reg_val = 0;
+
+	struct msm_gemini_hw_cmd *hw_cmd_p;
+
+	GMN_DBG("%s:%d] pingpong index %d", __func__, __LINE__,
+		pingpong_index);
+	if (pingpong_index == 0) {
+		hw_cmd_p = &hw_cmd_we_ping_update[0];
+
+		n_reg_val = ((p_input->y_len <<
+			HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) &
+			HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = p_input->y_buffer_addr;
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+	} else if (pingpong_index == 1) {
+		hw_cmd_p = &hw_cmd_we_pong_update[0];
+
+		n_reg_val = ((p_input->y_len <<
+			HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT) &
+			HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK);
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+
+		n_reg_val = p_input->y_buffer_addr;
+		hw_cmd_p->data = n_reg_val;
+		msm_gemini_hw_write(hw_cmd_p++);
+	} else {
+		/* shall not get to here */
+	}
+
+	return;
+}
+
+struct msm_gemini_hw_cmd hw_cmd_reset[] = {
+	/* type, repeat n times, offset, mask, data or pdata */
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR,
+		HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_DISABLE_ALL} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_CLEAR_ADDR,
+		HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_CLEAR_ALL} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_IRQ_MASK_ADDR,
+		HWIO_JPEG_IRQ_MASK_RMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
+	{MSM_GEMINI_HW_CMD_TYPE_WRITE, 1, HWIO_JPEG_RESET_CMD_ADDR,
+		HWIO_JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
+};
+
+void msm_gemini_hw_init(void *base, int size)
+{
+	gemini_region_base = base;
+	gemini_region_size = size;
+}
+
+void msm_gemini_hw_reset(void *base, int size)
+{
+	struct msm_gemini_hw_cmd *hw_cmd_p;
+
+	hw_cmd_p = &hw_cmd_reset[0];
+
+	msm_gemini_hw_write(hw_cmd_p++);
+	msm_gemini_hw_write(hw_cmd_p++);
+	msm_gemini_hw_write(hw_cmd_p++);
+	msm_gemini_hw_write(hw_cmd_p);
+}
+
+uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p)
+{
+	uint32_t *paddr;
+	uint32_t data;
+
+	paddr = gemini_region_base + hw_cmd_p->offset;
+
+	data = readl_relaxed(paddr);
+	data &= hw_cmd_p->mask;
+
+	GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n",
+		__func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n,
+		hw_cmd_p->offset, hw_cmd_p->mask, data);
+	return data;
+}
+
+void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p)
+{
+	uint32_t *paddr;
+	uint32_t old_data, new_data;
+
+	/* type, repeat n times, offset, mask, data or pdata */
+	GMN_DBG("%s:%d] type-%d n-%d offset-0x%4x mask-0x%8x data-0x%8x\n",
+		__func__, __LINE__, hw_cmd_p->type, hw_cmd_p->n,
+		hw_cmd_p->offset, hw_cmd_p->mask, hw_cmd_p->data);
+
+	paddr = gemini_region_base + hw_cmd_p->offset;
+
+	if (hw_cmd_p->mask == 0xffffffff) {
+		old_data = 0;
+	} else {
+		old_data = readl_relaxed(paddr);
+		old_data &= ~hw_cmd_p->mask;
+	}
+
+	new_data = hw_cmd_p->data & hw_cmd_p->mask;
+	new_data |= old_data;
+	writel_relaxed(new_data, paddr);
+}
+
+int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+	uint32_t data;
+	uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+	data = msm_gemini_hw_read(hw_cmd_p);
+	if (data != wait_data) {
+		while (tm) {
+			udelay(m_us);
+			data = msm_gemini_hw_read(hw_cmd_p);
+			if (data == wait_data)
+				break;
+			tm--;
+		}
+	}
+	hw_cmd_p->data = data;
+	return tm;
+}
+
+void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
+{
+	int tm = hw_cmd_p->n;
+	while (tm) {
+		udelay(m_us);
+		tm--;
+	}
+}
+
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+{
+	int is_copy_to_user = -1;
+	uint32_t data;
+
+	while (m_cmds--) {
+		if (hw_cmd_p->offset > gemini_region_size) {
+			GMN_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
+				__LINE__, hw_cmd_p->offset, gemini_region_size);
+			return -EFAULT;
+		}
+
+		switch (hw_cmd_p->type) {
+		case MSM_GEMINI_HW_CMD_TYPE_READ:
+			hw_cmd_p->data = msm_gemini_hw_read(hw_cmd_p);
+			is_copy_to_user = 1;
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_WRITE:
+			msm_gemini_hw_write(hw_cmd_p);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_WRITE_OR:
+			data = msm_gemini_hw_read(hw_cmd_p);
+			hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+				data;
+			msm_gemini_hw_write(hw_cmd_p);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_UWAIT:
+			msm_gemini_hw_wait(hw_cmd_p, 1);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_MWAIT:
+			msm_gemini_hw_wait(hw_cmd_p, 1000);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_UDELAY:
+			/* Userspace driver provided delay duration */
+			msm_gemini_hw_delay(hw_cmd_p, 1);
+			break;
+
+		case MSM_GEMINI_HW_CMD_TYPE_MDELAY:
+			/* Userspace driver provided delay duration */
+			msm_gemini_hw_delay(hw_cmd_p, 1000);
+			break;
+
+		default:
+			GMN_PR_ERR("wrong hw command type\n");
+			break;
+		}
+
+		hw_cmd_p++;
+	}
+	return is_copy_to_user;
+}
+
+#ifdef MSM_GMN_DBG_DUMP
+void msm_gemini_io_dump(int size)
+{
+	char line_str[128], *p_str;
+	void __iomem *addr = gemini_region_base;
+	int i;
+	u32 *p = (u32 *) addr;
+	u32 data;
+	pr_info("%s: %p %d reg_size %d\n", __func__, addr, size,
+							gemini_region_size);
+	line_str[0] = '\0';
+	p_str = line_str;
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			snprintf(p_str, 12, "%08x: ", (u32) p);
+			p_str += 10;
+		}
+		data = readl_relaxed(p++);
+		snprintf(p_str, 12, "%08x ", data);
+		p_str += 9;
+		if ((i + 1) % 4 == 0) {
+			pr_info("%s\n", line_str);
+			line_str[0] = '\0';
+			p_str = line_str;
+		}
+	}
+	if (line_str[0] != '\0')
+		pr_info("%s\n", line_str);
+}
+#else
+void msm_gemini_io_dump(int size)
+{
+
+}
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
new file mode 100644
index 0000000..84eed72
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw.h
@@ -0,0 +1,104 @@
+/* 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.
+ */
+
+#ifndef MSM_GEMINI_HW_H
+#define MSM_GEMINI_HW_H
+
+#include <linux/msm_ion.h>
+#include <media/msm_gemini.h>
+#include <mach/iommu_domains.h>
+#include "msm_gemini_hw_reg.h"
+
+struct msm_gemini_hw_buf {
+	struct msm_gemini_buf vbuf;
+	struct file  *file;
+	uint32_t framedone_len;
+	uint32_t y_buffer_addr;
+	uint32_t y_len;
+	uint32_t cbcr_buffer_addr;
+	uint32_t cbcr_len;
+	uint32_t num_of_mcu_rows;
+	struct ion_handle *handle;
+};
+
+struct msm_gemini_hw_pingpong {
+	uint8_t is_fe; /* 1: fe; 0: we */
+	struct  msm_gemini_hw_buf buf[2];
+	int     buf_status[2];
+	int     buf_active_index;
+};
+
+int msm_gemini_hw_pingpong_update(struct msm_gemini_hw_pingpong *pingpong_hw,
+	struct msm_gemini_hw_buf *buf);
+void *msm_gemini_hw_pingpong_irq(struct msm_gemini_hw_pingpong *pingpong_hw);
+void *msm_gemini_hw_pingpong_active_buffer(struct msm_gemini_hw_pingpong
+	*pingpong_hw);
+
+void msm_gemini_hw_irq_clear(uint32_t, uint32_t);
+int msm_gemini_hw_irq_get_status(void);
+long msm_gemini_hw_encode_output_size(void);
+#define MSM_GEMINI_HW_MASK_COMP_FRAMEDONE \
+		MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK
+#define MSM_GEMINI_HW_MASK_COMP_FE \
+		MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK
+#define MSM_GEMINI_HW_MASK_COMP_WE \
+		(MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK | \
+		 MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK)
+#define MSM_GEMINI_HW_MASK_COMP_RESET_ACK \
+		MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK
+#define MSM_GEMINI_HW_MASK_COMP_ERR \
+		(MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK | \
+		MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK)
+
+#define msm_gemini_hw_irq_is_frame_done(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FRAMEDONE)
+#define msm_gemini_hw_irq_is_fe_pingpong(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_FE)
+#define msm_gemini_hw_irq_is_we_pingpong(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_WE)
+#define msm_gemini_hw_irq_is_reset_ack(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_RESET_ACK)
+#define msm_gemini_hw_irq_is_err(gemini_irq_status) \
+	(gemini_irq_status & MSM_GEMINI_HW_MASK_COMP_ERR)
+
+void msm_gemini_hw_fe_buffer_update(struct msm_gemini_hw_buf *p_input,
+	uint8_t pingpong_index);
+void msm_gemini_hw_we_buffer_update(struct msm_gemini_hw_buf *p_input,
+	uint8_t pingpong_index);
+
+void msm_gemini_hw_we_buffer_cfg(uint8_t is_realtime);
+
+void msm_gemini_hw_fe_start(void);
+void msm_gemini_hw_clk_cfg(void);
+
+void msm_gemini_hw_reset(void *base, int size);
+void msm_gemini_hw_irq_cfg(void);
+void msm_gemini_hw_init(void *base, int size);
+
+uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p);
+void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
+int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
+void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_gemini_io_dump(int size);
+
+#define MSM_GEMINI_PIPELINE_CLK_128MHZ 128 /* 8MP  128MHz */
+#define MSM_GEMINI_PIPELINE_CLK_140MHZ 140 /* 9MP  140MHz */
+#define MSM_GEMINI_PIPELINE_CLK_200MHZ 153 /* 12MP 153MHz */
+
+#endif /* MSM_GEMINI_HW_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h
new file mode 100644
index 0000000..4f05650
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_hw_reg.h
@@ -0,0 +1,176 @@
+/* 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.
+ */
+
+#ifndef MSM_GEMINI_HW_REG_H
+#define MSM_GEMINI_HW_REG_H
+
+#define GEMINI_REG_BASE 0
+
+#define MSM_GEMINI_HW_IRQ_MASK_ADDR 0x00000014
+#define MSM_GEMINI_HW_IRQ_MASK_RMSK 0xffffffff
+#define MSM_GEMINI_HW_IRQ_MASK_SHFT 0
+#define MSM_GEMINI_HW_IRQ_DISABLE 0
+#define MSM_GEMINI_HW_IRQ_ENABLE 0xffffffff
+
+#define MSM_GEMINI_HW_IRQ_CLEAR_ADDR 0x00000018
+#define MSM_GEMINI_HW_IRQ_CLEAR_RMSK 0xffffffff
+#define MSM_GEMINI_HW_IRQ_CLEAR_SHFT 0
+#define MSM_GEMINI_HW_IRQ_CLEAR  0xffffffff
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001
+#define MSM_GEMINI_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_MASK 0x00000002
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RD_DONE_SHIFT 0x00000001
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_MASK 0x00000004
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_RTOVF_SHIFT 0x00000002
+
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_MASK 0x00000008
+#define MSM_GEMINI_HW_IRQ_STATUS_FE_VFE_OVERFLOW_SHIFT 0x00000003
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_MASK 0x00000010
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_PINGPONG_SHIFT 0x00000004
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_MASK 0x00000020
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_PINGPONG_SHIFT 0x00000005
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_MASK 0x00000040
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_Y_BUFFER_OVERFLOW_SHIFT 0x00000006
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_MASK 0x00000080
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CBCR_BUFFER_OVERFLOW_SHIFT 0x00000007
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_MASK 0x00000100
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH0_DATAFIFO_OVERFLOW_SHIFT 0x00000008
+
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_MASK 0x00000200
+#define MSM_GEMINI_HW_IRQ_STATUS_WE_CH1_DATAFIFO_OVERFLOW_SHIFT 0x00000009
+
+#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_MASK 0x00000400
+#define MSM_GEMINI_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a
+
+#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800
+#define MSM_GEMINI_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b
+
+#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_MASK 0x00001000
+#define MSM_GEMINI_HW_IRQ_STATUS_VIOLATION_SHIFT 0x0000000c
+
+#define JPEG_BUS_CMD_HALT_REQ 0x00000001
+
+#define JPEG_REALTIME_CMD_STOP_FB 0x00000000
+#define JPEG_REALTIME_CMD_STOP_IM 0x00000003
+#define JPEG_REALTIME_CMD_START 0x00000001
+
+#define JPEG_OFFLINE_CMD_START 0x00000003
+
+#define JPEG_DMI_CFG_DISABLE 0x00000000
+#define JPEG_DMI_ADDR_START 0x00000000
+
+#define JPEG_FE_CMD_BUFFERRELOAD 0x00000001
+
+#define JPEG_WE_YUB_ENCODE 0x01ff0000
+
+#define JPEG_RESET_DEFAULT 0x0004ffff /* cfff? */
+
+#define JPEG_IRQ_DISABLE_ALL 0x00000000
+#define JPEG_IRQ_CLEAR_ALL 0xffffffff
+#define JPEG_IRQ_ALLSOURCES_ENABLE 0xffffffff
+
+#define HWIO_JPEG_FE_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x00000080)
+#define HWIO_JPEG_FE_BUFFER_CFG_RMSK 0x1fff1fff
+
+#define HWIO_JPEG_FE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x00000084)
+#define HWIO_JPEG_FE_Y_PING_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000088)
+#define HWIO_JPEG_FE_Y_PONG_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x0000008c)
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x00000090)
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_RMSK 0xffffffff
+
+#define HWIO_JPEG_FE_CMD_ADDR (GEMINI_REG_BASE + 0x00000094)
+#define HWIO_JPEG_FE_CMD_RMSK 0x3
+
+#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_BMSK 0x1fff0000
+#define HWIO_JPEG_FE_BUFFER_CFG_CBCR_MCU_ROWS_SHFT 0x10
+#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_BMSK 0x1fff
+#define HWIO_JPEG_FE_BUFFER_CFG_Y_MCU_ROWS_SHFT 0
+
+#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_Y_PING_ADDR_FE_Y_PING_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_CBCR_PING_ADDR_FE_CBCR_PING_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_Y_PONG_ADDR_FE_Y_PONG_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_BMSK 0xffffffff
+#define HWIO_JPEG_FE_CBCR_PONG_ADDR_FE_CBCR_PONG_START_ADDR_SHFT 0
+
+#define HWIO_JPEG_WE_Y_THRESHOLD_ADDR (GEMINI_REG_BASE + 0x000000c0)
+#define HWIO_JPEG_WE_Y_THRESHOLD_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_ADDR (GEMINI_REG_BASE      + 0x000000c4)
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_Y_UB_CFG_ADDR (GEMINI_REG_BASE + 0x000000e8)
+#define HWIO_JPEG_WE_Y_UB_CFG_RMSK 0x1ff01ff
+
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff
+#define HWIO_JPEG_WE_Y_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0
+
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_BMSK 0x1ff0000
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_DEASSERT_STALL_TH_SHFT 0x10
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_BMSK 0x1ff
+#define HWIO_JPEG_WE_CBCR_THRESHOLD_WE_ASSERT_STALL_TH_SHFT 0
+
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000c8)
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_RMSK 0x7fffff
+
+#define HWIO_JPEG_WE_Y_PING_ADDR_ADDR (GEMINI_REG_BASE + 0x000000d8)
+#define HWIO_JPEG_WE_Y_PING_ADDR_RMSK 0xfffffff8
+
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_ADDR (GEMINI_REG_BASE + 0x000000cc)
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_RMSK 0x7fffff
+
+#define HWIO_JPEG_WE_Y_PONG_ADDR_ADDR (GEMINI_REG_BASE + 0x000000dc)
+#define HWIO_JPEG_WE_Y_PONG_ADDR_RMSK 0xfffffff8
+
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff
+#define HWIO_JPEG_WE_Y_PING_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0
+
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_BMSK 0x7fffff
+#define HWIO_JPEG_WE_Y_PONG_BUFFER_CFG_WE_BUFFER_LENGTH_SHFT 0
+
+#define HWIO_JPEG_IRQ_MASK_ADDR (GEMINI_REG_BASE + 0x00000014)
+#define HWIO_JPEG_IRQ_MASK_RMSK 0xffffffff
+
+#define HWIO_JPEG_IRQ_CLEAR_ADDR (GEMINI_REG_BASE + 0x00000018)
+#define HWIO_JPEG_IRQ_CLEAR_RMSK 0xffffffff
+
+#define HWIO_JPEG_RESET_CMD_ADDR (GEMINI_REG_BASE + 0x00000004)
+#define HWIO_JPEG_RESET_CMD_RMSK 0xe004ffff
+
+#define HWIO_JPEG_IRQ_STATUS_ADDR (GEMINI_REG_BASE + 0x0000001c)
+#define HWIO_JPEG_IRQ_STATUS_RMSK 0xffffffff
+
+#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_ADDR (GEMINI_REG_BASE + 0x00000034)
+#define HWIO_JPEG_STATUS_ENCODE_OUTPUT_SIZE_RMSK 0xffffffff
+
+#endif /* MSM_GEMINI_HW_REG_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c
new file mode 100644
index 0000000..f442068
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.c
@@ -0,0 +1,283 @@
+/* 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/module.h>
+#include <linux/pm_qos.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/clk.h>
+#include <mach/camera2.h>
+#include <mach/iommu_domains.h>
+#include "msm_gemini_platform.h"
+#include "msm_gemini_sync.h"
+#include "msm_gemini_common.h"
+#include "msm_gemini_hw.h"
+#include "msm_camera_io_util.h"
+
+/* AXI rate in KHz */
+#define MSM_SYSTEM_BUS_RATE	160000
+struct ion_client *gemini_client;
+
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+void msm_gemini_platform_p2v(struct file  *file,
+				struct ion_handle **ionhandle)
+{
+	ion_unmap_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL);
+	ion_free(gemini_client, *ionhandle);
+	*ionhandle = NULL;
+}
+#else
+void msm_gemini_platform_p2v(struct file  *file,
+				struct ion_handle **ionhandle)
+{
+
+}
+#endif
+
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
+				struct ion_handle **ionhandle)
+{
+	unsigned long paddr;
+	unsigned long size;
+	int rc;
+
+	*ionhandle = ion_import_dma_buf(gemini_client, fd);
+	if (IS_ERR_OR_NULL(*ionhandle))
+		return 0;
+
+	rc = ion_map_iommu(gemini_client, *ionhandle, CAMERA_DOMAIN, GEN_POOL,
+			SZ_4K, 0, &paddr, (unsigned long *)&size, 0, 0);
+	if (rc < 0) {
+		GMN_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+				rc);
+		goto error1;
+	}
+	/* validate user input */
+	if (len > size) {
+		GMN_PR_ERR("%s: invalid offset + len\n", __func__);
+		goto error1;
+	}
+
+	return paddr;
+error1:
+	ion_free(gemini_client, *ionhandle);
+
+	return 0;
+}
+#else
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file_p,
+				struct ion_handle **ionhandle)
+{
+	return 0;
+}
+#endif
+
+static struct msm_cam_clk_info gemini_8x_clk_info[] = {
+	{"core_clk", 228571000, 0},
+	{"iface_clk", -1, 0},
+};
+
+static struct msm_cam_clk_info gemini_7x_clk_info[] = {
+	{"core_clk", 153600000, 0},
+	{"iface_clk", -1, 0},
+};
+
+static struct msm_cam_clk_info gemini_imem_clk_info[] = {
+	{"mem_clk", -1, 0},
+};
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_client *msm_gemini_ion_client_create(unsigned int heap_mask,
+		  const char *name)
+{
+	return msm_ion_client_create(heap_mask, name);
+}
+#else
+static struct ion_client *msm_gemini_ion_client_create(unsigned int heap_mask,
+		  const char *name)
+{
+	return NULL;
+}
+#endif
+
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+void msm_gemini_ion_client_destroy(struct ion_client *client)
+{
+	ion_client_destroy(client);
+}
+#else
+void msm_gemini_ion_client_destroy(struct ion_client *client)
+{
+
+}
+#endif
+
+int msm_gemini_platform_init(struct platform_device *pdev,
+	struct resource **mem,
+	void **base,
+	int *irq,
+	irqreturn_t (*handler) (int, void *),
+	void *context)
+{
+	int rc = -1;
+	int gemini_irq;
+	struct resource *gemini_mem, *gemini_io, *gemini_irq_res;
+	void *gemini_base;
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *) context;
+
+	gemini_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!gemini_mem) {
+		GMN_PR_ERR("%s: no mem resource!\n", __func__);
+		return -ENODEV;
+	}
+
+	gemini_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!gemini_irq_res) {
+		GMN_PR_ERR("no irq resource!\n");
+		return -ENODEV;
+	}
+	gemini_irq = gemini_irq_res->start;
+
+	gemini_io = request_mem_region(gemini_mem->start,
+		resource_size(gemini_mem), pdev->name);
+	if (!gemini_io) {
+		GMN_PR_ERR("%s: region already claimed\n", __func__);
+		return -EBUSY;
+	}
+
+	gemini_base = ioremap(gemini_mem->start, resource_size(gemini_mem));
+	if (!gemini_base) {
+		rc = -ENOMEM;
+		GMN_PR_ERR("%s: ioremap failed\n", __func__);
+		goto fail1;
+	}
+	pgmn_dev->hw_version = GEMINI_8X60;
+	rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+	 pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 1);
+	if (rc < 0) {
+		pgmn_dev->hw_version = GEMINI_7X;
+		rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+			gemini_7x_clk_info, pgmn_dev->gemini_clk,
+			ARRAY_SIZE(gemini_7x_clk_info), 1);
+		if (rc < 0) {
+			GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+			goto fail2;
+		}
+	} else {
+		rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+				gemini_imem_clk_info, &pgmn_dev->gemini_clk[2],
+				ARRAY_SIZE(gemini_imem_clk_info), 1);
+		if (!rc)
+			pgmn_dev->hw_version = GEMINI_8960;
+	}
+
+	if (pgmn_dev->hw_version != GEMINI_7X) {
+		if (pgmn_dev->gemini_fs == NULL) {
+			pgmn_dev->gemini_fs =
+				regulator_get(&pgmn_dev->pdev->dev, "vdd");
+			if (IS_ERR(pgmn_dev->gemini_fs)) {
+				GMN_PR_ERR("%s: regulator_get failed %ld\n",
+				__func__, PTR_ERR(pgmn_dev->gemini_fs));
+				pgmn_dev->gemini_fs = NULL;
+				goto gemini_fs_failed;
+			} else if (regulator_enable(pgmn_dev->gemini_fs)) {
+				GMN_PR_ERR("%s: regulator_enable failed\n",
+				__func__);
+				regulator_put(pgmn_dev->gemini_fs);
+				pgmn_dev->gemini_fs = NULL;
+				goto gemini_fs_failed;
+			}
+		}
+	}
+
+	msm_gemini_hw_init(gemini_base, resource_size(gemini_mem));
+	rc = request_irq(gemini_irq, handler, IRQF_TRIGGER_RISING, "gemini",
+		context);
+	if (rc) {
+		GMN_PR_ERR("%s: request_irq failed, %d\n", __func__,
+			gemini_irq);
+		goto fail3;
+	}
+
+	*mem  = gemini_mem;
+	*base = gemini_base;
+	*irq  = gemini_irq;
+
+	gemini_client = msm_gemini_ion_client_create(-1, "camera/gemini");
+
+	GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+
+	return rc;
+
+fail3:
+	if (pgmn_dev->hw_version != GEMINI_7X) {
+		regulator_disable(pgmn_dev->gemini_fs);
+		regulator_put(pgmn_dev->gemini_fs);
+		pgmn_dev->gemini_fs = NULL;
+	}
+gemini_fs_failed:
+	if (pgmn_dev->hw_version == GEMINI_8960)
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+		 &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+	if (pgmn_dev->hw_version != GEMINI_7X)
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+		pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+	else
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+		pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
+fail2:
+	iounmap(gemini_base);
+fail1:
+	release_mem_region(gemini_mem->start, resource_size(gemini_mem));
+	GMN_DBG("%s:%d] fail\n", __func__, __LINE__);
+	return rc;
+}
+
+int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
+	void *context)
+{
+	int result = 0;
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *) context;
+
+	free_irq(irq, context);
+
+	if (pgmn_dev->hw_version != GEMINI_7X) {
+		regulator_disable(pgmn_dev->gemini_fs);
+		regulator_put(pgmn_dev->gemini_fs);
+		pgmn_dev->gemini_fs = NULL;
+	}
+
+	if (pgmn_dev->hw_version == GEMINI_8960)
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+		 &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+	if (pgmn_dev->hw_version != GEMINI_7X)
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+		pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+	else
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+		pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
+
+	iounmap(base);
+	release_mem_region(mem->start, resource_size(mem));
+
+	msm_gemini_ion_client_destroy(gemini_client);
+
+	GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+	return result;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h
new file mode 100644
index 0000000..a071df9
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_platform.h
@@ -0,0 +1,37 @@
+/* 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.
+ */
+
+#ifndef MSM_GEMINI_PLATFORM_H
+#define MSM_GEMINI_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+void msm_gemini_platform_p2v(struct file  *file,
+				struct ion_handle **ionhandle);
+uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
+				struct ion_handle **ionhandle);
+
+int msm_gemini_platform_clk_enable(void);
+int msm_gemini_platform_clk_disable(void);
+
+int msm_gemini_platform_init(struct platform_device *pdev,
+	struct resource **mem,
+	void **base,
+	int *irq,
+	irqreturn_t (*handler) (int, void *),
+	void *context);
+int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
+	void *context);
+
+#endif /* MSM_GEMINI_PLATFORM_H */
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
new file mode 100644
index 0000000..8f84a2c
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.c
@@ -0,0 +1,1081 @@
+/* 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/module.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_gemini.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "msm_gemini_sync.h"
+#include "msm_gemini_core.h"
+#include "msm_gemini_platform.h"
+#include "msm_gemini_common.h"
+
+static int release_buf;
+
+/* size is based on 4k page size */
+static const int g_max_out_size = 0x7ff000;
+
+/*************** queue helper ****************/
+static inline void msm_gemini_q_init(char const *name, struct msm_gemini_q *q_p)
+{
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+	q_p->name = name;
+	spin_lock_init(&q_p->lck);
+	INIT_LIST_HEAD(&q_p->q);
+	init_waitqueue_head(&q_p->wait);
+	q_p->unblck = 0;
+}
+
+static inline void *msm_gemini_q_out(struct msm_gemini_q *q_p)
+{
+	unsigned long flags;
+	struct msm_gemini_q_entry *q_entry_p = NULL;
+	void *data = NULL;
+
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	spin_lock_irqsave(&q_p->lck, flags);
+	if (!list_empty(&q_p->q)) {
+		q_entry_p = list_first_entry(&q_p->q, struct msm_gemini_q_entry,
+			list);
+		list_del_init(&q_entry_p->list);
+	}
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	if (q_entry_p) {
+		data = q_entry_p->data;
+		kfree(q_entry_p);
+	} else {
+		GMN_DBG("%s:%d] %s no entry\n", __func__, __LINE__,
+			q_p->name);
+	}
+
+	return data;
+}
+
+static inline int msm_gemini_q_in(struct msm_gemini_q *q_p, void *data)
+{
+	unsigned long flags;
+
+	struct msm_gemini_q_entry *q_entry_p;
+
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+	q_entry_p = kmalloc(sizeof(struct msm_gemini_q_entry), GFP_ATOMIC);
+	if (!q_entry_p) {
+		GMN_PR_ERR("%s: no mem\n", __func__);
+		return -ENOMEM;
+	}
+	q_entry_p->data = data;
+
+	spin_lock_irqsave(&q_p->lck, flags);
+	list_add_tail(&q_entry_p->list, &q_p->q);
+	spin_unlock_irqrestore(&q_p->lck, flags);
+
+	return 0;
+}
+
+static inline int msm_gemini_q_in_buf(struct msm_gemini_q *q_p,
+	struct msm_gemini_core_buf *buf)
+{
+	struct msm_gemini_core_buf *buf_p;
+
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+	buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		GMN_PR_ERR("%s: no mem\n", __func__);
+		return -ENOMEM;
+	}
+
+	memcpy(buf_p, buf, sizeof(struct msm_gemini_core_buf));
+
+	msm_gemini_q_in(q_p, buf_p);
+	return 0;
+}
+
+static inline int msm_gemini_q_wait(struct msm_gemini_q *q_p)
+{
+	int tm = MAX_SCHEDULE_TIMEOUT;
+	int rc;
+
+	GMN_DBG("%s:%d] %s wait\n", __func__, __LINE__, q_p->name);
+	rc = wait_event_interruptible_timeout(q_p->wait,
+		(!list_empty_careful(&q_p->q) || q_p->unblck),
+		msecs_to_jiffies(tm));
+	GMN_DBG("%s:%d] %s wait done\n", __func__, __LINE__, q_p->name);
+	if (list_empty_careful(&q_p->q)) {
+		if (rc == 0) {
+			rc = -ETIMEDOUT;
+			GMN_PR_ERR("%s:%d] %s timeout\n", __func__, __LINE__,
+				q_p->name);
+		} else if (q_p->unblck) {
+			GMN_DBG("%s:%d] %s unblock is true\n", __func__,
+				__LINE__, q_p->name);
+			q_p->unblck = 0;
+			rc = -ECANCELED;
+		} else if (rc < 0) {
+			GMN_PR_ERR("%s:%d] %s rc %d\n", __func__, __LINE__,
+				q_p->name, rc);
+		}
+	}
+	return rc;
+}
+
+static inline int msm_gemini_q_wakeup(struct msm_gemini_q *q_p)
+{
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+static inline int msm_gemini_q_unblock(struct msm_gemini_q *q_p)
+{
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	q_p->unblck = 1;
+	wake_up(&q_p->wait);
+	return 0;
+}
+
+static inline void msm_gemini_outbuf_q_cleanup(struct msm_gemini_q *q_p)
+{
+	struct msm_gemini_core_buf *buf_p;
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		buf_p = msm_gemini_q_out(q_p);
+		if (buf_p) {
+			msm_gemini_platform_p2v(buf_p->file,
+				&buf_p->handle);
+			GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(buf_p);
+		}
+	} while (buf_p);
+	q_p->unblck = 0;
+}
+
+static inline void msm_gemini_q_cleanup(struct msm_gemini_q *q_p)
+{
+	void *data;
+	GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+	do {
+		data = msm_gemini_q_out(q_p);
+		if (data) {
+			GMN_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+			kfree(data);
+		}
+	} while (data);
+	q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+
+int msm_gemini_framedone_irq(struct msm_gemini_device *pgmn_dev,
+	struct msm_gemini_core_buf *buf_in)
+{
+	int rc = 0;
+
+	GMN_DBG("%s:%d] buf_in %p", __func__, __LINE__, buf_in);
+
+	if (buf_in) {
+		buf_in->vbuf.framedone_len = buf_in->framedone_len;
+		buf_in->vbuf.type = MSM_GEMINI_EVT_FRAMEDONE;
+		GMN_DBG("%s:%d] 0x%08x %d framedone_len %d\n",
+			__func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len,
+			buf_in->vbuf.framedone_len);
+		rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, buf_in);
+	} else {
+		GMN_DBG("%s:%d] no output return buffer\n",
+			__func__, __LINE__);
+		rc = -1;
+	}
+
+	if (buf_in)
+		rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q);
+
+	return rc;
+}
+
+int msm_gemini_evt_get(struct msm_gemini_device *pgmn_dev,
+	void __user *to)
+{
+	struct msm_gemini_core_buf *buf_p;
+	struct msm_gemini_ctrl_cmd ctrl_cmd;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_gemini_q_wait(&pgmn_dev->evt_q);
+	buf_p = msm_gemini_q_out(&pgmn_dev->evt_q);
+
+	if (!buf_p) {
+		GMN_DBG("%s:%d] no buffer\n", __func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	memset(&ctrl_cmd, 0, sizeof(struct msm_gemini_ctrl_cmd));
+	ctrl_cmd.type = buf_p->vbuf.type;
+	kfree(buf_p);
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) ctrl_cmd.value, ctrl_cmd.len);
+
+	if (copy_to_user(to, &ctrl_cmd, sizeof(ctrl_cmd))) {
+		GMN_PR_ERR("%s:%d]\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_gemini_evt_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_q_unblock(&pgmn_dev->evt_q);
+	return 0;
+}
+
+void msm_gemini_reset_ack_irq(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+}
+
+void msm_gemini_err_irq(struct msm_gemini_device *pgmn_dev,
+	int event)
+{
+	int rc = 0;
+	struct msm_gemini_core_buf buf;
+
+	GMN_DBG("%s:%d] error: %d\n", __func__, __LINE__, event);
+
+	buf.vbuf.type = MSM_GEMINI_EVT_ERR;
+	rc = msm_gemini_q_in_buf(&pgmn_dev->evt_q, &buf);
+	if (!rc)
+		rc = msm_gemini_q_wakeup(&pgmn_dev->evt_q);
+
+	if (!rc)
+		GMN_PR_ERR("%s:%d] err err\n", __func__, __LINE__);
+
+	return;
+}
+
+/*************** output queue ****************/
+
+int msm_gemini_get_out_buffer(struct msm_gemini_device *pgmn_dev,
+	struct msm_gemini_hw_buf *p_outbuf)
+{
+	int buf_size = 0;
+	int bytes_remaining = 0;
+	if (pgmn_dev->out_offset >= pgmn_dev->out_buf.y_len) {
+		GMN_PR_ERR("%s:%d] no more buffers", __func__, __LINE__);
+		return -EINVAL;
+	}
+	bytes_remaining = pgmn_dev->out_buf.y_len - pgmn_dev->out_offset;
+	buf_size = min(bytes_remaining, pgmn_dev->max_out_size);
+
+	pgmn_dev->out_frag_cnt++;
+	GMN_DBG("%s:%d] buf_size[%d] %d", __func__, __LINE__,
+		pgmn_dev->out_frag_cnt, buf_size);
+	p_outbuf->y_len = buf_size;
+	p_outbuf->y_buffer_addr = pgmn_dev->out_buf.y_buffer_addr +
+		pgmn_dev->out_offset;
+	pgmn_dev->out_offset += buf_size;
+	return 0;
+}
+
+int msm_gemini_outmode_single_we_pingpong_irq(
+	struct msm_gemini_device *pgmn_dev,
+	struct msm_gemini_core_buf *buf_in)
+{
+	int rc = 0;
+	struct msm_gemini_core_buf out_buf;
+	int frame_done = buf_in &&
+		buf_in->vbuf.type == MSM_GEMINI_EVT_FRAMEDONE;
+	GMN_DBG("%s:%d] framedone %d", __func__, __LINE__, frame_done);
+	if (!pgmn_dev->out_buf_set) {
+		GMN_PR_ERR("%s:%d] output buffer not set",
+			__func__, __LINE__);
+		return -EFAULT;
+	}
+	if (frame_done) {
+		/* send the buffer back */
+		pgmn_dev->out_buf.vbuf.framedone_len = buf_in->framedone_len;
+		pgmn_dev->out_buf.vbuf.type = MSM_GEMINI_EVT_FRAMEDONE;
+		rc = msm_gemini_q_in_buf(&pgmn_dev->output_rtn_q,
+			&pgmn_dev->out_buf);
+		if (rc) {
+			GMN_PR_ERR("%s:%d] cannot queue the output buffer",
+				 __func__, __LINE__);
+			return -EFAULT;
+		}
+		rc =  msm_gemini_q_wakeup(&pgmn_dev->output_rtn_q);
+		/*
+		 * reset the output buffer since the ownership is
+		 * transferred to the rtn queue
+		 */
+		if (!rc)
+			pgmn_dev->out_buf_set = 0;
+	} else {
+		/* configure ping/pong */
+		rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+		if (rc)
+			msm_gemini_core_we_buf_reset(&out_buf);
+		else
+			msm_gemini_core_we_buf_update(&out_buf);
+	}
+	return rc;
+}
+
+int msm_gemini_we_pingpong_irq(struct msm_gemini_device *pgmn_dev,
+	struct msm_gemini_core_buf *buf_in)
+{
+	int rc = 0;
+	struct msm_gemini_core_buf *buf_out;
+
+	GMN_DBG("%s:%d] Enter mode %d", __func__, __LINE__,
+		pgmn_dev->out_mode);
+
+	if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_SINGLE)
+		return msm_gemini_outmode_single_we_pingpong_irq(pgmn_dev,
+			buf_in);
+
+	if (buf_in) {
+		GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len);
+		rc = msm_gemini_q_in_buf(&pgmn_dev->output_rtn_q, buf_in);
+	} else {
+		GMN_DBG("%s:%d] no output return buffer\n", __func__,
+			__LINE__);
+		rc = -1;
+		return rc;
+	}
+
+	buf_out = msm_gemini_q_out(&pgmn_dev->output_buf_q);
+
+	if (buf_out) {
+		rc = msm_gemini_core_we_buf_update(buf_out);
+		kfree(buf_out);
+	} else {
+		msm_gemini_core_we_buf_reset(buf_in);
+		GMN_DBG("%s:%d] no output buffer\n", __func__, __LINE__);
+		rc = -2;
+	}
+
+	if (buf_in)
+		rc = msm_gemini_q_wakeup(&pgmn_dev->output_rtn_q);
+
+	return rc;
+}
+
+int msm_gemini_output_get(struct msm_gemini_device *pgmn_dev, void __user *to)
+{
+	struct msm_gemini_core_buf *buf_p;
+	struct msm_gemini_buf buf_cmd;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	msm_gemini_q_wait(&pgmn_dev->output_rtn_q);
+	buf_p = msm_gemini_q_out(&pgmn_dev->output_rtn_q);
+
+	if (!buf_p) {
+		GMN_DBG("%s:%d] no output buffer return\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	buf_cmd = buf_p->vbuf;
+	msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
+	kfree(buf_p);
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+		GMN_PR_ERR("%s:%d]", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_gemini_output_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_q_unblock(&pgmn_dev->output_rtn_q);
+	return 0;
+}
+
+int msm_gemini_set_output_buf(struct msm_gemini_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_gemini_buf buf_cmd;
+
+	if (pgmn_dev->out_buf_set) {
+		GMN_PR_ERR("%s:%d] outbuffer buffer already provided",
+			__func__, __LINE__);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	GMN_DBG("%s:%d] output addr 0x%08x len %d", __func__, __LINE__,
+		(int) buf_cmd.vaddr,
+		buf_cmd.y_len);
+
+	pgmn_dev->out_buf.y_buffer_addr = msm_gemini_platform_v2p(
+		buf_cmd.fd,
+		buf_cmd.y_len,
+		&pgmn_dev->out_buf.file,
+		&pgmn_dev->out_buf.handle);
+	if (!pgmn_dev->out_buf.y_buffer_addr) {
+		GMN_PR_ERR("%s:%d] cannot map the output address",
+			__func__, __LINE__);
+		return -EFAULT;
+	}
+	pgmn_dev->out_buf.y_len = buf_cmd.y_len;
+	pgmn_dev->out_buf.vbuf = buf_cmd;
+	pgmn_dev->out_buf_set = 1;
+
+	return 0;
+}
+
+int msm_gemini_output_buf_enqueue(struct msm_gemini_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_gemini_buf buf_cmd;
+	struct msm_gemini_core_buf *buf_p;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+		return -ENOMEM;
+	}
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__, (int) buf_cmd.vaddr,
+		buf_cmd.y_len);
+
+	buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
+		buf_cmd.y_len, &buf_p->file, &buf_p->handle);
+	if (!buf_p->y_buffer_addr) {
+		GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		kfree(buf_p);
+		return -ENOMEM;
+	}
+	buf_p->y_len = buf_cmd.y_len;
+	buf_p->vbuf = buf_cmd;
+
+	msm_gemini_q_in(&pgmn_dev->output_buf_q, buf_p);
+	return 0;
+}
+
+/*************** input queue ****************/
+
+int msm_gemini_fe_pingpong_irq(struct msm_gemini_device *pgmn_dev,
+	struct msm_gemini_core_buf *buf_in)
+{
+	struct msm_gemini_core_buf *buf_out;
+	int rc = 0;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (buf_in) {
+		GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+			(int) buf_in->y_buffer_addr, buf_in->y_len);
+		rc = msm_gemini_q_in_buf(&pgmn_dev->input_rtn_q, buf_in);
+	} else {
+		GMN_DBG("%s:%d] no input return buffer\n", __func__,
+			__LINE__);
+		rc = -1;
+	}
+
+	buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q);
+
+	if (buf_out) {
+		rc = msm_gemini_core_fe_buf_update(buf_out);
+		kfree(buf_out);
+		msm_gemini_core_fe_start();
+	} else {
+		GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+		rc = -2;
+	}
+
+	if (buf_in)
+		rc = msm_gemini_q_wakeup(&pgmn_dev->input_rtn_q);
+
+	return rc;
+}
+
+int msm_gemini_input_get(struct msm_gemini_device *pgmn_dev, void __user *to)
+{
+	struct msm_gemini_core_buf *buf_p;
+	struct msm_gemini_buf buf_cmd;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_q_wait(&pgmn_dev->input_rtn_q);
+	buf_p = msm_gemini_q_out(&pgmn_dev->input_rtn_q);
+
+	if (!buf_p) {
+		GMN_DBG("%s:%d] no input buffer return\n",
+			__func__, __LINE__);
+		return -EAGAIN;
+	}
+
+	buf_cmd = buf_p->vbuf;
+	if (pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ENCODE ||
+		pgmn_dev->op_mode == MSM_GEMINI_MODE_OFFLINE_ROTATION) {
+		msm_gemini_platform_p2v(buf_p->file, &buf_p->handle);
+	}
+	kfree(buf_p);
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (copy_to_user(to, &buf_cmd, sizeof(buf_cmd))) {
+		GMN_PR_ERR("%s:%d]\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int msm_gemini_input_get_unblock(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	msm_gemini_q_unblock(&pgmn_dev->input_rtn_q);
+	return 0;
+}
+
+int msm_gemini_input_buf_enqueue(struct msm_gemini_device *pgmn_dev,
+	void __user *arg)
+{
+	struct msm_gemini_core_buf *buf_p;
+	struct msm_gemini_buf buf_cmd;
+	int rc = 0;
+	struct msm_bus_scale_pdata *p_bus_scale_data = NULL;
+
+	if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	buf_p = kmalloc(sizeof(struct msm_gemini_core_buf), GFP_ATOMIC);
+	if (!buf_p) {
+		GMN_PR_ERR("%s:%d] no mem\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	GMN_DBG("%s:%d] 0x%08x %d\n", __func__, __LINE__,
+		(int) buf_cmd.vaddr, buf_cmd.y_len);
+
+	if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
+		rc = msm_iommu_map_contig_buffer(
+			(unsigned long)buf_cmd.y_off, CAMERA_DOMAIN, GEN_POOL,
+			((buf_cmd.y_len + buf_cmd.cbcr_len + 4095) & (~4095)),
+			SZ_4K, IOMMU_WRITE | IOMMU_READ,
+			(unsigned long *)&buf_p->y_buffer_addr);
+		if (rc < 0) {
+			GMN_PR_ERR("%s iommu mapping failed with error %d\n",
+				 __func__, rc);
+			kfree(buf_p);
+			return rc;
+		}
+	} else {
+		buf_p->y_buffer_addr    = msm_gemini_platform_v2p(buf_cmd.fd,
+			buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
+			&buf_p->handle)	+ buf_cmd.offset + buf_cmd.y_off;
+	}
+	buf_p->y_len          = buf_cmd.y_len;
+
+	buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len +
+					buf_cmd.cbcr_off;
+	buf_p->cbcr_len       = buf_cmd.cbcr_len;
+	buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
+	GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
+		buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
+		buf_p->cbcr_len);
+
+	if (!buf_p->y_buffer_addr || !buf_p->cbcr_buffer_addr) {
+		GMN_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+		kfree(buf_p);
+		return -EINVAL;
+	}
+	buf_p->vbuf           = buf_cmd;
+	buf_p->vbuf.type      = MSM_GEMINI_EVT_RESET;
+
+	/* Set bus vectors */
+	p_bus_scale_data = (struct msm_bus_scale_pdata *)
+		pgmn_dev->pdev->dev.platform_data;
+	if (pgmn_dev->bus_perf_client &&
+		(MSM_GMN_OUTMODE_SINGLE == pgmn_dev->out_mode)) {
+		int rc;
+		struct msm_bus_paths *path = &(p_bus_scale_data->usecase[1]);
+		GMN_DBG("%s:%d] Update bus bandwidth", __func__, __LINE__);
+		if (pgmn_dev->op_mode & MSM_GEMINI_MODE_OFFLINE_ENCODE) {
+			path->vectors[0].ab = (buf_p->y_len + buf_p->cbcr_len) *
+				15 * 2;
+			path->vectors[0].ib = path->vectors[0].ab;
+			path->vectors[1].ab = 0;
+			path->vectors[1].ib = 0;
+		}
+		rc = msm_bus_scale_client_update_request(
+			pgmn_dev->bus_perf_client, 1);
+		if (rc < 0) {
+			GMN_PR_ERR("%s:%d] update_request fails %d",
+				__func__, __LINE__, rc);
+		}
+	}
+
+	msm_gemini_q_in(&pgmn_dev->input_buf_q, buf_p);
+
+	return 0;
+}
+
+int msm_gemini_irq(int event, void *context, void *data)
+{
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *) context;
+
+	switch (event) {
+	case MSM_GEMINI_HW_MASK_COMP_FRAMEDONE:
+		msm_gemini_framedone_irq(pgmn_dev, data);
+		msm_gemini_we_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_GEMINI_HW_MASK_COMP_FE:
+		msm_gemini_fe_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_GEMINI_HW_MASK_COMP_WE:
+		msm_gemini_we_pingpong_irq(pgmn_dev, data);
+		break;
+
+	case MSM_GEMINI_HW_MASK_COMP_RESET_ACK:
+		msm_gemini_reset_ack_irq(pgmn_dev);
+		break;
+
+	case MSM_GEMINI_HW_MASK_COMP_ERR:
+	default:
+		msm_gemini_err_irq(pgmn_dev, event);
+		break;
+	}
+
+	return 0;
+}
+
+int __msm_gemini_open(struct msm_gemini_device *pgmn_dev)
+{
+	int rc;
+	struct msm_bus_scale_pdata *p_bus_scale_data =
+		(struct msm_bus_scale_pdata *)pgmn_dev->pdev->dev.
+			platform_data;
+
+	mutex_lock(&pgmn_dev->lock);
+	if (pgmn_dev->open_count) {
+		/* only open once */
+		GMN_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+		mutex_unlock(&pgmn_dev->lock);
+		return -EBUSY;
+	}
+	pgmn_dev->open_count++;
+	mutex_unlock(&pgmn_dev->lock);
+
+	msm_gemini_core_irq_install(msm_gemini_irq);
+
+
+	rc = msm_gemini_platform_init(pgmn_dev->pdev,
+		&pgmn_dev->mem, &pgmn_dev->base,
+		&pgmn_dev->irq, msm_gemini_core_irq, pgmn_dev);
+	if (rc) {
+		GMN_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+			__LINE__, rc);
+		return rc;
+	}
+
+	GMN_DBG("%s:%d] platform resources - mem %p, base %p, irq %d\n",
+		__func__, __LINE__,
+		pgmn_dev->mem, pgmn_dev->base, pgmn_dev->irq);
+
+	msm_gemini_q_cleanup(&pgmn_dev->evt_q);
+	msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q);
+	msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q);
+	msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q);
+	msm_gemini_q_cleanup(&pgmn_dev->input_buf_q);
+	msm_gemini_core_init();
+	pgmn_dev->out_mode = MSM_GMN_OUTMODE_FRAGMENTED;
+	pgmn_dev->out_buf_set = 0;
+	pgmn_dev->out_offset = 0;
+	pgmn_dev->max_out_size = g_max_out_size;
+	pgmn_dev->out_frag_cnt = 0;
+	pgmn_dev->bus_perf_client = 0;
+
+	if (p_bus_scale_data) {
+		GMN_DBG("%s:%d] register bus client", __func__, __LINE__);
+		pgmn_dev->bus_perf_client =
+			msm_bus_scale_register_client(p_bus_scale_data);
+		if (!pgmn_dev->bus_perf_client) {
+			GMN_PR_ERR("%s:%d] bus client register failed",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+	}
+	GMN_DBG("%s:%d] success\n", __func__, __LINE__);
+	return rc;
+}
+
+int __msm_gemini_release(struct msm_gemini_device *pgmn_dev)
+{
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	mutex_lock(&pgmn_dev->lock);
+	if (!pgmn_dev->open_count) {
+		GMN_PR_ERR("%s: not opened\n", __func__);
+		mutex_unlock(&pgmn_dev->lock);
+		return -EINVAL;
+	}
+	pgmn_dev->open_count--;
+	mutex_unlock(&pgmn_dev->lock);
+
+	if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED) {
+		msm_gemini_core_release(release_buf);
+	} else if (pgmn_dev->out_buf_set) {
+		msm_gemini_platform_p2v(pgmn_dev->out_buf.file,
+			&pgmn_dev->out_buf.handle);
+	}
+	msm_gemini_q_cleanup(&pgmn_dev->evt_q);
+	msm_gemini_q_cleanup(&pgmn_dev->output_rtn_q);
+	msm_gemini_outbuf_q_cleanup(&pgmn_dev->output_buf_q);
+	msm_gemini_q_cleanup(&pgmn_dev->input_rtn_q);
+	msm_gemini_outbuf_q_cleanup(&pgmn_dev->input_buf_q);
+
+	if (pgmn_dev->bus_perf_client) {
+		msm_bus_scale_unregister_client(pgmn_dev->bus_perf_client);
+		pgmn_dev->bus_perf_client = 0;
+	}
+
+	if (pgmn_dev->open_count)
+		GMN_PR_ERR("%s: multiple opens\n", __func__);
+
+	msm_gemini_platform_release(pgmn_dev->mem, pgmn_dev->base,
+		pgmn_dev->irq, pgmn_dev);
+
+	return 0;
+}
+
+int msm_gemini_ioctl_hw_cmd(struct msm_gemini_device *pgmn_dev,
+	void * __user arg)
+{
+	struct msm_gemini_hw_cmd hw_cmd;
+	int is_copy_to_user;
+
+	if (copy_from_user(&hw_cmd, arg, sizeof(struct msm_gemini_hw_cmd))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	is_copy_to_user = msm_gemini_hw_exec_cmds(&hw_cmd, 1);
+	GMN_DBG("%s:%d] type %d, n %d, offset %d, mask %x, data %x, pdata %x\n",
+		__func__, __LINE__, hw_cmd.type, hw_cmd.n, hw_cmd.offset,
+		hw_cmd.mask, hw_cmd.data, (int) hw_cmd.pdata);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user(arg, &hw_cmd, sizeof(hw_cmd))) {
+			GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int msm_gemini_ioctl_hw_cmds(struct msm_gemini_device *pgmn_dev,
+	void * __user arg)
+{
+	int is_copy_to_user;
+	int len;
+	uint32_t m;
+	struct msm_gemini_hw_cmds *hw_cmds_p;
+	struct msm_gemini_hw_cmd *hw_cmd_p;
+
+	if (copy_from_user(&m, arg, sizeof(m))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	len = sizeof(struct msm_gemini_hw_cmds) +
+		sizeof(struct msm_gemini_hw_cmd) * (m - 1);
+	hw_cmds_p = kmalloc(len, GFP_KERNEL);
+	if (!hw_cmds_p) {
+		GMN_PR_ERR("%s:%d] no mem %d\n", __func__, __LINE__, len);
+		return -EFAULT;
+	}
+
+	if (copy_from_user(hw_cmds_p, arg, len)) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		kfree(hw_cmds_p);
+		return -EFAULT;
+	}
+
+	hw_cmd_p = (struct msm_gemini_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+	is_copy_to_user = msm_gemini_hw_exec_cmds(hw_cmd_p, m);
+
+	if (is_copy_to_user >= 0) {
+		if (copy_to_user(arg, hw_cmds_p, len)) {
+			GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+			kfree(hw_cmds_p);
+			return -EFAULT;
+		}
+	}
+	kfree(hw_cmds_p);
+	return 0;
+}
+
+static int msm_gemini_start(struct msm_gemini_device *pgmn_dev,
+		void * __user arg)
+{
+	struct msm_gemini_core_buf *buf_out;
+	struct msm_gemini_core_buf *buf_out_free[2] = {NULL, NULL};
+	int i, rc;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+
+	release_buf = 1;
+	for (i = 0; i < 2; i++) {
+		buf_out = msm_gemini_q_out(&pgmn_dev->input_buf_q);
+
+		if (buf_out) {
+			msm_gemini_core_fe_buf_update(buf_out);
+			kfree(buf_out);
+		} else {
+			GMN_DBG("%s:%d] no input buffer\n", __func__, __LINE__);
+			break;
+		}
+	}
+
+	if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED) {
+		for (i = 0; i < 2; i++) {
+			buf_out_free[i] =
+				msm_gemini_q_out(&pgmn_dev->output_buf_q);
+
+			if (buf_out_free[i]) {
+				msm_gemini_core_we_buf_update(buf_out_free[i]);
+			} else if (i == 1) {
+				/* set the pong to same address as ping */
+				buf_out_free[0]->y_len >>= 1;
+				buf_out_free[0]->y_buffer_addr +=
+					buf_out_free[0]->y_len;
+				msm_gemini_core_we_buf_update(buf_out_free[0]);
+				/*
+				 * since ping and pong are same buf
+				 * release only once
+				 */
+				release_buf = 0;
+			} else {
+				GMN_DBG("%s:%d] no output buffer\n",
+					__func__, __LINE__);
+				break;
+			}
+		}
+		for (i = 0; i < 2; i++)
+			kfree(buf_out_free[i]);
+	} else {
+		struct msm_gemini_core_buf out_buf;
+		/*
+		 * Since the same buffer is fragmented, p2v need not be
+		 * called for all the buffers
+		 */
+		release_buf = 0;
+		if (!pgmn_dev->out_buf_set) {
+			GMN_PR_ERR("%s:%d] output buffer not set",
+				__func__, __LINE__);
+			return -EFAULT;
+		}
+		/* configure ping */
+		rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+		if (rc) {
+			GMN_PR_ERR("%s:%d] no output buffer for ping",
+				__func__, __LINE__);
+			return rc;
+		}
+		msm_gemini_core_we_buf_update(&out_buf);
+		/* configure pong */
+		rc = msm_gemini_get_out_buffer(pgmn_dev, &out_buf);
+		if (rc) {
+			GMN_DBG("%s:%d] no output buffer for pong",
+				__func__, __LINE__);
+			/* fall through to configure same buffer */
+		}
+		msm_gemini_core_we_buf_update(&out_buf);
+		msm_gemini_io_dump(0x150);
+	}
+
+	rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, arg);
+	GMN_DBG("%s:%d]\n", __func__, __LINE__);
+	return rc;
+}
+
+static int msm_gemini_ioctl_reset(struct msm_gemini_device *pgmn_dev,
+	void * __user arg)
+{
+	int rc;
+	struct msm_gemini_ctrl_cmd ctrl_cmd;
+
+	GMN_DBG("%s:%d] Enter\n", __func__, __LINE__);
+	if (copy_from_user(&ctrl_cmd, arg, sizeof(ctrl_cmd))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+
+	pgmn_dev->op_mode = ctrl_cmd.type;
+
+	rc = msm_gemini_core_reset(pgmn_dev->op_mode, pgmn_dev->base,
+		resource_size(pgmn_dev->mem));
+	return rc;
+}
+
+static int msm_gemini_ioctl_set_outmode(struct msm_gemini_device *pgmn_dev,
+	void * __user arg)
+{
+	int rc = 0;
+	enum msm_gmn_out_mode mode;
+
+	if (copy_from_user(&mode, arg, sizeof(mode))) {
+		GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	GMN_DBG("%s:%d] mode %d", __func__, __LINE__, mode);
+
+	if ((mode == MSM_GMN_OUTMODE_FRAGMENTED)
+		|| (mode == MSM_GMN_OUTMODE_SINGLE))
+		pgmn_dev->out_mode = mode;
+	return rc;
+}
+
+long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	switch (cmd) {
+	case MSM_GMN_IOCTL_GET_HW_VERSION:
+		GMN_DBG("%s:%d] VERSION 1\n", __func__, __LINE__);
+		rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_RESET:
+		rc = msm_gemini_ioctl_reset(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_STOP:
+		rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_START:
+		rc = msm_gemini_start(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_INPUT_BUF_ENQUEUE:
+		rc = msm_gemini_input_buf_enqueue(pgmn_dev,
+			(void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_INPUT_GET:
+		rc = msm_gemini_input_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_INPUT_GET_UNBLOCK:
+		rc = msm_gemini_input_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_GMN_IOCTL_OUTPUT_BUF_ENQUEUE:
+		if (pgmn_dev->out_mode == MSM_GMN_OUTMODE_FRAGMENTED)
+			rc = msm_gemini_output_buf_enqueue(pgmn_dev,
+				(void __user *) arg);
+		else
+			rc = msm_gemini_set_output_buf(pgmn_dev,
+				(void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_OUTPUT_GET:
+		rc = msm_gemini_output_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_OUTPUT_GET_UNBLOCK:
+		rc = msm_gemini_output_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_GMN_IOCTL_EVT_GET:
+		rc = msm_gemini_evt_get(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_EVT_GET_UNBLOCK:
+		rc = msm_gemini_evt_get_unblock(pgmn_dev);
+		break;
+
+	case MSM_GMN_IOCTL_HW_CMD:
+		rc = msm_gemini_ioctl_hw_cmd(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_HW_CMDS:
+		rc = msm_gemini_ioctl_hw_cmds(pgmn_dev, (void __user *) arg);
+		break;
+
+	case MSM_GMN_IOCTL_SET_MODE:
+		rc = msm_gemini_ioctl_set_outmode(pgmn_dev, (void __user *)arg);
+		break;
+
+	default:
+		GMN_PR_ERR("%s:%d] cmd = %d not supported\n",
+			__func__, __LINE__, _IOC_NR(cmd));
+		rc = -EINVAL;
+		break;
+	}
+	return rc;
+}
+
+struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev)
+{
+	struct msm_gemini_device *pgmn_dev;
+
+	pgmn_dev = kzalloc(sizeof(struct msm_gemini_device), GFP_ATOMIC);
+	if (!pgmn_dev) {
+		GMN_PR_ERR("%s:%d]no mem\n", __func__, __LINE__);
+		return NULL;
+	}
+
+	mutex_init(&pgmn_dev->lock);
+
+	pgmn_dev->pdev = pdev;
+
+	msm_gemini_q_init("evt_q", &pgmn_dev->evt_q);
+	msm_gemini_q_init("output_rtn_q", &pgmn_dev->output_rtn_q);
+	msm_gemini_q_init("output_buf_q", &pgmn_dev->output_buf_q);
+	msm_gemini_q_init("input_rtn_q", &pgmn_dev->input_rtn_q);
+	msm_gemini_q_init("input_buf_q", &pgmn_dev->input_buf_q);
+
+	return pgmn_dev;
+}
+
+int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev)
+{
+	mutex_destroy(&pgmn_dev->lock);
+	kfree(pgmn_dev);
+	return 0;
+}
+
diff --git a/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h
new file mode 100644
index 0000000..6982a78
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/gemini/msm_gemini_sync.h
@@ -0,0 +1,98 @@
+/* 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.
+ */
+
+#ifndef MSM_GEMINI_SYNC_H
+#define MSM_GEMINI_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_gemini_core.h"
+
+#define GEMINI_7X 0x1
+#define GEMINI_8X60 (0x1 << 1)
+#define GEMINI_8960 (0x1 << 2)
+
+struct msm_gemini_q {
+	char const	*name;
+	struct list_head  q;
+	spinlock_t	lck;
+	wait_queue_head_t wait;
+	int	       unblck;
+};
+
+struct msm_gemini_q_entry {
+	struct list_head list;
+	void   *data;
+};
+
+struct msm_gemini_device {
+	struct platform_device *pdev;
+	struct resource        *mem;
+	int                     irq;
+	void                   *base;
+	struct clk *gemini_clk[3];
+	struct regulator *gemini_fs;
+	uint32_t hw_version;
+
+	struct device *device;
+	struct cdev   cdev;
+	struct mutex  lock;
+	char	  open_count;
+	uint8_t       op_mode;
+
+	/* event queue including frame done & err indications
+	 */
+	struct msm_gemini_q evt_q;
+
+	/* output return queue
+	 */
+	struct msm_gemini_q output_rtn_q;
+
+	/* output buf queue
+	 */
+	struct msm_gemini_q output_buf_q;
+
+	/* input return queue
+	 */
+	struct msm_gemini_q input_rtn_q;
+
+	/* input buf queue
+	 */
+	struct msm_gemini_q input_buf_q;
+
+	struct v4l2_subdev subdev;
+	enum msm_gmn_out_mode out_mode;
+
+	/*single out mode parameters*/
+	struct msm_gemini_hw_buf out_buf;
+	int out_offset;
+	int out_buf_set;
+	int max_out_size;
+	int out_frag_cnt;
+
+	uint32_t bus_perf_client;
+};
+
+int __msm_gemini_open(struct msm_gemini_device *pgmn_dev);
+int __msm_gemini_release(struct msm_gemini_device *pgmn_dev);
+
+long __msm_gemini_ioctl(struct msm_gemini_device *pgmn_dev,
+	unsigned int cmd, unsigned long arg);
+
+struct msm_gemini_device *__msm_gemini_init(struct platform_device *pdev);
+int __msm_gemini_exit(struct msm_gemini_device *pgmn_dev);
+
+#endif /* MSM_GEMINI_SYNC_H */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 59858b5..88f2f08 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -80,13 +80,20 @@
 }
 
 static uint32_t msm_isp_get_buf_handle(
-	struct msm_isp_buf_mgr *buf_mgr)
+	struct msm_isp_buf_mgr *buf_mgr,
+	uint32_t session_id, uint32_t stream_id)
 {
 	int i;
 	if ((buf_mgr->buf_handle_cnt << 8) == 0)
 		buf_mgr->buf_handle_cnt++;
 
 	for (i = 0; i < buf_mgr->num_buf_q; i++) {
+		if (buf_mgr->bufq[i].session_id == session_id &&
+			buf_mgr->bufq[i].stream_id == stream_id)
+			return 0;
+	}
+
+	for (i = 0; i < buf_mgr->num_buf_q; i++) {
 		if (buf_mgr->bufq[i].bufq_handle == 0) {
 			memset(&buf_mgr->bufq[i],
 				0, sizeof(struct msm_isp_bufq));
@@ -604,7 +611,8 @@
 		return rc;
 	}
 
-	buf_request->handle = msm_isp_get_buf_handle(buf_mgr);
+	buf_request->handle = msm_isp_get_buf_handle(buf_mgr,
+		buf_request->session_id, buf_request->stream_id);
 	if (!buf_request->handle) {
 		pr_err("Invalid buffer handle\n");
 		return rc;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 7bc2b7d..6de6e74 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -38,6 +38,8 @@
 #define VFE_PING_FLAG 0xFFFFFFFF
 #define VFE_PONG_FLAG 0x0
 
+#define VFE_MAX_CFG_TIMEOUT 3000
+
 struct vfe_device;
 struct msm_vfe_axi_stream;
 struct msm_vfe_stats_stream;
@@ -88,7 +90,7 @@
 	void (*enable_wm) (struct vfe_device *vfe_dev,
 		uint8_t wm_idx, uint8_t enable);
 	void (*cfg_io_format) (struct vfe_device *vfe_dev,
-		struct msm_vfe_axi_stream_request_cmd *stream_req_cmd);
+		struct msm_vfe_axi_stream *stream_info);
 	void (*cfg_framedrop) (struct vfe_device *vfe_dev,
 		struct msm_vfe_axi_stream *stream_info);
 	void (*clear_framedrop) (struct vfe_device *vfe_dev,
@@ -103,13 +105,13 @@
 		struct msm_vfe_axi_stream *stream_info);
 
 	void (*cfg_wm_reg) (struct vfe_device *vfe_dev,
-		struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+		struct msm_vfe_axi_stream *stream_info,
 		uint8_t plane_idx);
 	void (*clear_wm_reg) (struct vfe_device *vfe_dev,
 		struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
 
 	void (*cfg_wm_xbar_reg) (struct vfe_device *vfe_dev,
-		struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+		struct msm_vfe_axi_stream *stream_info,
 		uint8_t plane_idx);
 	void (*clear_wm_xbar_reg) (struct vfe_device *vfe_dev,
 		struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx);
@@ -231,7 +233,8 @@
 	enum msm_vfe_axi_stream_src stream_src;
 	uint8_t num_planes;
 	uint8_t wm[MAX_PLANES_PER_STREAM];
-	uint32_t plane_offset[MAX_PLANES_PER_STREAM];
+	uint32_t output_format;/*Planar/RAW/Misc*/
+	struct msm_vfe_axi_plane_cfg plane_cfg[MAX_PLANES_PER_STREAM];
 	uint8_t comp_mask_index;
 	struct msm_isp_buffer *buf[2];
 	uint32_t session_id;
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 679c5cb..3a94af3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -441,11 +441,11 @@
 }
 
 static void msm_vfe32_cfg_io_format(struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+	struct msm_vfe_axi_stream *stream_info)
 {
 	int bpp, bpp_reg = 0;
 	uint32_t io_format_reg;
-	bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+	bpp = msm_isp_get_bit_per_pixel(stream_info->output_format);
 
 	switch (bpp) {
 	case 8:
@@ -459,7 +459,7 @@
 		break;
 	}
 	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x6F8);
-	switch (stream_req_cmd->stream_src) {
+	switch (stream_info->stream_src) {
 	case CAMIF_RAW:
 		io_format_reg &= 0xFFFFCFFF;
 		io_format_reg |= bpp_reg << 12;
@@ -565,44 +565,40 @@
 
 static void msm_vfe32_axi_cfg_wm_reg(
 	struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+	struct msm_vfe_axi_stream *stream_info,
 	uint8_t plane_idx)
 {
 	uint32_t val;
-	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-			(stream_cfg_cmd->axi_stream_handle & 0xFF)];
 	uint32_t wm_base = VFE32_WM_BASE(stream_info->wm[plane_idx]);
 
 	if (!stream_info->frame_based) {
 		/*WR_IMAGE_SIZE*/
 		val =
 			((msm_isp_cal_word_per_line(
-			stream_cfg_cmd->output_format,
-			stream_cfg_cmd->plane_cfg[plane_idx].
+			stream_info->output_format,
+			stream_info->plane_cfg[plane_idx].
 			output_width)+1)/2 - 1) << 16 |
-			(stream_cfg_cmd->plane_cfg[plane_idx].
+			(stream_info->plane_cfg[plane_idx].
 			output_height - 1);
 		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x10);
 
 		/*WR_BUFFER_CFG*/
 		val =
 			msm_isp_cal_word_per_line(
-			stream_cfg_cmd->output_format,
-			stream_cfg_cmd->plane_cfg[plane_idx].
+			stream_info->output_format,
+			stream_info->plane_cfg[plane_idx].
 			output_stride) << 16 |
-			(stream_cfg_cmd->plane_cfg[plane_idx].
+			(stream_info->plane_cfg[plane_idx].
 			output_height - 1) << 4 | VFE32_BURST_LEN;
 		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
 	} else {
 		msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
 		val =
 			msm_isp_cal_word_per_line(
-			stream_cfg_cmd->output_format,
-			stream_cfg_cmd->plane_cfg[plane_idx].
+			stream_info->output_format,
+			stream_info->plane_cfg[plane_idx].
 			output_width) << 16 |
-			(stream_cfg_cmd->plane_cfg[plane_idx].
+			(stream_info->plane_cfg[plane_idx].
 			output_height - 1) << 4 | VFE32_BURST_LEN;
 		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
 	}
@@ -624,19 +620,15 @@
 
 static void msm_vfe32_axi_cfg_wm_xbar_reg(
 	struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
-	uint8_t plane_idx)
+	struct msm_vfe_axi_stream *stream_info, uint8_t plane_idx)
 {
-	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-	struct msm_vfe_axi_stream *stream_info =
-	 &axi_data->stream_info[(stream_cfg_cmd->axi_stream_handle & 0xFF)];
 	struct msm_vfe_axi_plane_cfg *plane_cfg =
-		&stream_cfg_cmd->plane_cfg[plane_idx];
+		&stream_info->plane_cfg[plane_idx];
 	uint8_t wm = stream_info->wm[plane_idx];
 	uint32_t xbar_cfg = 0;
 	uint32_t xbar_reg_cfg = 0;
 
-	switch (stream_cfg_cmd->stream_src) {
+	switch (stream_info->stream_src) {
 	case PIX_ENCODER:
 	case PIX_VIEWFINDER: {
 		if (plane_cfg->output_plane_format != CRCB_PLANE &&
@@ -644,7 +636,7 @@
 			/*SINGLE_STREAM_SEL*/
 			xbar_cfg |= plane_cfg->output_plane_format << 5;
 		} else {
-			switch (stream_cfg_cmd->output_format) {
+			switch (stream_info->output_format) {
 			case V4L2_PIX_FMT_NV12:
 			case V4L2_PIX_FMT_NV16:
 				xbar_cfg |= 0x3 << 3; /*PAIR_STREAM_SWAP_CTRL*/
@@ -652,7 +644,7 @@
 			}
 			xbar_cfg |= BIT(1); /*PAIR_STREAM_EN*/
 		}
-		if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
+		if (stream_info->stream_src == PIX_VIEWFINDER)
 			xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
 		break;
 	}
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 756cb41..c4a1b63 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -436,6 +436,8 @@
 {
 	*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
 	*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
+	/*Ignore composite 3 irq which is used for dual VFE only*/
+	*irq_status0 &= ~BIT(28);
 	msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
 	msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
 	msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
@@ -521,14 +523,14 @@
 	comp_mask &= ~(0x7F << (comp_mask_index * 8));
 	comp_mask |= (axi_data->composite_info[comp_mask_index].
 		stream_composite_mask << (comp_mask_index * 8));
-	if (stream_info->plane_offset[0])
+	if (stream_info->plane_cfg[0].plane_addr_offset)
 		comp_mask |= (axi_data->composite_info[comp_mask_index].
 		stream_composite_mask << 24);
 	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 
 	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
 	irq_mask |= 1 << (comp_mask_index + 25);
-	if (stream_info->plane_offset[0] && (comp_mask >> 24))
+	if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
 		irq_mask |= BIT(28);
 	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
 }
@@ -542,14 +544,14 @@
 
 	comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40);
 	comp_mask &= ~(0x7F << (comp_mask_index * 8));
-	if (stream_info->plane_offset[0])
+	if (stream_info->plane_cfg[0].plane_addr_offset)
 		comp_mask &= ~(axi_data->composite_info[comp_mask_index].
 		stream_composite_mask << 24);
 	msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40);
 
 	irq_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x28);
 	irq_mask &= ~(1 << (comp_mask_index + 25));
-	if (stream_info->plane_offset[0] && !(comp_mask >> 24))
+	if (stream_info->plane_cfg[0].plane_addr_offset && (comp_mask >> 24))
 		irq_mask &= ~BIT(28);
 	msm_camera_io_w(irq_mask, vfe_dev->vfe_base + 0x28);
 }
@@ -612,11 +614,11 @@
 }
 
 static void msm_vfe40_cfg_io_format(struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream_request_cmd *stream_req_cmd)
+	struct msm_vfe_axi_stream *stream_info)
 {
 	int bpp, bpp_reg = 0;
 	uint32_t io_format_reg;
-	bpp = msm_isp_get_bit_per_pixel(stream_req_cmd->output_format);
+	bpp = msm_isp_get_bit_per_pixel(stream_info->output_format);
 
 	switch (bpp) {
 	case 8:
@@ -630,7 +632,7 @@
 		break;
 	}
 	io_format_reg = msm_camera_io_r(vfe_dev->vfe_base + 0x54);
-	switch (stream_req_cmd->stream_src) {
+	switch (stream_info->stream_src) {
 	case CAMIF_RAW:
 		io_format_reg &= 0xFFFFCFFF;
 		io_format_reg |= bpp_reg << 12;
@@ -751,43 +753,39 @@
 
 static void msm_vfe40_axi_cfg_wm_reg(
 	struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+	struct msm_vfe_axi_stream *stream_info,
 	uint8_t plane_idx)
 {
 	uint32_t val;
-	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-			(stream_cfg_cmd->axi_stream_handle & 0xFF)];
 	uint32_t wm_base = VFE40_WM_BASE(stream_info->wm[plane_idx]);
 
 	if (!stream_info->frame_based) {
 		/*WR_IMAGE_SIZE*/
 		val =
 			((msm_isp_cal_word_per_line(
-				stream_cfg_cmd->output_format,
-				stream_cfg_cmd->plane_cfg[plane_idx].
+				stream_info->output_format,
+				stream_info->plane_cfg[plane_idx].
 				output_width)+1)/2 - 1) << 16 |
-				(stream_cfg_cmd->plane_cfg[plane_idx].
+				(stream_info->plane_cfg[plane_idx].
 				output_height - 1);
 		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x14);
 
 		/*WR_BUFFER_CFG*/
 		val =
-			msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
-			stream_cfg_cmd->plane_cfg[
+			msm_isp_cal_word_per_line(stream_info->output_format,
+			stream_info->plane_cfg[
 				plane_idx].output_stride) << 16 |
-			(stream_cfg_cmd->plane_cfg[
+			(stream_info->plane_cfg[
 				plane_idx].output_height - 1) << 4 |
 			VFE40_BURST_LEN;
 		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
 	} else {
 		msm_camera_io_w(0x2, vfe_dev->vfe_base + wm_base);
 		val =
-			msm_isp_cal_word_per_line(stream_cfg_cmd->output_format,
-			stream_cfg_cmd->plane_cfg[
+			msm_isp_cal_word_per_line(stream_info->output_format,
+			stream_info->plane_cfg[
 				plane_idx].output_width) << 16 |
-			(stream_cfg_cmd->plane_cfg[
+			(stream_info->plane_cfg[
 				plane_idx].output_height - 1) << 4 |
 			VFE40_BURST_LEN;
 		msm_camera_io_w(val, vfe_dev->vfe_base + wm_base + 0x18);
@@ -819,20 +817,16 @@
 
 static void msm_vfe40_axi_cfg_wm_xbar_reg(
 	struct vfe_device *vfe_dev,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd,
+	struct msm_vfe_axi_stream *stream_info,
 	uint8_t plane_idx)
 {
-	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-			(stream_cfg_cmd->axi_stream_handle & 0xFF)];
 	struct msm_vfe_axi_plane_cfg *plane_cfg =
-		&stream_cfg_cmd->plane_cfg[plane_idx];
+		&stream_info->plane_cfg[plane_idx];
 	uint8_t wm = stream_info->wm[plane_idx];
 	uint32_t xbar_cfg = 0;
 	uint32_t xbar_reg_cfg = 0;
 
-	switch (stream_cfg_cmd->stream_src) {
+	switch (stream_info->stream_src) {
 	case PIX_ENCODER:
 	case PIX_VIEWFINDER: {
 		if (plane_cfg->output_plane_format != CRCB_PLANE &&
@@ -840,7 +834,7 @@
 			/*SINGLE_STREAM_SEL*/
 			xbar_cfg |= plane_cfg->output_plane_format << 8;
 		} else {
-			switch (stream_cfg_cmd->output_format) {
+			switch (stream_info->output_format) {
 			case V4L2_PIX_FMT_NV12:
 			case V4L2_PIX_FMT_NV16:
 				xbar_cfg |= 0x3 << 4; /*PAIR_STREAM_SWAP_CTRL*/
@@ -848,7 +842,7 @@
 			}
 			xbar_cfg |= 0x1 << 1; /*PAIR_STREAM_EN*/
 		}
-		if (stream_cfg_cmd->stream_src == PIX_VIEWFINDER)
+		if (stream_info->stream_src == PIX_VIEWFINDER)
 			xbar_cfg |= 0x1; /*VIEW_STREAM_EN*/
 		break;
 	}
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 13160ee..e3d036f6 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
@@ -136,23 +136,23 @@
 	}
 
 	for (i = 0; i < stream_info->num_planes; i++) {
-		stream_info->plane_offset[i] =
-			stream_cfg_cmd->plane_cfg[i].plane_addr_offset;
+		stream_info->plane_cfg[i] = stream_cfg_cmd->plane_cfg[i];
 		stream_info->max_width = max(stream_info->max_width,
 			stream_cfg_cmd->plane_cfg[i].output_width);
 	}
 
+	stream_info->output_format = stream_cfg_cmd->output_format;
 	stream_info->stream_src = stream_cfg_cmd->stream_src;
 	stream_info->frame_based = stream_cfg_cmd->frame_base;
 	return 0;
 }
 
 static uint32_t msm_isp_axi_get_plane_size(
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd, int plane_idx)
+	struct msm_vfe_axi_stream *stream_info, int plane_idx)
 {
 	uint32_t size = 0;
-	struct msm_vfe_axi_plane_cfg *plane_cfg = stream_cfg_cmd->plane_cfg;
-	switch (stream_cfg_cmd->output_format) {
+	struct msm_vfe_axi_plane_cfg *plane_cfg = stream_info->plane_cfg;
+	switch (stream_info->output_format) {
 	case V4L2_PIX_FMT_SBGGR8:
 	case V4L2_PIX_FMT_SGBRG8:
 	case V4L2_PIX_FMT_SGRBG8:
@@ -211,21 +211,17 @@
 }
 
 void msm_isp_axi_reserve_wm(struct msm_vfe_axi_shared_data *axi_data,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+	struct msm_vfe_axi_stream *stream_info)
 {
 	int i, j;
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-			HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
-
 	for (i = 0; i < stream_info->num_planes; i++) {
 		for (j = 0; j < axi_data->hw_info->num_wm; j++) {
 			if (!axi_data->free_wm[j]) {
 				axi_data->free_wm[j] =
-					stream_cfg_cmd->axi_stream_handle;
+					stream_info->stream_handle;
 				axi_data->wm_image_size[j] =
 					msm_isp_axi_get_plane_size(
-						stream_cfg_cmd, i);
+						stream_info, i);
 				axi_data->num_used_wm++;
 				break;
 			}
@@ -246,20 +242,17 @@
 
 void msm_isp_axi_reserve_comp_mask(
 	struct msm_vfe_axi_shared_data *axi_data,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd)
+	struct msm_vfe_axi_stream *stream_info)
 {
 	int i;
 	uint8_t comp_mask = 0;
-	struct msm_vfe_axi_stream *stream_info =
-		&axi_data->stream_info[
-			HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
 	for (i = 0; i < stream_info->num_planes; i++)
 		comp_mask |= 1 << stream_info->wm[i];
 
 	for (i = 0; i < axi_data->hw_info->num_comp_mask; i++) {
 		if (!axi_data->composite_info[i].stream_handle) {
 			axi_data->composite_info[i].stream_handle =
-			stream_cfg_cmd->axi_stream_handle;
+				stream_info->stream_handle;
 			axi_data->composite_info[i].
 				stream_composite_mask = comp_mask;
 			axi_data->num_used_composite_mask++;
@@ -384,7 +377,7 @@
 		break;
 	}
 
-	sof_event.frame_id = vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id;
+	sof_event.frame_id = vfe_dev->axi_data.src_info[frame_src].frame_id;
 	sof_event.timestamp = ts->event_time;
 	msm_isp_send_event(vfe_dev, ISP_EVENT_SOF, &sof_event);
 }
@@ -471,18 +464,18 @@
 
 	stream_info = &vfe_dev->axi_data.
 		stream_info[HANDLE_TO_IDX(stream_cfg_cmd->axi_stream_handle)];
-	msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_cfg_cmd);
+	msm_isp_axi_reserve_wm(&vfe_dev->axi_data, stream_info);
 
 	if (stream_cfg_cmd->stream_src == CAMIF_RAW ||
 		stream_cfg_cmd->stream_src == IDEAL_RAW)
 			vfe_dev->hw_info->vfe_ops.axi_ops.
-				cfg_io_format(vfe_dev, stream_cfg_cmd);
+				cfg_io_format(vfe_dev, stream_info);
 
 	msm_isp_calculate_framedrop(&vfe_dev->axi_data, stream_cfg_cmd);
 
 	if (stream_info->num_planes > 1) {
 		msm_isp_axi_reserve_comp_mask(
-			&vfe_dev->axi_data, stream_cfg_cmd);
+			&vfe_dev->axi_data, stream_info);
 		vfe_dev->hw_info->vfe_ops.axi_ops.
 		cfg_comp_mask(vfe_dev, stream_info);
 	} else {
@@ -492,10 +485,10 @@
 
 	for (i = 0; i < stream_info->num_planes; i++) {
 		vfe_dev->hw_info->vfe_ops.axi_ops.
-			cfg_wm_reg(vfe_dev, stream_cfg_cmd, i);
+			cfg_wm_reg(vfe_dev, stream_info, i);
 
 		vfe_dev->hw_info->vfe_ops.axi_ops.
-			cfg_wm_xbar_reg(vfe_dev, stream_cfg_cmd, i);
+			cfg_wm_xbar_reg(vfe_dev, stream_info, i);
 	}
 	return rc;
 }
@@ -610,7 +603,7 @@
 		vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
 			vfe_dev, stream_info->wm[i],
 			VFE_PONG_FLAG, buf->mapped_info[i].paddr +
-			stream_info->plane_offset[i]);
+			stream_info->plane_cfg[i].plane_addr_offset);
 	stream_info->buf[1] = buf;
 }
 
@@ -657,7 +650,7 @@
 		vfe_dev->hw_info->vfe_ops.axi_ops.update_ping_pong_addr(
 			vfe_dev, stream_info->wm[i],
 			pingpong_status, buf->mapped_info[i].paddr +
-			stream_info->plane_offset[i]);
+			stream_info->plane_cfg[i].plane_addr_offset);
 
 	pingpong_bit = (~(pingpong_status >> stream_info->wm[0]) & 0x1);
 	stream_info->buf[pingpong_bit] = buf;
@@ -852,7 +845,7 @@
 	spin_unlock_irqrestore(&vfe_dev->shared_data_lock, flags);
 	rc = wait_for_completion_interruptible_timeout(
 		&vfe_dev->stream_config_complete,
-		msecs_to_jiffies(500));
+		msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
 	if (rc == 0) {
 		pr_err("%s: wait timeout\n", __func__);
 		rc = -1;
@@ -976,18 +969,33 @@
 			enum msm_isp_camif_update_state camif_update)
 {
 	int i, rc = 0;
+	uint8_t wait_for_complete = 0;
 	struct msm_vfe_axi_stream *stream_info;
 	struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
 	for (i = 0; i < stream_cfg_cmd->num_streams; i++) {
 		stream_info = &axi_data->stream_info[
 			HANDLE_TO_IDX(stream_cfg_cmd->stream_handle[i])];
+
 		stream_info->state = STOP_PENDING;
+		if (stream_info->stream_type == BURST_STREAM &&
+			stream_info->runtime_num_burst_capture == 0) {
+			/*Configure AXI writemasters to stop immediately
+			 *since for burst case, write masters already skip
+			 *all frames.
+			 */
+			msm_isp_axi_stream_enable_cfg(vfe_dev, stream_info);
+			stream_info->state = INACTIVE;
+		} else {
+			wait_for_complete = 1;
+		}
 	}
 
-	rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
-	if (rc < 0) {
-		pr_err("%s: wait for config done failed\n", __func__);
-		return rc;
+	if (wait_for_complete) {
+		rc = msm_isp_axi_wait_for_cfg_done(vfe_dev, camif_update);
+		if (rc < 0) {
+			pr_err("%s: wait for config done failed\n", __func__);
+			return rc;
+		}
 	}
 	msm_isp_update_stream_bandwidth(vfe_dev);
 	if (camif_update == DISABLE_CAMIF)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index f592a60..3d775f9 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -27,15 +27,11 @@
 
 void msm_isp_axi_reserve_wm(
 	struct msm_vfe_axi_shared_data *axi_data,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
-
-void msm_isp_axi_reserve_rdi(
-	struct msm_vfe_axi_shared_data *axi_data,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+	struct msm_vfe_axi_stream *stream_info);
 
 void msm_isp_axi_reserve_comp_mask(
 	struct msm_vfe_axi_shared_data *axi_data,
-	struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd);
+	struct msm_vfe_axi_stream *stream_info);
 
 int msm_isp_axi_check_stream_state(
 	struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index ce71235..d857a14 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -343,7 +343,7 @@
 	atomic_set(&vfe_dev->stats_data.stats_update, 2);
 	rc = wait_for_completion_interruptible_timeout(
 		&vfe_dev->stats_config_complete,
-		msecs_to_jiffies(500));
+		msecs_to_jiffies(VFE_MAX_CFG_TIMEOUT));
 	if (rc == 0) {
 		pr_err("%s: wait timeout\n", __func__);
 		rc = -1;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/Makefile b/drivers/media/platform/msm/camera_v2/pproc/Makefile
index 854e4e7..4193adc 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/Makefile
+++ b/drivers/media/platform/msm/camera_v2/pproc/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_MSMB_CAMERA) += cpp/
+obj-$(CONFIG_MSMB_CAMERA) += vpe/
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile b/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile
new file mode 100644
index 0000000..65a7e34
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+obj-$(CONFIG_MSMB_CAMERA) += msm_vpe.o
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
new file mode 100644
index 0000000..d53d766
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -0,0 +1,1643 @@
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "MSM-VPE %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/msm_ion.h>
+#include <linux/iommu.h>
+#include <mach/iommu_domains.h>
+#include <mach/iommu.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/media-entity.h>
+#include <media/msmb_pproc.h>
+#include <media/msmb_generic_buf_mgr.h>
+#include "msm_vpe.h"
+#include "msm_camera_io_util.h"
+
+#define MSM_VPE_IDENT_TO_SESSION_ID(identity) ((identity >> 16) & 0xFFFF)
+#define MSM_VPE_IDENT_TO_STREAM_ID(identity) (identity & 0xFFFF)
+
+#define MSM_VPE_DRV_NAME "msm_vpe"
+
+#define MSM_VPE_MAX_BUFF_QUEUE 16
+
+#define CONFIG_MSM_VPE_DBG 0
+
+#if CONFIG_MSM_VPE_DBG
+#define VPE_DBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define VPE_DBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+static void vpe_mem_dump(const char * const name, const void * const addr,
+			int size)
+{
+	char line_str[128], *p_str;
+	int i;
+	u32 *p = (u32 *) addr;
+	u32 data;
+	VPE_DBG("%s: (%s) %p %d\n", __func__, name, addr, size);
+	line_str[0] = '\0';
+	p_str = line_str;
+	for (i = 0; i < size/4; i++) {
+		if (i % 4 == 0) {
+			snprintf(p_str, 12, "%08x: ", (u32) p);
+			p_str += 10;
+		}
+		data = *p++;
+		snprintf(p_str, 12, "%08x ", data);
+		p_str += 9;
+		if ((i + 1) % 4 == 0) {
+			VPE_DBG("%s\n", line_str);
+			line_str[0] = '\0';
+			p_str = line_str;
+		}
+	}
+	if (line_str[0] != '\0')
+		VPE_DBG("%s\n", line_str);
+}
+
+static inline long long vpe_do_div(long long num, long long den)
+{
+	do_div(num, den);
+	return num;
+}
+
+#define msm_dequeue(queue, member) ({					\
+			unsigned long flags;				\
+			struct msm_device_queue *__q = (queue);		\
+			struct msm_queue_cmd *qcmd = 0;			\
+			spin_lock_irqsave(&__q->lock, flags);		\
+			if (!list_empty(&__q->list)) {			\
+				__q->len--;				\
+				qcmd = list_first_entry(&__q->list,	\
+							struct msm_queue_cmd, \
+							member);	\
+				list_del_init(&qcmd->member);		\
+			}						\
+			spin_unlock_irqrestore(&__q->lock, flags);	\
+			qcmd;						\
+		})
+
+static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+{
+	spin_lock_init(&queue->lock);
+	queue->len = 0;
+	queue->max = 0;
+	queue->name = name;
+	INIT_LIST_HEAD(&queue->list);
+	init_waitqueue_head(&queue->wait);
+}
+
+static struct msm_cam_clk_info vpe_clk_info[] = {
+	{"vpe_clk", 160000000},
+	{"vpe_pclk", -1},
+};
+
+static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev);
+
+static void msm_enqueue(struct msm_device_queue *queue,
+			struct list_head *entry)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&queue->lock, flags);
+	queue->len++;
+	if (queue->len > queue->max) {
+		queue->max = queue->len;
+		pr_debug("queue %s new max is %d\n", queue->name, queue->max);
+	}
+	list_add_tail(entry, &queue->list);
+	wake_up(&queue->wait);
+	VPE_DBG("woke up %s\n", queue->name);
+	spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static struct msm_vpe_buff_queue_info_t *msm_vpe_get_buff_queue_entry(
+	struct vpe_device *vpe_dev, uint32_t session_id, uint32_t stream_id)
+{
+	uint32_t i = 0;
+	struct msm_vpe_buff_queue_info_t *buff_queue_info = NULL;
+
+	for (i = 0; i < vpe_dev->num_buffq; i++) {
+		if ((vpe_dev->buff_queue[i].used == 1) &&
+			(vpe_dev->buff_queue[i].session_id == session_id) &&
+			(vpe_dev->buff_queue[i].stream_id == stream_id)) {
+			buff_queue_info = &vpe_dev->buff_queue[i];
+			break;
+		}
+	}
+
+	if (buff_queue_info == NULL) {
+		pr_err("error buffer queue entry for sess:%d strm:%d not found\n",
+			session_id, stream_id);
+	}
+	return buff_queue_info;
+}
+
+static unsigned long msm_vpe_get_phy_addr(struct vpe_device *vpe_dev,
+	struct msm_vpe_buff_queue_info_t *buff_queue_info, uint32_t buff_index,
+	uint8_t native_buff)
+{
+	unsigned long phy_add = 0;
+	struct list_head *buff_head;
+	struct msm_vpe_buffer_map_list_t *buff, *save;
+
+	if (native_buff)
+		buff_head = &buff_queue_info->native_buff_head;
+	else
+		buff_head = &buff_queue_info->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buff_index) {
+			phy_add = buff->map_info.phy_addr;
+			break;
+		}
+	}
+
+	return phy_add;
+}
+
+static unsigned long msm_vpe_queue_buffer_info(struct vpe_device *vpe_dev,
+	struct msm_vpe_buff_queue_info_t *buff_queue,
+	struct msm_vpe_buffer_info_t *buffer_info)
+{
+	struct list_head *buff_head;
+	struct msm_vpe_buffer_map_list_t *buff, *save;
+	int rc = 0;
+
+	if (buffer_info->native_buff)
+		buff_head = &buff_queue->native_buff_head;
+	else
+		buff_head = &buff_queue->vb2_buff_head;
+
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		if (buff->map_info.buff_info.index == buffer_info->index) {
+			pr_err("error buffer index already queued\n");
+			return -EINVAL;
+		}
+	}
+
+	buff = kzalloc(
+		sizeof(struct msm_vpe_buffer_map_list_t), GFP_KERNEL);
+	if (!buff) {
+		pr_err("error allocating memory\n");
+		return -EINVAL;
+	}
+
+	buff->map_info.buff_info = *buffer_info;
+	buff->map_info.ion_handle = ion_import_dma_buf(vpe_dev->client,
+		buffer_info->fd);
+	if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) {
+		pr_err("ION import failed\n");
+		goto queue_buff_error1;
+	}
+
+	rc = ion_map_iommu(vpe_dev->client, buff->map_info.ion_handle,
+		vpe_dev->domain_num, 0, SZ_4K, 0,
+		(unsigned long *)&buff->map_info.phy_addr,
+		&buff->map_info.len, 0, 0);
+	if (rc < 0) {
+		pr_err("ION mmap failed\n");
+		goto queue_buff_error2;
+	}
+
+	INIT_LIST_HEAD(&buff->entry);
+	list_add_tail(&buff->entry, buff_head);
+
+	return buff->map_info.phy_addr;
+
+queue_buff_error2:
+	ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle,
+		vpe_dev->domain_num, 0);
+queue_buff_error1:
+	ion_free(vpe_dev->client, buff->map_info.ion_handle);
+	buff->map_info.ion_handle = NULL;
+	kzfree(buff);
+
+	return 0;
+}
+
+static void msm_vpe_dequeue_buffer_info(struct vpe_device *vpe_dev,
+	struct msm_vpe_buffer_map_list_t *buff)
+{
+	ion_unmap_iommu(vpe_dev->client, buff->map_info.ion_handle,
+		vpe_dev->domain_num, 0);
+	ion_free(vpe_dev->client, buff->map_info.ion_handle);
+	buff->map_info.ion_handle = NULL;
+
+	list_del_init(&buff->entry);
+	kzfree(buff);
+
+	return;
+}
+
+static unsigned long msm_vpe_fetch_buffer_info(struct vpe_device *vpe_dev,
+	struct msm_vpe_buffer_info_t *buffer_info, uint32_t session_id,
+	uint32_t stream_id)
+{
+	unsigned long phy_addr = 0;
+	struct msm_vpe_buff_queue_info_t *buff_queue_info;
+	uint8_t native_buff = buffer_info->native_buff;
+
+	buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id,
+		stream_id);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			session_id, stream_id);
+		return phy_addr;
+	}
+
+	phy_addr = msm_vpe_get_phy_addr(vpe_dev, buff_queue_info,
+		buffer_info->index, native_buff);
+	if ((phy_addr == 0) && (native_buff)) {
+		phy_addr = msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info,
+			buffer_info);
+	}
+	return phy_addr;
+}
+
+static int32_t msm_vpe_enqueue_buff_info_list(struct vpe_device *vpe_dev,
+	struct msm_vpe_stream_buff_info_t *stream_buff_info)
+{
+	uint32_t j;
+	struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+	buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev,
+			(stream_buff_info->identity >> 16) & 0xFFFF,
+			stream_buff_info->identity & 0xFFFF);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			(stream_buff_info->identity >> 16) & 0xFFFF,
+			stream_buff_info->identity & 0xFFFF);
+		return -EINVAL;
+	}
+
+	for (j = 0; j < stream_buff_info->num_buffs; j++) {
+		msm_vpe_queue_buffer_info(vpe_dev, buff_queue_info,
+		&stream_buff_info->buffer_info[j]);
+	}
+	return 0;
+}
+
+static int32_t msm_vpe_dequeue_buff_info_list(struct vpe_device *vpe_dev,
+	struct msm_vpe_buff_queue_info_t *buff_queue_info)
+{
+	struct msm_vpe_buffer_map_list_t *buff, *save;
+	struct list_head *buff_head;
+
+	buff_head = &buff_queue_info->native_buff_head;
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		msm_vpe_dequeue_buffer_info(vpe_dev, buff);
+	}
+
+	buff_head = &buff_queue_info->vb2_buff_head;
+	list_for_each_entry_safe(buff, save, buff_head, entry) {
+		msm_vpe_dequeue_buffer_info(vpe_dev, buff);
+	}
+
+	return 0;
+}
+
+static int32_t msm_vpe_add_buff_queue_entry(struct vpe_device *vpe_dev,
+	uint16_t session_id, uint16_t stream_id)
+{
+	uint32_t i;
+	struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+	for (i = 0; i < vpe_dev->num_buffq; i++) {
+		if (vpe_dev->buff_queue[i].used == 0) {
+			buff_queue_info = &vpe_dev->buff_queue[i];
+			buff_queue_info->used = 1;
+			buff_queue_info->session_id = session_id;
+			buff_queue_info->stream_id = stream_id;
+			INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+			INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+			return 0;
+		}
+	}
+	pr_err("buffer queue full. error for sessionid: %d streamid: %d\n",
+		session_id, stream_id);
+	return -EINVAL;
+}
+
+static int32_t msm_vpe_free_buff_queue_entry(struct vpe_device *vpe_dev,
+					uint32_t session_id, uint32_t stream_id)
+{
+	struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+	buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev, session_id,
+		stream_id);
+	if (buff_queue_info == NULL) {
+		pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n",
+			session_id, stream_id);
+		return -EINVAL;
+	}
+
+	buff_queue_info->used = 0;
+	buff_queue_info->session_id = 0;
+	buff_queue_info->stream_id = 0;
+	INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
+	INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
+	return 0;
+}
+
+static int32_t msm_vpe_create_buff_queue(struct vpe_device *vpe_dev,
+					uint32_t num_buffq)
+{
+	struct msm_vpe_buff_queue_info_t *buff_queue;
+	buff_queue = kzalloc(
+		sizeof(struct msm_vpe_buff_queue_info_t) * num_buffq,
+		GFP_KERNEL);
+	if (!buff_queue) {
+		pr_err("Buff queue allocation failure\n");
+		return -ENOMEM;
+	}
+
+	if (vpe_dev->buff_queue) {
+		pr_err("Buff queue not empty\n");
+		kzfree(buff_queue);
+		return -EINVAL;
+	} else {
+		vpe_dev->buff_queue = buff_queue;
+		vpe_dev->num_buffq = num_buffq;
+	}
+	return 0;
+}
+
+static void msm_vpe_delete_buff_queue(struct vpe_device *vpe_dev)
+{
+	uint32_t i;
+
+	for (i = 0; i < vpe_dev->num_buffq; i++) {
+		if (vpe_dev->buff_queue[i].used == 1) {
+			pr_err("Queue not free sessionid: %d, streamid: %d\n",
+				vpe_dev->buff_queue[i].session_id,
+				vpe_dev->buff_queue[i].stream_id);
+			msm_vpe_free_buff_queue_entry(vpe_dev,
+				vpe_dev->buff_queue[i].session_id,
+				vpe_dev->buff_queue[i].stream_id);
+		}
+	}
+	kzfree(vpe_dev->buff_queue);
+	vpe_dev->buff_queue = NULL;
+	vpe_dev->num_buffq = 0;
+	return;
+}
+
+void vpe_release_ion_client(struct kref *ref)
+{
+	struct vpe_device *vpe_dev = container_of(ref,
+		struct vpe_device, refcount);
+	ion_client_destroy(vpe_dev->client);
+}
+
+static int vpe_init_mem(struct vpe_device *vpe_dev)
+{
+	kref_init(&vpe_dev->refcount);
+	kref_get(&vpe_dev->refcount);
+	vpe_dev->client = msm_ion_client_create(-1, "vpe");
+
+	if (!vpe_dev->client) {
+		pr_err("couldn't create ion client\n");
+		return  -ENODEV;
+	}
+
+	return 0;
+}
+
+static void vpe_deinit_mem(struct vpe_device *vpe_dev)
+{
+	kref_put(&vpe_dev->refcount, vpe_release_ion_client);
+}
+
+static irqreturn_t msm_vpe_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	uint32_t irq_status;
+	struct msm_vpe_tasklet_queue_cmd *queue_cmd;
+	struct vpe_device *vpe_dev = (struct vpe_device *) data;
+
+	irq_status = msm_camera_io_r_mb(vpe_dev->base +
+					VPE_INTR_STATUS_OFFSET);
+
+	spin_lock_irqsave(&vpe_dev->tasklet_lock, flags);
+	queue_cmd = &vpe_dev->tasklet_queue_cmd[vpe_dev->taskletq_idx];
+	if (queue_cmd->cmd_used) {
+		VPE_DBG("%s: vpe tasklet queue overflow\n", __func__);
+		list_del(&queue_cmd->list);
+	} else {
+		atomic_add(1, &vpe_dev->irq_cnt);
+	}
+	queue_cmd->irq_status = irq_status;
+
+	queue_cmd->cmd_used = 1;
+	vpe_dev->taskletq_idx =
+		(vpe_dev->taskletq_idx + 1) % MSM_VPE_TASKLETQ_SIZE;
+	list_add_tail(&queue_cmd->list, &vpe_dev->tasklet_q);
+	spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+
+	tasklet_schedule(&vpe_dev->vpe_tasklet);
+
+	msm_camera_io_w_mb(irq_status, vpe_dev->base + VPE_INTR_CLEAR_OFFSET);
+	msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+	VPE_DBG("%s: irq_status=0x%x.\n", __func__, irq_status);
+
+	return IRQ_HANDLED;
+}
+
+static void msm_vpe_do_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	struct vpe_device *vpe_dev = (struct vpe_device *)data;
+	struct msm_vpe_tasklet_queue_cmd *queue_cmd;
+
+	while (atomic_read(&vpe_dev->irq_cnt)) {
+		spin_lock_irqsave(&vpe_dev->tasklet_lock, flags);
+		queue_cmd = list_first_entry(&vpe_dev->tasklet_q,
+					struct msm_vpe_tasklet_queue_cmd, list);
+		if (!queue_cmd) {
+			atomic_set(&vpe_dev->irq_cnt, 0);
+			spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+			return;
+		}
+		atomic_sub(1, &vpe_dev->irq_cnt);
+		list_del(&queue_cmd->list);
+		queue_cmd->cmd_used = 0;
+
+		spin_unlock_irqrestore(&vpe_dev->tasklet_lock, flags);
+
+		VPE_DBG("Frame done!!\n");
+		msm_vpe_notify_frame_done(vpe_dev);
+	}
+}
+
+static int vpe_init_hardware(struct vpe_device *vpe_dev)
+{
+	int rc = 0;
+
+	if (vpe_dev->fs_vpe == NULL) {
+		vpe_dev->fs_vpe =
+			regulator_get(&vpe_dev->pdev->dev, "vdd");
+		if (IS_ERR(vpe_dev->fs_vpe)) {
+			pr_err("Regulator vpe vdd get failed %ld\n",
+				PTR_ERR(vpe_dev->fs_vpe));
+			vpe_dev->fs_vpe = NULL;
+			rc = -ENODEV;
+			goto fail;
+		} else if (regulator_enable(vpe_dev->fs_vpe)) {
+			pr_err("Regulator vpe vdd enable failed\n");
+			regulator_put(vpe_dev->fs_vpe);
+			vpe_dev->fs_vpe = NULL;
+			rc = -ENODEV;
+			goto fail;
+		}
+	}
+
+	rc = msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info,
+				vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 1);
+	if (rc < 0) {
+		rc = -ENODEV;
+		pr_err("clk enable failed\n");
+		goto disable_and_put_regulator;
+	}
+
+	vpe_dev->base = ioremap(vpe_dev->mem->start,
+		resource_size(vpe_dev->mem));
+	if (!vpe_dev->base) {
+		rc = -ENOMEM;
+		pr_err("ioremap failed\n");
+		goto disable_and_put_regulator;
+	}
+
+	if (vpe_dev->state != VPE_STATE_BOOT) {
+		rc = request_irq(vpe_dev->irq->start, msm_vpe_irq,
+				IRQF_TRIGGER_RISING,
+				"vpe", vpe_dev);
+		if (rc < 0) {
+			pr_err("irq request fail! start=%u\n",
+				vpe_dev->irq->start);
+			rc = -EBUSY;
+			goto unmap_base;
+		} else {
+			VPE_DBG("Got irq! %d\n", vpe_dev->irq->start);
+		}
+	} else {
+		VPE_DBG("Skip requesting the irq since device is booting\n");
+	}
+	vpe_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev();
+
+	msm_vpe_create_buff_queue(vpe_dev, MSM_VPE_MAX_BUFF_QUEUE);
+	return rc;
+
+unmap_base:
+	iounmap(vpe_dev->base);
+disable_and_put_regulator:
+	regulator_disable(vpe_dev->fs_vpe);
+	regulator_put(vpe_dev->fs_vpe);
+fail:
+	return rc;
+}
+
+static int vpe_release_hardware(struct vpe_device *vpe_dev)
+{
+	if (vpe_dev->state != VPE_STATE_BOOT) {
+		free_irq(vpe_dev->irq->start, vpe_dev);
+		tasklet_kill(&vpe_dev->vpe_tasklet);
+		atomic_set(&vpe_dev->irq_cnt, 0);
+	}
+
+	msm_vpe_delete_buff_queue(vpe_dev);
+	iounmap(vpe_dev->base);
+	msm_cam_clk_enable(&vpe_dev->pdev->dev, vpe_clk_info,
+			vpe_dev->vpe_clk, ARRAY_SIZE(vpe_clk_info), 0);
+	return 0;
+}
+
+static int vpe_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	int rc = 0;
+	uint32_t i;
+	struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+
+	mutex_lock(&vpe_dev->mutex);
+	if (vpe_dev->vpe_open_cnt == MAX_ACTIVE_VPE_INSTANCE) {
+		pr_err("No free VPE instance\n");
+		rc = -ENODEV;
+		goto err_mutex_unlock;
+	}
+
+	for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+		if (vpe_dev->vpe_subscribe_list[i].active == 0) {
+			vpe_dev->vpe_subscribe_list[i].active = 1;
+			vpe_dev->vpe_subscribe_list[i].vfh = &fh->vfh;
+			break;
+		}
+	}
+	if (i == MAX_ACTIVE_VPE_INSTANCE) {
+		pr_err("No free instance\n");
+		rc = -ENODEV;
+		goto err_mutex_unlock;
+	}
+
+	VPE_DBG("open %d %p\n", i, &fh->vfh);
+	vpe_dev->vpe_open_cnt++;
+	if (vpe_dev->vpe_open_cnt == 1) {
+		rc = vpe_init_hardware(vpe_dev);
+		if (rc < 0) {
+			pr_err("%s: Couldn't init vpe hardware\n", __func__);
+			vpe_dev->vpe_open_cnt--;
+			rc = -ENODEV;
+			goto err_fixup_sub_list;
+		}
+		rc = vpe_init_mem(vpe_dev);
+		if (rc < 0) {
+			pr_err("%s: Couldn't init mem\n", __func__);
+			vpe_dev->vpe_open_cnt--;
+			rc = -ENODEV;
+			goto err_release_hardware;
+		}
+		vpe_dev->state = VPE_STATE_IDLE;
+	}
+	mutex_unlock(&vpe_dev->mutex);
+
+	return rc;
+
+err_release_hardware:
+	vpe_release_hardware(vpe_dev);
+err_fixup_sub_list:
+	for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+		if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) {
+			vpe_dev->vpe_subscribe_list[i].active = 0;
+			vpe_dev->vpe_subscribe_list[i].vfh = NULL;
+			break;
+		}
+	}
+err_mutex_unlock:
+	mutex_unlock(&vpe_dev->mutex);
+	return rc;
+}
+
+static int vpe_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	uint32_t i;
+	struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+	mutex_lock(&vpe_dev->mutex);
+	for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+		if (vpe_dev->vpe_subscribe_list[i].vfh == &fh->vfh) {
+			vpe_dev->vpe_subscribe_list[i].active = 0;
+			vpe_dev->vpe_subscribe_list[i].vfh = NULL;
+			break;
+		}
+	}
+	if (i == MAX_ACTIVE_VPE_INSTANCE) {
+		pr_err("Invalid close\n");
+		mutex_unlock(&vpe_dev->mutex);
+		return -ENODEV;
+	}
+
+	VPE_DBG("close %d %p\n", i, &fh->vfh);
+	vpe_dev->vpe_open_cnt--;
+	if (vpe_dev->vpe_open_cnt == 0) {
+		vpe_deinit_mem(vpe_dev);
+		vpe_release_hardware(vpe_dev);
+		vpe_dev->state = VPE_STATE_OFF;
+	}
+	mutex_unlock(&vpe_dev->mutex);
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = {
+	.open = vpe_open_node,
+	.close = vpe_close_node,
+};
+
+static int msm_vpe_buffer_ops(struct vpe_device *vpe_dev,
+	uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info)
+{
+	int rc = -EINVAL;
+
+	rc = v4l2_subdev_call(vpe_dev->buf_mgr_subdev, core, ioctl,
+		buff_mgr_ops, buff_mgr_info);
+	if (rc < 0)
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+	return rc;
+}
+
+static int msm_vpe_notify_frame_done(struct vpe_device *vpe_dev)
+{
+	struct v4l2_event v4l2_evt;
+	struct msm_queue_cmd *frame_qcmd;
+	struct msm_queue_cmd *event_qcmd;
+	struct msm_vpe_frame_info_t *processed_frame;
+	struct msm_device_queue *queue = &vpe_dev->processing_q;
+	struct msm_buf_mngr_info buff_mgr_info;
+	int rc = 0;
+
+	if (queue->len > 0) {
+		frame_qcmd = msm_dequeue(queue, list_frame);
+		processed_frame = frame_qcmd->command;
+		do_gettimeofday(&(processed_frame->out_time));
+		kfree(frame_qcmd);
+		event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+		if (!event_qcmd) {
+			pr_err("%s: Insufficient memory\n", __func__);
+			return -ENOMEM;
+		}
+		atomic_set(&event_qcmd->on_heap, 1);
+		event_qcmd->command = processed_frame;
+		VPE_DBG("fid %d\n", processed_frame->frame_id);
+		msm_enqueue(&vpe_dev->eventData_q, &event_qcmd->list_eventdata);
+
+		if (!processed_frame->output_buffer_info.processed_divert) {
+			memset(&buff_mgr_info, 0 ,
+				sizeof(buff_mgr_info));
+			buff_mgr_info.session_id =
+				((processed_frame->identity >> 16) & 0xFFFF);
+			buff_mgr_info.stream_id =
+				(processed_frame->identity & 0xFFFF);
+			buff_mgr_info.frame_id = processed_frame->frame_id;
+			buff_mgr_info.timestamp = processed_frame->timestamp;
+			buff_mgr_info.index =
+				processed_frame->output_buffer_info.index;
+			rc = msm_vpe_buffer_ops(vpe_dev,
+						VIDIOC_MSM_BUF_MNGR_BUF_DONE,
+						&buff_mgr_info);
+			if (rc < 0) {
+				pr_err("%s: error doing VIDIOC_MSM_BUF_MNGR_BUF_DONE\n",
+					__func__);
+				rc = -EINVAL;
+			}
+		}
+
+		v4l2_evt.id = processed_frame->inst_id;
+		v4l2_evt.type = V4L2_EVENT_VPE_FRAME_DONE;
+		v4l2_event_queue(vpe_dev->msm_sd.sd.devnode, &v4l2_evt);
+	}
+	return rc;
+}
+
+static void vpe_update_scaler_params(struct vpe_device *vpe_dev,
+			struct msm_vpe_frame_strip_info strip_info)
+{
+	uint32_t out_ROI_width, out_ROI_height;
+	uint32_t src_ROI_width, src_ROI_height;
+
+	/*
+	* phase_step_x, phase_step_y, phase_init_x and phase_init_y
+	* are represented in fixed-point, unsigned 3.29 format
+	*/
+	uint32_t phase_step_x = 0;
+	uint32_t phase_step_y = 0;
+	uint32_t phase_init_x = 0;
+	uint32_t phase_init_y = 0;
+
+	uint32_t src_roi, src_x, src_y, src_xy, temp;
+	uint32_t yscale_filter_sel, xscale_filter_sel;
+	uint32_t scale_unit_sel_x, scale_unit_sel_y;
+	uint64_t numerator, denominator;
+
+	/*
+	 * assumption is both direction need zoom. this can be
+	 * improved.
+	 */
+	temp = msm_camera_io_r(vpe_dev->base + VPE_OP_MODE_OFFSET) | 0x3;
+	msm_camera_io_w(temp, vpe_dev->base + VPE_OP_MODE_OFFSET);
+
+	src_ROI_width  = strip_info.src_w;
+	src_ROI_height = strip_info.src_h;
+	out_ROI_width  = strip_info.dst_w;
+	out_ROI_height = strip_info.dst_h;
+
+	VPE_DBG("src w = %u, h=%u, dst w = %u, h =%u.\n",
+		src_ROI_width, src_ROI_height, out_ROI_width,
+		out_ROI_height);
+	src_roi = (src_ROI_height << 16) + src_ROI_width;
+
+	msm_camera_io_w(src_roi, vpe_dev->base + VPE_SRC_SIZE_OFFSET);
+
+	src_x = strip_info.src_x;
+	src_y = strip_info.src_y;
+
+	VPE_DBG("src_x = %d, src_y=%d.\n", src_x, src_y);
+
+	src_xy = src_y*(1<<16) + src_x;
+	msm_camera_io_w(src_xy, vpe_dev->base +
+			VPE_SRC_XY_OFFSET);
+	VPE_DBG("src_xy = 0x%x, src_roi=0x%x.\n", src_xy, src_roi);
+
+	/* decide whether to use FIR or M/N for scaling */
+	if ((out_ROI_width == 1 && src_ROI_width < 4) ||
+		(src_ROI_width < 4 * out_ROI_width - 3))
+		scale_unit_sel_x = 0;/* use FIR scalar */
+	else
+		scale_unit_sel_x = 1;/* use M/N scalar */
+
+	if ((out_ROI_height == 1 && src_ROI_height < 4) ||
+		(src_ROI_height < 4 * out_ROI_height - 3))
+		scale_unit_sel_y = 0;/* use FIR scalar */
+	else
+		scale_unit_sel_y = 1;/* use M/N scalar */
+
+	/* calculate phase step for the x direction */
+
+	/*
+	 * if destination is only 1 pixel wide, the value of
+	 * phase_step_x is unimportant. Assigning phase_step_x to src
+	 * ROI width as an arbitrary value.
+	 */
+	if (out_ROI_width == 1)
+		phase_step_x = (uint32_t) ((src_ROI_width) <<
+						SCALER_PHASE_BITS);
+
+		/* if using FIR scalar */
+	else if (scale_unit_sel_x == 0) {
+
+		/*
+		 * Calculate the quotient ( src_ROI_width - 1 ) (
+		 * out_ROI_width - 1) with u3.29 precision. Quotient
+		 * is rounded up to the larger 29th decimal point
+		 */
+		numerator = (uint64_t)(src_ROI_width - 1) <<
+			SCALER_PHASE_BITS;
+		/*
+		 * never equals to 0 because of the "(out_ROI_width ==
+		 * 1 )"
+		 */
+		denominator = (uint64_t)(out_ROI_width - 1);
+		/*
+		 * divide and round up to the larger 29th decimal
+		 * point.
+		 */
+		phase_step_x = (uint32_t) vpe_do_div((numerator +
+					denominator - 1), denominator);
+	} else if (scale_unit_sel_x == 1) { /* if M/N scalar */
+		/*
+		 * Calculate the quotient ( src_ROI_width ) / (
+		 * out_ROI_width) with u3.29 precision. Quotient is
+		 * rounded down to the smaller 29th decimal point.
+		 */
+		numerator = (uint64_t)(src_ROI_width) <<
+			SCALER_PHASE_BITS;
+		denominator = (uint64_t)(out_ROI_width);
+		phase_step_x =
+			(uint32_t) vpe_do_div(numerator, denominator);
+	}
+	/* calculate phase step for the y direction */
+
+	/*
+	 * if destination is only 1 pixel wide, the value of
+	 * phase_step_x is unimportant. Assigning phase_step_x to src
+	 * ROI width as an arbitrary value.
+	 */
+	if (out_ROI_height == 1)
+		phase_step_y =
+		(uint32_t) ((src_ROI_height) << SCALER_PHASE_BITS);
+
+	/* if FIR scalar */
+	else if (scale_unit_sel_y == 0) {
+		/*
+		 * Calculate the quotient ( src_ROI_height - 1 ) / (
+		 * out_ROI_height - 1) with u3.29 precision. Quotient
+		 * is rounded up to the larger 29th decimal point.
+		 */
+		numerator = (uint64_t)(src_ROI_height - 1) <<
+			SCALER_PHASE_BITS;
+		/*
+		 * never equals to 0 because of the " ( out_ROI_height
+		 * == 1 )" case
+		 */
+		denominator = (uint64_t)(out_ROI_height - 1);
+		/*
+		 * Quotient is rounded up to the larger 29th decimal
+		 * point.
+		 */
+		phase_step_y =
+		(uint32_t) vpe_do_div(
+			(numerator + denominator - 1), denominator);
+	} else if (scale_unit_sel_y == 1) { /* if M/N scalar */
+		/*
+		 * Calculate the quotient ( src_ROI_height ) (
+		 * out_ROI_height) with u3.29 precision. Quotient is
+		 * rounded down to the smaller 29th decimal point.
+		 */
+		numerator = (uint64_t)(src_ROI_height) <<
+			SCALER_PHASE_BITS;
+		denominator = (uint64_t)(out_ROI_height);
+		phase_step_y = (uint32_t) vpe_do_div(
+			numerator, denominator);
+	}
+
+	/* decide which set of FIR coefficients to use */
+	if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
+		xscale_filter_sel = 0;
+	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
+		xscale_filter_sel = 1;
+	else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
+		xscale_filter_sel = 2;
+	else
+		xscale_filter_sel = 3;
+
+	if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
+		yscale_filter_sel = 0;
+	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
+		yscale_filter_sel = 1;
+	else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
+		yscale_filter_sel = 2;
+	else
+		yscale_filter_sel = 3;
+
+	/* calculate phase init for the x direction */
+
+	/* if using FIR scalar */
+	if (scale_unit_sel_x == 0) {
+		if (out_ROI_width == 1)
+			phase_init_x =
+				(uint32_t) ((src_ROI_width - 1) <<
+							SCALER_PHASE_BITS);
+		else
+			phase_init_x = 0;
+	} else if (scale_unit_sel_x == 1) /* M over N scalar  */
+		phase_init_x = 0;
+
+	/*
+	 * calculate phase init for the y direction if using FIR
+	 * scalar
+	 */
+	if (scale_unit_sel_y == 0) {
+		if (out_ROI_height == 1)
+			phase_init_y =
+			(uint32_t) ((src_ROI_height -
+						1) << SCALER_PHASE_BITS);
+		else
+			phase_init_y = 0;
+	} else if (scale_unit_sel_y == 1) /* M over N scalar   */
+		phase_init_y = 0;
+
+	strip_info.phase_step_x = phase_step_x;
+	strip_info.phase_step_y = phase_step_y;
+	strip_info.phase_init_x = phase_init_x;
+	strip_info.phase_init_y = phase_init_y;
+	VPE_DBG("phase step x = %d, step y = %d.\n",
+		 strip_info.phase_step_x, strip_info.phase_step_y);
+	VPE_DBG("phase init x = %d, init y = %d.\n",
+		 strip_info.phase_init_x, strip_info.phase_init_y);
+
+	msm_camera_io_w(strip_info.phase_step_x, vpe_dev->base +
+			VPE_SCALE_PHASEX_STEP_OFFSET);
+	msm_camera_io_w(strip_info.phase_step_y, vpe_dev->base +
+			VPE_SCALE_PHASEY_STEP_OFFSET);
+
+	msm_camera_io_w(strip_info.phase_init_x, vpe_dev->base +
+			VPE_SCALE_PHASEX_INIT_OFFSET);
+	msm_camera_io_w(strip_info.phase_init_y, vpe_dev->base +
+			VPE_SCALE_PHASEY_INIT_OFFSET);
+}
+
+static void vpe_program_buffer_addresses(
+	struct vpe_device *vpe_dev,
+	unsigned long srcP0,
+	unsigned long srcP1,
+	unsigned long outP0,
+	unsigned long outP1)
+{
+	VPE_DBG("%s VPE Configured with:\n"
+		"Src %x, %x Dest %x, %x",
+		__func__, (uint32_t)srcP0, (uint32_t)srcP1,
+		(uint32_t)outP0, (uint32_t)outP1);
+
+	msm_camera_io_w(srcP0, vpe_dev->base + VPE_SRCP0_ADDR_OFFSET);
+	msm_camera_io_w(srcP1, vpe_dev->base + VPE_SRCP1_ADDR_OFFSET);
+	msm_camera_io_w(outP0, vpe_dev->base + VPE_OUTP0_ADDR_OFFSET);
+	msm_camera_io_w(outP1, vpe_dev->base + VPE_OUTP1_ADDR_OFFSET);
+}
+
+static int vpe_start(struct vpe_device *vpe_dev)
+{
+	/*  enable the frame irq, bit 0 = Display list 0 ROI done */
+	msm_camera_io_w_mb(1, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+	msm_camera_io_dump(vpe_dev->base, 0x120);
+	msm_camera_io_dump(vpe_dev->base + 0x00400, 0x18);
+	msm_camera_io_dump(vpe_dev->base + 0x10000, 0x250);
+	msm_camera_io_dump(vpe_dev->base + 0x30000, 0x20);
+	msm_camera_io_dump(vpe_dev->base + 0x50000, 0x30);
+	msm_camera_io_dump(vpe_dev->base + 0x50400, 0x10);
+
+	/*
+	 * This triggers the operation. When the VPE is done,
+	 * msm_vpe_irq will fire.
+	 */
+	msm_camera_io_w_mb(1, vpe_dev->base + VPE_DL0_START_OFFSET);
+	return 0;
+}
+
+static void vpe_config_axi_default(struct vpe_device *vpe_dev)
+{
+	msm_camera_io_w(0x25, vpe_dev->base + VPE_AXI_ARB_2_OFFSET);
+}
+
+static int vpe_reset(struct vpe_device *vpe_dev)
+{
+	uint32_t vpe_version;
+	uint32_t rc = 0;
+
+	vpe_version = msm_camera_io_r(
+			vpe_dev->base + VPE_HW_VERSION_OFFSET);
+	VPE_DBG("vpe_version = 0x%x\n", vpe_version);
+	/* disable all interrupts.*/
+	msm_camera_io_w(0, vpe_dev->base + VPE_INTR_ENABLE_OFFSET);
+	/* clear all pending interrupts*/
+	msm_camera_io_w(0x1fffff, vpe_dev->base + VPE_INTR_CLEAR_OFFSET);
+	/* write sw_reset to reset the core. */
+	msm_camera_io_w(0x10, vpe_dev->base + VPE_SW_RESET_OFFSET);
+	/* then poll the reset bit, it should be self-cleared. */
+	while (1) {
+		rc = msm_camera_io_r(vpe_dev->base + VPE_SW_RESET_OFFSET) \
+			& 0x10;
+		if (rc == 0)
+			break;
+		cpu_relax();
+	}
+	/*
+	 * at this point, hardware is reset. Then pogram to default
+	 * values.
+	 */
+	msm_camera_io_w(VPE_AXI_RD_ARB_CONFIG_VALUE,
+			vpe_dev->base + VPE_AXI_RD_ARB_CONFIG_OFFSET);
+
+	msm_camera_io_w(VPE_CGC_ENABLE_VALUE,
+			vpe_dev->base + VPE_CGC_EN_OFFSET);
+	msm_camera_io_w(1, vpe_dev->base + VPE_CMD_MODE_OFFSET);
+	msm_camera_io_w(VPE_DEFAULT_OP_MODE_VALUE,
+			vpe_dev->base + VPE_OP_MODE_OFFSET);
+	msm_camera_io_w(VPE_DEFAULT_SCALE_CONFIG,
+			vpe_dev->base + VPE_SCALE_CONFIG_OFFSET);
+	vpe_config_axi_default(vpe_dev);
+	return rc;
+}
+
+static void vpe_update_scale_coef(struct vpe_device *vpe_dev, uint32_t *p)
+{
+	uint32_t i, offset;
+	offset = *p;
+	for (i = offset; i < (VPE_SCALE_COEFF_NUM + offset); i++) {
+		VPE_DBG("Setting scale table %d\n", i);
+		msm_camera_io_w(*(++p),
+			vpe_dev->base + VPE_SCALE_COEFF_LSBn(i));
+		msm_camera_io_w(*(++p),
+			vpe_dev->base + VPE_SCALE_COEFF_MSBn(i));
+	}
+}
+
+static void vpe_input_plane_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+	msm_camera_io_w(*p, vpe_dev->base + VPE_SRC_FORMAT_OFFSET);
+	msm_camera_io_w(*(++p),
+		vpe_dev->base + VPE_SRC_UNPACK_PATTERN1_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_IMAGE_SIZE_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_YSTRIDE1_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_SIZE_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_SRC_XY_OFFSET);
+}
+
+static void vpe_output_plane_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+	msm_camera_io_w(*p, vpe_dev->base + VPE_OUT_FORMAT_OFFSET);
+	msm_camera_io_w(*(++p),
+		vpe_dev->base + VPE_OUT_PACK_PATTERN1_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_YSTRIDE1_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_SIZE_OFFSET);
+	msm_camera_io_w(*(++p), vpe_dev->base + VPE_OUT_XY_OFFSET);
+}
+
+static void vpe_operation_config(struct vpe_device *vpe_dev, uint32_t *p)
+{
+	msm_camera_io_w(*p, vpe_dev->base + VPE_OP_MODE_OFFSET);
+}
+
+/**
+ * msm_vpe_transaction_setup() - send setup for one frame to VPE
+ * @vpe_dev:	vpe device
+ * @data:	packed setup commands
+ *
+ * See msm_vpe.h for the expected format of `data'
+ */
+static void msm_vpe_transaction_setup(struct vpe_device *vpe_dev, void *data)
+{
+	int i;
+	void *iter = data;
+
+	vpe_mem_dump("vpe_transaction", data, VPE_TRANSACTION_SETUP_CONFIG_LEN);
+
+	for (i = 0; i < VPE_NUM_SCALER_TABLES; ++i) {
+		vpe_update_scale_coef(vpe_dev, (uint32_t *)iter);
+		iter += VPE_SCALER_CONFIG_LEN;
+	}
+	vpe_input_plane_config(vpe_dev, (uint32_t *)iter);
+	iter += VPE_INPUT_PLANE_CFG_LEN;
+	vpe_output_plane_config(vpe_dev, (uint32_t *)iter);
+	iter += VPE_OUTPUT_PLANE_CFG_LEN;
+	vpe_operation_config(vpe_dev, (uint32_t *)iter);
+}
+
+static int msm_vpe_send_frame_to_hardware(struct vpe_device *vpe_dev,
+	struct msm_queue_cmd *frame_qcmd)
+{
+	struct msm_vpe_frame_info_t *process_frame;
+
+	if (vpe_dev->processing_q.len < MAX_VPE_PROCESSING_FRAME) {
+		process_frame = frame_qcmd->command;
+		msm_enqueue(&vpe_dev->processing_q,
+					&frame_qcmd->list_frame);
+
+		vpe_update_scaler_params(vpe_dev, process_frame->strip_info);
+		vpe_program_buffer_addresses(
+			vpe_dev,
+			process_frame->src_phyaddr,
+			process_frame->src_phyaddr
+			+ process_frame->src_chroma_plane_offset,
+			process_frame->dest_phyaddr,
+			process_frame->dest_phyaddr
+			+ process_frame->dest_chroma_plane_offset);
+		vpe_start(vpe_dev);
+		do_gettimeofday(&(process_frame->in_time));
+	}
+	return 0;
+}
+
+static int msm_vpe_cfg(struct vpe_device *vpe_dev,
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+	int rc = 0;
+	struct msm_queue_cmd *frame_qcmd = NULL;
+	struct msm_vpe_frame_info_t *new_frame =
+		kzalloc(sizeof(struct msm_vpe_frame_info_t), GFP_KERNEL);
+	unsigned long in_phyaddr, out_phyaddr;
+	struct msm_buf_mngr_info buff_mgr_info;
+
+	if (!new_frame) {
+		pr_err("Insufficient memory. return\n");
+		return -ENOMEM;
+	}
+
+	rc = copy_from_user(new_frame, (void __user *)ioctl_ptr->ioctl_ptr,
+			sizeof(struct msm_vpe_frame_info_t));
+	if (rc) {
+		pr_err("%s:%d copy from user\n", __func__, __LINE__);
+		rc = -EINVAL;
+		goto err_free_new_frame;
+	}
+
+	in_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev,
+		&new_frame->input_buffer_info,
+		((new_frame->identity >> 16) & 0xFFFF),
+		(new_frame->identity & 0xFFFF));
+	if (!in_phyaddr) {
+		pr_err("error gettting input physical address\n");
+		rc = -EINVAL;
+		goto err_free_new_frame;
+	}
+
+	memset(&new_frame->output_buffer_info, 0,
+		sizeof(struct msm_vpe_buffer_info_t));
+	memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info));
+	buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF);
+	buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF);
+	rc = msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF,
+				&buff_mgr_info);
+	if (rc < 0) {
+		pr_err("error getting buffer\n");
+		rc = -EINVAL;
+		goto err_free_new_frame;
+	}
+
+	new_frame->output_buffer_info.index = buff_mgr_info.index;
+	out_phyaddr = msm_vpe_fetch_buffer_info(vpe_dev,
+		&new_frame->output_buffer_info,
+		((new_frame->identity >> 16) & 0xFFFF),
+		(new_frame->identity & 0xFFFF));
+	if (!out_phyaddr) {
+		pr_err("error gettting output physical address\n");
+		rc = -EINVAL;
+		goto err_put_buf;
+	}
+
+	new_frame->src_phyaddr = in_phyaddr;
+	new_frame->dest_phyaddr = out_phyaddr;
+
+	frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
+	if (!frame_qcmd) {
+		pr_err("Insufficient memory. return\n");
+		rc = -ENOMEM;
+		goto err_put_buf;
+	}
+
+	atomic_set(&frame_qcmd->on_heap, 1);
+	frame_qcmd->command = new_frame;
+	rc = msm_vpe_send_frame_to_hardware(vpe_dev, frame_qcmd);
+	if (rc < 0) {
+		pr_err("error cannot send frame to hardware\n");
+		rc = -EINVAL;
+		goto err_free_frame_qcmd;
+	}
+
+	return rc;
+
+err_free_frame_qcmd:
+	kfree(frame_qcmd);
+err_put_buf:
+	msm_vpe_buffer_ops(vpe_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF,
+		&buff_mgr_info);
+err_free_new_frame:
+	kfree(new_frame);
+	return rc;
+}
+
+static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+	struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+	int rc = 0;
+
+	mutex_lock(&vpe_dev->mutex);
+	switch (cmd) {
+	case VIDIOC_MSM_VPE_TRANSACTION_SETUP: {
+		struct msm_vpe_transaction_setup_cfg *cfg;
+		VPE_DBG("VIDIOC_MSM_VPE_TRANSACTION_SETUP\n");
+		if (sizeof(*cfg) != ioctl_ptr->len) {
+			pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
+				__func__, cmd, ioctl_ptr->len,
+				sizeof(*cfg));
+			rc = -EINVAL;
+			break;
+		}
+
+		cfg = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+		if (!cfg) {
+			pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = copy_from_user(cfg, (void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len);
+		if (rc) {
+			pr_err("%s:%d copy from user\n", __func__, __LINE__);
+			kfree(cfg);
+			break;
+		}
+
+		msm_vpe_transaction_setup(vpe_dev, (void *)cfg);
+		kfree(cfg);
+		break;
+	}
+	case VIDIOC_MSM_VPE_CFG: {
+		VPE_DBG("VIDIOC_MSM_VPE_CFG\n");
+		rc = msm_vpe_cfg(vpe_dev, ioctl_ptr);
+		break;
+	}
+	case VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO: {
+		struct msm_vpe_stream_buff_info_t *u_stream_buff_info;
+		struct msm_vpe_stream_buff_info_t k_stream_buff_info;
+
+		VPE_DBG("VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO\n");
+
+		if (sizeof(struct msm_vpe_stream_buff_info_t) !=
+			ioctl_ptr->len) {
+			pr_err("%s:%d: invalid length\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL);
+		if (!u_stream_buff_info) {
+			pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = (copy_from_user(u_stream_buff_info,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len) ? -EFAULT : 0);
+		if (rc) {
+			pr_err("%s:%d copy from user\n", __func__, __LINE__);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs;
+		k_stream_buff_info.identity = u_stream_buff_info->identity;
+		k_stream_buff_info.buffer_info =
+			kzalloc(k_stream_buff_info.num_buffs *
+			sizeof(struct msm_vpe_buffer_info_t), GFP_KERNEL);
+		if (!k_stream_buff_info.buffer_info) {
+			pr_err("%s:%d: malloc error\n", __func__, __LINE__);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = (copy_from_user(k_stream_buff_info.buffer_info,
+				(void __user *)u_stream_buff_info->buffer_info,
+				k_stream_buff_info.num_buffs *
+				sizeof(struct msm_vpe_buffer_info_t)) ?
+				-EFAULT : 0);
+		if (rc) {
+			pr_err("%s:%d copy from user\n", __func__, __LINE__);
+			kfree(k_stream_buff_info.buffer_info);
+			kfree(u_stream_buff_info);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		rc = msm_vpe_add_buff_queue_entry(vpe_dev,
+			((k_stream_buff_info.identity >> 16) & 0xFFFF),
+			(k_stream_buff_info.identity & 0xFFFF));
+		if (!rc)
+			rc = msm_vpe_enqueue_buff_info_list(vpe_dev,
+				&k_stream_buff_info);
+
+		kfree(k_stream_buff_info.buffer_info);
+		kfree(u_stream_buff_info);
+		break;
+	}
+	case VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO: {
+		uint32_t identity;
+		struct msm_vpe_buff_queue_info_t *buff_queue_info;
+
+		VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n");
+
+		rc = (copy_from_user(&identity,
+				(void __user *)ioctl_ptr->ioctl_ptr,
+				ioctl_ptr->len) ? -EFAULT : 0);
+		if (rc) {
+			pr_err("%s:%d copy from user\n", __func__, __LINE__);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		buff_queue_info = msm_vpe_get_buff_queue_entry(vpe_dev,
+			((identity >> 16) & 0xFFFF), (identity & 0xFFFF));
+		if (buff_queue_info == NULL) {
+			pr_err("error finding buffer queue entry for identity:%d\n",
+				identity);
+			mutex_unlock(&vpe_dev->mutex);
+			return -EINVAL;
+		}
+
+		msm_vpe_dequeue_buff_info_list(vpe_dev, buff_queue_info);
+		rc = msm_vpe_free_buff_queue_entry(vpe_dev,
+			buff_queue_info->session_id,
+			buff_queue_info->stream_id);
+		break;
+	}
+	case VIDIOC_MSM_VPE_GET_EVENTPAYLOAD: {
+		struct msm_device_queue *queue = &vpe_dev->eventData_q;
+		struct msm_queue_cmd *event_qcmd;
+		struct msm_vpe_frame_info_t *process_frame;
+		VPE_DBG("VIDIOC_MSM_VPE_GET_EVENTPAYLOAD\n");
+		event_qcmd = msm_dequeue(queue, list_eventdata);
+		process_frame = event_qcmd->command;
+		VPE_DBG("fid %d\n", process_frame->frame_id);
+		if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+				process_frame,
+				sizeof(struct msm_vpe_frame_info_t))) {
+					mutex_unlock(&vpe_dev->mutex);
+					return -EINVAL;
+		}
+
+		kfree(process_frame);
+		kfree(event_qcmd);
+		break;
+	}
+	}
+	mutex_unlock(&vpe_dev->mutex);
+	return rc;
+}
+
+static int msm_vpe_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_subscribe(fh, sub, MAX_VPE_V4l2_EVENTS);
+}
+
+static int msm_vpe_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+				struct v4l2_event_subscription *sub)
+{
+	return v4l2_event_unsubscribe(fh, sub);
+}
+
+static struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
+	.ioctl = msm_vpe_subdev_ioctl,
+	.subscribe_event = msm_vpe_subscribe_event,
+	.unsubscribe_event = msm_vpe_unsubscribe_event,
+};
+
+static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
+	.core = &msm_vpe_subdev_core_ops,
+};
+
+static struct v4l2_file_operations msm_vpe_v4l2_subdev_fops;
+
+static long msm_vpe_subdev_do_ioctl(
+	struct file *file, unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+	struct v4l2_fh *vfh = file->private_data;
+
+	switch (cmd) {
+	case VIDIOC_DQEVENT:
+		if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+			return -ENOIOCTLCMD;
+
+		return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_SUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+		return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+	case VIDIOC_MSM_VPE_GET_INST_INFO: {
+		uint32_t i;
+		struct vpe_device *vpe_dev = v4l2_get_subdevdata(sd);
+		struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+		struct msm_vpe_frame_info_t inst_info;
+		for (i = 0; i < MAX_ACTIVE_VPE_INSTANCE; i++) {
+			if (vpe_dev->vpe_subscribe_list[i].vfh == vfh) {
+				inst_info.inst_id = i;
+				break;
+			}
+		}
+		if (copy_to_user(
+				(void __user *)ioctl_ptr->ioctl_ptr, &inst_info,
+				sizeof(struct msm_vpe_frame_info_t))) {
+			return -EINVAL;
+		}
+	}
+	default:
+		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+	}
+
+	return 0;
+}
+
+static long msm_vpe_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	return video_usercopy(file, cmd, arg, msm_vpe_subdev_do_ioctl);
+}
+
+static int vpe_register_domain(void)
+{
+	struct msm_iova_partition vpe_iommu_partition = {
+		/* TODO: verify that these are correct? */
+		.start = SZ_128K,
+		.size = SZ_2G - SZ_128K,
+	};
+	struct msm_iova_layout vpe_iommu_layout = {
+		.partitions = &vpe_iommu_partition,
+		.npartitions = 1,
+		.client_name = "camera_vpe",
+		.domain_flags = 0,
+	};
+
+	return msm_register_domain(&vpe_iommu_layout);
+}
+
+static int __devinit vpe_probe(struct platform_device *pdev)
+{
+	struct vpe_device *vpe_dev;
+	int rc = 0;
+
+	vpe_dev = kzalloc(sizeof(struct vpe_device), GFP_KERNEL);
+	if (!vpe_dev) {
+		pr_err("not enough memory\n");
+		return -ENOMEM;
+	}
+
+	vpe_dev->vpe_clk = kzalloc(sizeof(struct clk *) *
+				ARRAY_SIZE(vpe_clk_info), GFP_KERNEL);
+	if (!vpe_dev->vpe_clk) {
+		pr_err("not enough memory\n");
+		rc = -ENOMEM;
+		goto err_free_vpe_dev;
+	}
+
+	v4l2_subdev_init(&vpe_dev->msm_sd.sd, &msm_vpe_subdev_ops);
+	vpe_dev->msm_sd.sd.internal_ops = &msm_vpe_internal_ops;
+	snprintf(vpe_dev->msm_sd.sd.name, ARRAY_SIZE(vpe_dev->msm_sd.sd.name),
+		"vpe");
+	vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	vpe_dev->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+	v4l2_set_subdevdata(&vpe_dev->msm_sd.sd, vpe_dev);
+	platform_set_drvdata(pdev, &vpe_dev->msm_sd.sd);
+	mutex_init(&vpe_dev->mutex);
+	spin_lock_init(&vpe_dev->tasklet_lock);
+
+	vpe_dev->pdev = pdev;
+
+	vpe_dev->mem = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM, "vpe");
+	if (!vpe_dev->mem) {
+		pr_err("no mem resource?\n");
+		rc = -ENODEV;
+		goto err_free_vpe_clk;
+	}
+
+	vpe_dev->irq = platform_get_resource_byname(pdev,
+						IORESOURCE_IRQ, "vpe");
+	if (!vpe_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto err_release_mem;
+	}
+
+	vpe_dev->domain_num = vpe_register_domain();
+	if (vpe_dev->domain_num < 0) {
+		pr_err("%s: could not register domain\n", __func__);
+		rc = -ENODEV;
+		goto err_release_mem;
+	}
+
+	vpe_dev->domain =
+		msm_get_iommu_domain(vpe_dev->domain_num);
+	if (!vpe_dev->domain) {
+		pr_err("%s: cannot find domain\n", __func__);
+		rc = -ENODEV;
+		goto err_release_mem;
+	}
+
+	vpe_dev->iommu_ctx_src = msm_iommu_get_ctx("vpe_src");
+	vpe_dev->iommu_ctx_dst = msm_iommu_get_ctx("vpe_dst");
+	if (!vpe_dev->iommu_ctx_src || !vpe_dev->iommu_ctx_dst) {
+		pr_err("%s: cannot get iommu_ctx\n", __func__);
+		rc = -ENODEV;
+		goto err_release_mem;
+	}
+
+	media_entity_init(&vpe_dev->msm_sd.sd.entity, 0, NULL, 0);
+	vpe_dev->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+	vpe_dev->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_VPE;
+	vpe_dev->msm_sd.sd.entity.name = pdev->name;
+	msm_sd_register(&vpe_dev->msm_sd);
+	msm_vpe_v4l2_subdev_fops.owner = v4l2_subdev_fops.owner;
+	msm_vpe_v4l2_subdev_fops.open = v4l2_subdev_fops.open;
+	msm_vpe_v4l2_subdev_fops.unlocked_ioctl = msm_vpe_subdev_fops_ioctl;
+	msm_vpe_v4l2_subdev_fops.release = v4l2_subdev_fops.release;
+	msm_vpe_v4l2_subdev_fops.poll = v4l2_subdev_fops.poll;
+
+	vpe_dev->msm_sd.sd.devnode->fops = &msm_vpe_v4l2_subdev_fops;
+	vpe_dev->msm_sd.sd.entity.revision = vpe_dev->msm_sd.sd.devnode->num;
+	vpe_dev->state = VPE_STATE_BOOT;
+	rc = vpe_init_hardware(vpe_dev);
+	if (rc < 0) {
+		pr_err("%s: Couldn't init vpe hardware\n", __func__);
+		rc = -ENODEV;
+		goto err_unregister_sd;
+	}
+	vpe_reset(vpe_dev);
+	vpe_release_hardware(vpe_dev);
+	vpe_dev->state = VPE_STATE_OFF;
+
+	rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+	if (rc < 0) {
+		pr_err("Couldn't attach to vpe_src context bank\n");
+		rc = -ENODEV;
+		goto err_unregister_sd;
+	}
+	rc = iommu_attach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst);
+	if (rc < 0) {
+		pr_err("Couldn't attach to vpe_dst context bank\n");
+		rc = -ENODEV;
+		goto err_detach_src;
+	}
+
+	vpe_dev->state = VPE_STATE_OFF;
+
+	msm_queue_init(&vpe_dev->eventData_q, "vpe-eventdata");
+	msm_queue_init(&vpe_dev->processing_q, "vpe-frame");
+	INIT_LIST_HEAD(&vpe_dev->tasklet_q);
+	tasklet_init(&vpe_dev->vpe_tasklet, msm_vpe_do_tasklet,
+		(unsigned long)vpe_dev);
+	vpe_dev->vpe_open_cnt = 0;
+
+	return rc;
+
+err_detach_src:
+	iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+err_unregister_sd:
+	msm_sd_unregister(&vpe_dev->msm_sd);
+err_release_mem:
+	release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem));
+err_free_vpe_clk:
+	kfree(vpe_dev->vpe_clk);
+err_free_vpe_dev:
+	kfree(vpe_dev);
+	return rc;
+}
+
+static int vpe_device_remove(struct platform_device *dev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(dev);
+	struct vpe_device  *vpe_dev;
+	if (!sd) {
+		pr_err("%s: Subdevice is NULL\n", __func__);
+		return 0;
+	}
+
+	vpe_dev = (struct vpe_device *)v4l2_get_subdevdata(sd);
+	if (!vpe_dev) {
+		pr_err("%s: vpe device is NULL\n", __func__);
+		return 0;
+	}
+
+	iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_dst);
+	iommu_detach_device(vpe_dev->domain, vpe_dev->iommu_ctx_src);
+	msm_sd_unregister(&vpe_dev->msm_sd);
+	release_mem_region(vpe_dev->mem->start, resource_size(vpe_dev->mem));
+	mutex_destroy(&vpe_dev->mutex);
+	kfree(vpe_dev);
+	return 0;
+}
+
+static struct platform_driver vpe_driver = {
+	.probe = vpe_probe,
+	.remove = __devexit_p(vpe_device_remove),
+	.driver = {
+		.name = MSM_VPE_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_vpe_init_module(void)
+{
+	return platform_driver_register(&vpe_driver);
+}
+
+static void __exit msm_vpe_exit_module(void)
+{
+	platform_driver_unregister(&vpe_driver);
+}
+
+module_init(msm_vpe_init_module);
+module_exit(msm_vpe_exit_module);
+MODULE_DESCRIPTION("MSM VPE driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h
new file mode 100644
index 0000000..c02432e
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.h
@@ -0,0 +1,255 @@
+/* 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_VPE_H__
+#define __MSM_VPE_H__
+
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-subdev.h>
+#include "msm_sd.h"
+
+/***********  start of register offset *********************/
+#define VPE_INTR_ENABLE_OFFSET                0x0020
+#define VPE_INTR_STATUS_OFFSET                0x0024
+#define VPE_INTR_CLEAR_OFFSET                 0x0028
+#define VPE_DL0_START_OFFSET                  0x0030
+#define VPE_HW_VERSION_OFFSET                 0x0070
+#define VPE_SW_RESET_OFFSET                   0x0074
+#define VPE_AXI_RD_ARB_CONFIG_OFFSET          0x0078
+#define VPE_SEL_CLK_OR_HCLK_TEST_BUS_OFFSET   0x007C
+#define VPE_CGC_EN_OFFSET                     0x0100
+#define VPE_CMD_STATUS_OFFSET                 0x10008
+#define VPE_PROFILE_EN_OFFSET                 0x10010
+#define VPE_PROFILE_COUNT_OFFSET              0x10014
+#define VPE_CMD_MODE_OFFSET                   0x10060
+#define VPE_SRC_SIZE_OFFSET                   0x10108
+#define VPE_SRCP0_ADDR_OFFSET                 0x1010C
+#define VPE_SRCP1_ADDR_OFFSET                 0x10110
+#define VPE_SRC_YSTRIDE1_OFFSET               0x1011C
+#define VPE_SRC_FORMAT_OFFSET                 0x10124
+#define VPE_SRC_UNPACK_PATTERN1_OFFSET        0x10128
+#define VPE_OP_MODE_OFFSET                    0x10138
+#define VPE_SCALE_PHASEX_INIT_OFFSET          0x1013C
+#define VPE_SCALE_PHASEY_INIT_OFFSET          0x10140
+#define VPE_SCALE_PHASEX_STEP_OFFSET          0x10144
+#define VPE_SCALE_PHASEY_STEP_OFFSET          0x10148
+#define VPE_OUT_FORMAT_OFFSET                 0x10150
+#define VPE_OUT_PACK_PATTERN1_OFFSET          0x10154
+#define VPE_OUT_SIZE_OFFSET                   0x10164
+#define VPE_OUTP0_ADDR_OFFSET                 0x10168
+#define VPE_OUTP1_ADDR_OFFSET                 0x1016C
+#define VPE_OUT_YSTRIDE1_OFFSET               0x10178
+#define VPE_OUT_XY_OFFSET                     0x1019C
+#define VPE_SRC_XY_OFFSET                     0x10200
+#define VPE_SRC_IMAGE_SIZE_OFFSET             0x10208
+#define VPE_SCALE_CONFIG_OFFSET               0x10230
+#define VPE_DEINT_STATUS_OFFSET               0x30000
+#define VPE_DEINT_DECISION_OFFSET             0x30004
+#define VPE_DEINT_COEFF0_OFFSET               0x30010
+#define VPE_SCALE_STATUS_OFFSET               0x50000
+#define VPE_SCALE_SVI_PARAM_OFFSET            0x50010
+#define VPE_SCALE_SHARPEN_CFG_OFFSET          0x50020
+#define VPE_SCALE_COEFF_LSP_0_OFFSET          0x50400
+#define VPE_SCALE_COEFF_MSP_0_OFFSET          0x50404
+
+#define VPE_AXI_ARB_1_OFFSET                  0x00408
+#define VPE_AXI_ARB_2_OFFSET                  0x0040C
+
+#define VPE_SCALE_COEFF_LSBn(n)	(0x50400 + 8 * (n))
+#define VPE_SCALE_COEFF_MSBn(n)	(0x50404 + 8 * (n))
+#define VPE_SCALE_COEFF_NUM			32
+
+/*********** end of register offset ********************/
+
+
+#define VPE_HARDWARE_VERSION          0x00080308
+#define VPE_SW_RESET_VALUE            0x00000010  /* bit 4 for PPP*/
+#define VPE_AXI_RD_ARB_CONFIG_VALUE   0x124924
+#define VPE_CMD_MODE_VALUE            0x1
+#define VPE_DEFAULT_OP_MODE_VALUE     0x40FC0004
+#define VPE_CGC_ENABLE_VALUE          0xffff
+#define VPE_DEFAULT_SCALE_CONFIG      0x3c
+
+#define VPE_NORMAL_MODE_CLOCK_RATE   150000000
+#define VPE_TURBO_MODE_CLOCK_RATE    200000000
+#define VPE_SUBDEV_MAX_EVENTS        30
+
+/**************************************************/
+/*********** End of command id ********************/
+/**************************************************/
+
+#define SCALER_PHASE_BITS 29
+#define HAL_MDP_PHASE_STEP_2P50    0x50000000
+#define HAL_MDP_PHASE_STEP_1P66    0x35555555
+#define HAL_MDP_PHASE_STEP_1P25    0x28000000
+
+
+#define MAX_ACTIVE_VPE_INSTANCE 8
+#define MAX_VPE_PROCESSING_FRAME 2
+#define MAX_VPE_V4l2_EVENTS 30
+
+#define MSM_VPE_TASKLETQ_SIZE		16
+
+/**
+ * The format of the msm_vpe_transaction_setup_cfg is as follows:
+ *
+ * - vpe_update_scale_coef (65*4 uint32_t's)
+ *   - Each table is 65 uint32_t's long
+ *   - 1st uint32_t in each table indicates offset
+ *   - Following 64 uint32_t's are the data
+ *
+ * - vpe_input_plane_config (6 uint32_t's)
+ *   - VPE_SRC_FORMAT_OFFSET
+ *   - VPE_SRC_UNPACK_PATTERN1_OFFSET
+ *   - VPE_SRC_IMAGE_SIZE_OFFSET
+ *   - VPE_SRC_YSTRIDE1_OFFSET
+ *   - VPE_SRC_SIZE_OFFSET
+ *   - VPE_SRC_XY_OFFSET
+ *
+ * - vpe_output_plane_config (5 uint32_t's)
+ *   - VPE_OUT_FORMAT_OFFSET
+ *   - VPE_OUT_PACK_PATTERN1_OFFSET
+ *   - VPE_OUT_YSTRIDE1_OFFSET
+ *   - VPE_OUT_SIZE_OFFSET
+ *   - VPE_OUT_XY_OFFSET
+ *
+ * - vpe_operation_config (1 uint32_t)
+ *   - VPE_OP_MODE_OFFSET
+ *
+ */
+
+#define VPE_SCALER_CONFIG_LEN           260
+#define VPE_INPUT_PLANE_CFG_LEN         24
+#define VPE_OUTPUT_PLANE_CFG_LEN        20
+#define VPE_OPERATION_MODE_CFG_LEN      4
+#define VPE_NUM_SCALER_TABLES		4
+
+#define VPE_TRANSACTION_SETUP_CONFIG_LEN (			\
+		(VPE_SCALER_CONFIG_LEN * VPE_NUM_SCALER_TABLES)	\
+		+ VPE_INPUT_PLANE_CFG_LEN			\
+		+ VPE_OUTPUT_PLANE_CFG_LEN			\
+		+ VPE_OPERATION_MODE_CFG_LEN)
+/* VPE_TRANSACTION_SETUP_CONFIG_LEN = 1088 */
+
+struct msm_vpe_transaction_setup_cfg {
+	uint8_t scaler_cfg[VPE_TRANSACTION_SETUP_CONFIG_LEN];
+};
+
+struct vpe_subscribe_info {
+	struct v4l2_fh *vfh;
+	uint32_t active;
+};
+
+enum vpe_state {
+	VPE_STATE_BOOT,
+	VPE_STATE_IDLE,
+	VPE_STATE_ACTIVE,
+	VPE_STATE_OFF,
+};
+
+struct msm_queue_cmd {
+	struct list_head list_config;
+	struct list_head list_control;
+	struct list_head list_frame;
+	struct list_head list_pict;
+	struct list_head list_vpe_frame;
+	struct list_head list_eventdata;
+	void *command;
+	atomic_t on_heap;
+	struct timespec ts;
+	uint32_t error_code;
+	uint32_t trans_code;
+};
+
+struct msm_device_queue {
+	struct list_head list;
+	spinlock_t lock;
+	wait_queue_head_t wait;
+	int max;
+	int len;
+	const char *name;
+};
+
+struct msm_vpe_tasklet_queue_cmd {
+	struct list_head list;
+	uint32_t irq_status;
+	uint8_t cmd_used;
+};
+
+struct msm_vpe_buffer_map_info_t {
+	unsigned long len;
+	unsigned long phy_addr;
+	struct ion_handle *ion_handle;
+	struct msm_vpe_buffer_info_t buff_info;
+};
+
+struct msm_vpe_buffer_map_list_t {
+	struct msm_vpe_buffer_map_info_t map_info;
+	struct list_head entry;
+};
+
+struct msm_vpe_buff_queue_info_t {
+	uint32_t used;
+	uint16_t session_id;
+	uint16_t stream_id;
+	struct list_head vb2_buff_head;
+	struct list_head native_buff_head;
+};
+
+struct vpe_device {
+	struct platform_device *pdev;
+	struct msm_sd_subdev msm_sd;
+	struct v4l2_subdev subdev;
+	struct resource *mem;
+	struct resource *irq;
+	void __iomem *base;
+	struct clk **vpe_clk;
+	struct regulator *fs_vpe;
+	struct mutex mutex;
+	enum vpe_state state;
+
+	int domain_num;
+	struct iommu_domain *domain;
+	struct device *iommu_ctx_src;
+	struct device *iommu_ctx_dst;
+	struct ion_client *client;
+	struct kref refcount;
+
+	/* Reusing proven tasklet from msm isp */
+	atomic_t irq_cnt;
+	uint8_t taskletq_idx;
+	spinlock_t  tasklet_lock;
+	struct list_head tasklet_q;
+	struct tasklet_struct vpe_tasklet;
+	struct msm_vpe_tasklet_queue_cmd
+	tasklet_queue_cmd[MSM_VPE_TASKLETQ_SIZE];
+
+	struct vpe_subscribe_info vpe_subscribe_list[MAX_ACTIVE_VPE_INSTANCE];
+	uint32_t vpe_open_cnt;
+
+	struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */
+
+	/*
+	 * Processing Queue: store frame info for frames sent to
+	 * microcontroller
+	 */
+	struct msm_device_queue processing_q;
+
+	struct msm_vpe_buff_queue_info_t *buff_queue;
+	uint32_t num_buffq;
+	struct v4l2_subdev *buf_mgr_subdev;
+};
+
+#endif /* __MSM_VPE_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
index c9476ee..9b02b17 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/imx135.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
@@ -36,6 +36,12 @@
 		.delay = 0,
 	},
 	{
+		.seq_type = SENSOR_VREG,
+		.seq_val = CAM_VAF,
+		.config_val = 0,
+		.delay = 0,
+	},
+	{
 		.seq_type = SENSOR_GPIO,
 		.seq_val = SENSOR_GPIO_RESET,
 		.config_val = GPIO_OUT_LOW,
@@ -48,6 +54,18 @@
 		.delay = 30,
 	},
 	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_LOW,
+		.delay = 1,
+	},
+	{
+		.seq_type = SENSOR_GPIO,
+		.seq_val = SENSOR_GPIO_STANDBY,
+		.config_val = GPIO_OUT_HIGH,
+		.delay = 30,
+	},
+	{
 		.seq_type = SENSOR_CLK,
 		.seq_val = SENSOR_CAM_MCLK,
 		.config_val = 0,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 82a4f3c..42d4f95 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -45,6 +45,22 @@
 	[ilog2(HAL_H264_CABAC_MODEL_2)] = HFI_H264_CABAC_MODEL_2,
 };
 
+static int color_format[] = {
+	[ilog2(HAL_COLOR_FORMAT_MONOCHROME)] = HFI_COLOR_FORMAT_MONOCHROME,
+	[ilog2(HAL_COLOR_FORMAT_NV12)] = HFI_COLOR_FORMAT_NV12,
+	[ilog2(HAL_COLOR_FORMAT_NV21)] = HFI_COLOR_FORMAT_NV21,
+	[ilog2(HAL_COLOR_FORMAT_NV12_4x4TILE)] = HFI_COLOR_FORMAT_NV12_4x4TILE,
+	[ilog2(HAL_COLOR_FORMAT_NV21_4x4TILE)] = HFI_COLOR_FORMAT_NV21_4x4TILE,
+	[ilog2(HAL_COLOR_FORMAT_YUYV)] = HFI_COLOR_FORMAT_YUYV,
+	[ilog2(HAL_COLOR_FORMAT_YVYU)] = HFI_COLOR_FORMAT_YVYU,
+	[ilog2(HAL_COLOR_FORMAT_UYVY)] = HFI_COLOR_FORMAT_UYVY,
+	[ilog2(HAL_COLOR_FORMAT_VYUY)] = HFI_COLOR_FORMAT_VYUY,
+	[ilog2(HAL_COLOR_FORMAT_RGB565)] = HFI_COLOR_FORMAT_RGB565,
+	[ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565,
+	[ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888,
+	[ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
+};
+
 static inline int hal_to_hfi_type(int property, int hal_type)
 {
 	if (hal_type && (roundup_pow_of_two(hal_type) != hal_type)) {
@@ -66,6 +82,9 @@
 	case HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL:
 		return (hal_type >= ARRAY_SIZE(cabac_model)) ?
 			-ENOTSUPP : cabac_model[hal_type];
+	case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT:
+		return (hal_type >= ARRAY_SIZE(color_format)) ?
+			-ENOTSUPP : color_format[hal_type];
 	default:
 		return -ENOTSUPP;
 	}
@@ -632,11 +651,13 @@
 			hfi->buffer_type = buffer_type;
 		else
 			return -EINVAL;
-		hfi->format = prop->format;
+		hfi->format = hal_to_hfi_type(
+				HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+				prop->format);
 		pkt->size += sizeof(u32) +
 			sizeof(struct hfi_uncompressed_format_select);
 		break;
-		}
+	}
 	case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO:
 		break;
 	case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 511a478..1885379 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1498,6 +1498,6 @@
 		kfree(curr->cluster);
 		kfree(curr);
 	}
-
+	v4l2_ctrl_handler_free(&inst->ctrl_handler);
 	return 0;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index b6e77dc..20cb08d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -687,7 +687,7 @@
 
 static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
 {
-	return height * width * 2;
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
 }
 
 static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
@@ -2035,7 +2035,6 @@
 int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
 {
 	struct msm_vidc_format *fmt = NULL;
-	struct hal_frame_size frame_sz;
 	int rc = 0;
 	int i;
 	struct hfi_device *hdev;
@@ -2063,6 +2062,9 @@
 			goto exit;
 		}
 	} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+		struct hal_uncompressed_format_select hal_fmt = {0};
+		struct hal_frame_size frame_sz;
+
 		inst->prop.width = f->fmt.pix_mp.width;
 		inst->prop.height = f->fmt.pix_mp.height;
 		rc = msm_vidc_check_session_supported(inst);
@@ -2101,6 +2103,29 @@
 			rc = -EINVAL;
 			goto exit;
 		}
+
+		switch (fmt->fourcc) {
+		case V4L2_PIX_FMT_NV12:
+			hal_fmt.format = HAL_COLOR_FORMAT_NV12;
+			break;
+		case V4L2_PIX_FMT_NV21:
+			hal_fmt.format = HAL_COLOR_FORMAT_NV21;
+			break;
+		default:
+			/* we really shouldn't be here */
+			rc = -ENOTSUPP;
+			goto exit;
+		}
+
+		hal_fmt.buffer_type = HAL_BUFFER_INPUT;
+		rc = call_hfi_op(hdev, session_set_property, (void *)
+			inst->session, HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
+			&hal_fmt);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"Failed to set input color format\n");
+			goto exit;
+		}
 	}
 
 	if (fmt) {
@@ -2516,6 +2541,6 @@
 		kfree(curr->cluster);
 		kfree(curr);
 	}
-
+	v4l2_ctrl_handler_free(&inst->ctrl_handler);
 	return 0;
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 0fbfd72..1c43f1e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -565,6 +565,7 @@
 	struct msm_vidc_core *core;
 	struct list_head *ptr, *next;
 	int rc = 0;
+	int i;
 
 	if (!inst)
 		return -EINVAL;
@@ -592,6 +593,9 @@
 	if (rc)
 		dprintk(VIDC_ERR,
 			"Failed to move video instance to uninit state\n");
+	for (i = 0; i < MAX_PORT_NUM; i++)
+		vb2_queue_release(&inst->bufq[i].vb2_bufq);
+
 	pr_info(VIDC_DBG_TAG "Closed video instance: %p\n", VIDC_INFO, inst);
 	kfree(inst);
 	return 0;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index cf051b6..91fcdb6 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2383,38 +2383,27 @@
 	struct msm_vidc_core_capability *capability;
 	int rc = 0;
 	struct v4l2_event dqevent;
+	struct hfi_device *hdev;
 
-	if (!inst) {
+	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
 		return -EINVAL;
 	}
 	capability = &inst->capability;
+	hdev = inst->core->device;
 
 	if (inst->capability.capability_set) {
-		if (msm_vp8_low_tier &&
-			inst->core->hfi_type == VIDC_HFI_VENUS &&
-			inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_VP8) {
-			capability->width.max = DEFAULT_WIDTH;
-			capability->height.max = DEFAULT_HEIGHT;
-		}
-		if (inst->prop.width < capability->width.min ||
-			inst->prop.width > capability->width.max ||
-			(inst->prop.width % capability->width.step_size != 0)) {
-			dprintk(VIDC_ERR,
-			"Unsupported width = %d range min(%u) - max(%u) step_size(%u)",
-			inst->prop.width, capability->width.min,
-			capability->width.max, capability->width.step_size);
-			rc = -ENOTSUPP;
-		}
+		rc = call_hfi_op(hdev, capability_check,
+			inst->fmts[OUTPUT_PORT]->fourcc,
+			inst->prop.width, &capability->width.max,
+			&capability->height.max);
 
-		if (inst->prop.height < capability->height.min ||
-			inst->prop.height > capability->height.max ||
-			(inst->prop.height %
-			capability->height.step_size != 0)) {
+		if (!rc && (inst->prop.height * inst->prop.width >
+			capability->width.max * capability->height.max)) {
 			dprintk(VIDC_ERR,
-			"Unsupported height = %d range min(%u) - max(%u) step_size(%u)",
-			inst->prop.height, capability->height.min,
-			capability->height.max, capability->height.step_size);
+			"Unsupported WxH = (%u)x(%u), Max supported is - (%u)x(%u)",
+			inst->prop.width, inst->prop.height,
+			capability->width.max, capability->height.max);
 			rc = -ENOTSUPP;
 		}
 	}
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 964167f..74733c2 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2849,6 +2849,28 @@
 	return 0;
 }
 
+int venus_hfi_capability_check(u32 fourcc, u32 width,
+		u32 *max_width, u32 *max_height)
+{
+	int rc = 0;
+	if (!max_width || !max_height) {
+		dprintk(VIDC_ERR, "%s - invalid parameter\n", __func__);
+		return -EINVAL;
+	}
+
+	if (msm_vp8_low_tier && fourcc == V4L2_PIX_FMT_VP8) {
+		*max_width = DEFAULT_WIDTH;
+		*max_height = DEFAULT_HEIGHT;
+	}
+	if (width > *max_width) {
+		dprintk(VIDC_ERR,
+		"Unsupported width = %u supported max width = %u",
+		width, *max_width);
+		rc = -ENOTSUPP;
+	}
+	return rc;
+}
+
 static void *venus_hfi_add_device(u32 device_id,
 			struct msm_vidc_platform_resources *res,
 			hfi_cmd_response_callback callback)
@@ -2988,6 +3010,7 @@
 	hdev->unload_fw = venus_hfi_unload_fw;
 	hdev->get_fw_info = venus_hfi_get_fw_info;
 	hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
+	hdev->capability_check = venus_hfi_capability_check;
 }
 
 int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index bf1c70b..01395e5 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -391,20 +391,20 @@
 };
 
 enum hal_uncompressed_format {
-	HAL_COLOR_FORMAT_MONOCHROME,
-	HAL_COLOR_FORMAT_NV12,
-	HAL_COLOR_FORMAT_NV21,
-	HAL_COLOR_FORMAT_NV12_4x4TILE,
-	HAL_COLOR_FORMAT_NV21_4x4TILE,
-	HAL_COLOR_FORMAT_YUYV,
-	HAL_COLOR_FORMAT_YVYU,
-	HAL_COLOR_FORMAT_UYVY,
-	HAL_COLOR_FORMAT_VYUY,
-	HAL_COLOR_FORMAT_RGB565,
-	HAL_COLOR_FORMAT_BGR565,
-	HAL_COLOR_FORMAT_RGB888,
-	HAL_COLOR_FORMAT_BGR888,
-	HAL_UNUSED_COLOR = 0x10000000,
+	HAL_COLOR_FORMAT_MONOCHROME   = 0x00000001,
+	HAL_COLOR_FORMAT_NV12         = 0x00000002,
+	HAL_COLOR_FORMAT_NV21         = 0x00000004,
+	HAL_COLOR_FORMAT_NV12_4x4TILE = 0x00000008,
+	HAL_COLOR_FORMAT_NV21_4x4TILE = 0x00000010,
+	HAL_COLOR_FORMAT_YUYV         = 0x00000020,
+	HAL_COLOR_FORMAT_YVYU         = 0x00000040,
+	HAL_COLOR_FORMAT_UYVY         = 0x00000080,
+	HAL_COLOR_FORMAT_VYUY         = 0x00000100,
+	HAL_COLOR_FORMAT_RGB565       = 0x00000200,
+	HAL_COLOR_FORMAT_BGR565       = 0x00000400,
+	HAL_COLOR_FORMAT_RGB888       = 0x00000800,
+	HAL_COLOR_FORMAT_BGR888       = 0x00001000,
+	HAL_UNUSED_COLOR              = 0x10000000,
 };
 
 enum hal_ssr_trigger_type {
@@ -1075,6 +1075,8 @@
 	int (*get_fw_info)(void *dev, enum fw_info info);
 	int (*get_stride_scanline)(int color_fmt, int width,
 		int height,	int *stride, int *scanlines);
+	int (*capability_check)(u32 fourcc, u32 width,
+		u32 *max_width, u32 *max_height);
 };
 
 typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index fa28d6a..f139b21 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -540,6 +540,8 @@
 	unsigned long flags;
 	struct qseecom_client_listener_data_irsp send_data_rsp;
 	struct qseecom_registered_listener_list *ptr_svc = NULL;
+	sigset_t new_sigset;
+	sigset_t old_sigset;
 
 	while (resp->result == QSEOS_RESULT_INCOMPLETE) {
 		lstnr = resp->data;
@@ -564,17 +566,24 @@
 		}
 		pr_debug("waking up rcv_req_wq and "
 				"waiting for send_resp_wq\n");
-		if (wait_event_freezable(qseecom.send_resp_wq,
-				__qseecom_listener_has_sent_rsp(data))) {
-			pr_warning("Interrupted: exiting send_cmd loop\n");
-			ret = -ERESTARTSYS;
-		}
 
-		if ((data->abort) || (ret == -ERESTARTSYS)) {
+		/* initialize the new signal mask with all signals*/
+		sigfillset(&new_sigset);
+		/* block all signals */
+		sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+
+		do {
+			if (!wait_event_freezable(qseecom.send_resp_wq,
+				__qseecom_listener_has_sent_rsp(data)))
+				break;
+		} while (1);
+
+		/* restore signal mask */
+		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
+		if (data->abort) {
 			pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
 				data->client.app_id, lstnr, ret);
-			if (data->abort)
-				rc = -ENODEV;
+			rc = -ENODEV;
 			send_data_rsp.status  = QSEOS_RESULT_FAILURE;
 		} else {
 			send_data_rsp.status  = QSEOS_RESULT_SUCCESS;
diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c
index 0b04bbf..5fda343 100644
--- a/drivers/mtd/devices/msm_qpic_nand.c
+++ b/drivers/mtd/devices/msm_qpic_nand.c
@@ -30,7 +30,7 @@
 #include <linux/of.h>
 #include <linux/ctype.h>
 #include <mach/sps.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
 #define PAGE_SIZE_2K 2048
 #define PAGE_SIZE_4K 4096
 #define WRITE 1
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index 6fbf971..be9058b 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -46,7 +46,8 @@
 #define ECM_IPA_LOG_ENTRY() pr_debug("begin\n")
 #define ECM_IPA_LOG_EXIT() pr_debug("end\n")
 
-/** enum ecm_ipa_state - specify the current driver internal state
+/**
+ * enum ecm_ipa_state - specify the current driver internal state.
  *
  * The driver internal state changes due to its API usage.
  * The driver saves its internal state to guard from caller illegal
@@ -65,7 +66,8 @@
 	ECM_IPA_UP,
 };
 
-#define ECM_IPA_MODE(dev) pr_debug("Driver mode changed - %d", dev->mode);
+#define ECM_IPA_MODE(ecm_ipa_ctx) \
+	pr_debug("Driver mode changed - %d", ecm_ipa_ctx->mode);
 
 /**
  * struct ecm_ipa_dev - main driver context parameters
@@ -102,32 +104,26 @@
 	enum ecm_ipa_mode mode;
 };
 
-/**
- * struct ecm_ipa_ctx - saved pointer for the ecm_ipa network device
- *                which allow ecm_ipa to be a singleton
- */
-static struct ecm_ipa_dev *ecm_ipa_ctx;
-
 static int ecm_ipa_open(struct net_device *net);
 static void ecm_ipa_packet_receive_notify(void *priv,
 		enum ipa_dp_evt_type evt, unsigned long data);
 static void ecm_ipa_tx_complete_notify(void *priv,
 		enum ipa_dp_evt_type evt, unsigned long data);
 static int ecm_ipa_stop(struct net_device *net);
-static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *ecm_ipa_ctx,
 		const void *dst_mac, const void *src_mac);
-static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev);
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
 static int ecm_ipa_register_properties(void);
 static void ecm_ipa_deregister_properties(void);
 static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
 		unsigned long data);
-static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev);
-static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *dev);
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
 static bool rx_filter(struct sk_buff *skb);
 static bool tx_filter(struct sk_buff *skb);
-static bool rm_enabled(struct ecm_ipa_dev *dev);
-static int resource_request(struct ecm_ipa_dev *dev);
-static void resource_release(struct ecm_ipa_dev *dev);
+static bool rm_enabled(struct ecm_ipa_dev *ecm_ipa_ctx);
+static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx);
 static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
 					struct net_device *net);
 static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file);
@@ -140,8 +136,8 @@
 		char __user *ubuf, size_t count, loff_t *ppos);
 static ssize_t ecm_ipa_debugfs_atomic_read(struct file *file,
 		char __user *ubuf, size_t count, loff_t *ppos);
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev);
-static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev);
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
 static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
 static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
 static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
@@ -171,7 +167,7 @@
 
 /**
  * ecm_ipa_init() - create network device and initializes internal
- * data structures
+ *  data structures
  * @params: in/out parameters required for ecm_ipa initialization
  *
  * Shall be called prior to pipe connection.
@@ -195,7 +191,7 @@
 {
 	int result = 0;
 	struct net_device *net;
-	struct ecm_ipa_dev *dev;
+	struct ecm_ipa_dev *ecm_ipa_ctx;
 
 	ECM_IPA_LOG_ENTRY();
 	pr_debug("%s initializing\n", DRIVER_NAME);
@@ -213,26 +209,25 @@
 	}
 	pr_debug("network device was successfully allocated\n");
 
-	dev = netdev_priv(net);
-	memset(dev, 0, sizeof(*dev));
-	dev->net = net;
-	ecm_ipa_ctx = dev;
-	dev->tx_enable = true;
-	dev->rx_enable = true;
-	dev->rm_enable = true;
-	dev->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
-	dev->outstanding_low = DEFAULT_OUTSTANDING_LOW;
-	atomic_set(&dev->outstanding_pkts, 0);
+	ecm_ipa_ctx = netdev_priv(net);
+	memset(ecm_ipa_ctx, 0, sizeof(*ecm_ipa_ctx));
+	ecm_ipa_ctx->net = net;
+	ecm_ipa_ctx->tx_enable = true;
+	ecm_ipa_ctx->rx_enable = true;
+	ecm_ipa_ctx->rm_enable = true;
+	ecm_ipa_ctx->outstanding_high = DEFAULT_OUTSTANDING_HIGH;
+	ecm_ipa_ctx->outstanding_low = DEFAULT_OUTSTANDING_LOW;
+	atomic_set(&ecm_ipa_ctx->outstanding_pkts, 0);
 	snprintf(net->name, sizeof(net->name), "%s%%d", "ecm");
 	net->netdev_ops = &ecm_ipa_netdev_ops;
 	pr_debug("internal data structures were intialized and defaults set\n");
 
-	result = ecm_ipa_debugfs_init(dev);
+	result = ecm_ipa_debugfs_init(ecm_ipa_ctx);
 	if (result)
 		goto fail_debugfs;
 	pr_debug("debugfs entries were created\n");
 
-	result = ecm_ipa_create_rm_resource(dev);
+	result = ecm_ipa_create_rm_resource(ecm_ipa_ctx);
 	if (result) {
 		ECM_IPA_ERROR("fail on RM create\n");
 		goto fail_create_rm;
@@ -247,7 +242,7 @@
 	}
 	pr_debug("Device Ethernet address set %pM\n", net->dev_addr);
 
-	result = ecm_ipa_rules_cfg(dev, params->host_ethaddr,
+	result = ecm_ipa_rules_cfg(ecm_ipa_ctx, params->host_ethaddr,
 			params->device_ethaddr);
 	if (result) {
 		ECM_IPA_ERROR("fail on ipa rules set\n");
@@ -274,9 +269,9 @@
 
 	params->ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
 	params->ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
-	params->private = (void *)dev;
-	dev->mode = ECM_IPA_INITIALIZED;
-	ECM_IPA_MODE(dev);
+	params->private = (void *)ecm_ipa_ctx;
+	ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
+	ECM_IPA_MODE(ecm_ipa_ctx);
 
 	ECM_IPA_LOG_EXIT();
 
@@ -285,12 +280,12 @@
 fail_register_netdev:
 	ecm_ipa_deregister_properties();
 fail_register_tx:
-	ecm_ipa_rules_destroy(dev);
+	ecm_ipa_rules_destroy(ecm_ipa_ctx);
 fail_set_device_ethernet:
 fail_rules_cfg:
-	ecm_ipa_destory_rm_resource(dev);
+	ecm_ipa_destory_rm_resource(ecm_ipa_ctx);
 fail_create_rm:
-	ecm_ipa_debugfs_destroy(dev);
+	ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
 fail_debugfs:
 	free_netdev(net);
 fail_alloc_etherdev:
@@ -298,18 +293,34 @@
 }
 EXPORT_SYMBOL(ecm_ipa_init);
 
-
+/**
+ * ecm_ipa_connect() - notify ecm_ipa for IPA<->USB pipes connection
+ * @usb_to_ipa_hdl: handle of IPA driver client for USB->IPA
+ * @ipa_to_usb_hdl: handle of IPA driver client for IPA->USB
+ * @priv: same value that was set by ecm_ipa_init(), this
+ *  parameter holds the network device pointer.
+ *
+ * Once USB driver finishes the pipe connection between IPA core
+ * and USB core this method shall be called in order to
+ * allow ecm_ipa complete the data path configurations.
+ * Detailed description:
+ *  - configure the IPA end-points register
+ *  - notify the Linux kernel for "carrier_on"
+ *  After this function is done the driver state changes to "Connected".
+ *  This API is expected to be called after ecm_ipa_init() or
+ *  after a call to ecm_ipa_disconnect.
+ */
 int ecm_ipa_connect(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
 		void *priv)
 {
-	struct ecm_ipa_dev *dev = priv;
+	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
 
 	ECM_IPA_LOG_ENTRY();
 	NULL_CHECK(priv);
 	pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
 					usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
 
-	if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_CONNECTED)) {
+	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
 		ECM_IPA_ERROR("can't call connect before driver init\n");
 		return -EPERM;
 	}
@@ -324,20 +335,20 @@
 				ipa_to_usb_hdl);
 		return -EINVAL;
 	}
-	dev->ipa_to_usb_hdl = ipa_to_usb_hdl;
-	dev->usb_to_ipa_hdl = usb_to_ipa_hdl;
+	ecm_ipa_ctx->ipa_to_usb_hdl = ipa_to_usb_hdl;
+	ecm_ipa_ctx->usb_to_ipa_hdl = usb_to_ipa_hdl;
 	ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
 	pr_debug("end-point configured\n");
 
-	netif_carrier_on(dev->net);
-	if (!netif_carrier_ok(dev->net)) {
+	netif_carrier_on(ecm_ipa_ctx->net);
+	if (!netif_carrier_ok(ecm_ipa_ctx->net)) {
 		ECM_IPA_ERROR("netif_carrier_ok error\n");
 		return -EBUSY;
 	}
 	pr_debug("carrier_on notified, ecm_ipa is operational\n");
 
-	dev->mode = ECM_IPA_CONNECTED;
-	ECM_IPA_MODE(dev);
+	ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
+	ECM_IPA_MODE(ecm_ipa_ctx);
 
 	ECM_IPA_LOG_EXIT();
 
@@ -345,15 +356,24 @@
 }
 EXPORT_SYMBOL(ecm_ipa_connect);
 
+/**
+ * ecm_ipa_open() - notify Linux network stack to start sending packets
+ * @net: the network interface supplied by the network stack
+ *
+ * Linux uses this API to notify the driver that the network interface
+ * transitions to the up state.
+ * The driver will instruct the Linux network stack to start
+ * delivering data packets.
+ */
 static int ecm_ipa_open(struct net_device *net)
 {
-	struct ecm_ipa_dev *dev;
+	struct ecm_ipa_dev *ecm_ipa_ctx;
 
 	ECM_IPA_LOG_ENTRY();
 
-	dev = netdev_priv(net);
+	ecm_ipa_ctx = netdev_priv(net);
 
-	if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_UP)) {
+	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_UP)) {
 		ECM_IPA_ERROR("can't bring driver up before cable connect\n");
 		return -EPERM;
 	}
@@ -364,8 +384,8 @@
 	netif_start_queue(net);
 	pr_debug("queue started\n");
 
-	dev->mode = ECM_IPA_UP;
-	ECM_IPA_MODE(dev);
+	ecm_ipa_ctx->mode = ECM_IPA_UP;
+	ECM_IPA_MODE(ecm_ipa_ctx);
 
 	ECM_IPA_LOG_EXIT();
 
@@ -374,28 +394,37 @@
 
 /**
  * ecm_ipa_start_xmit() - send data from APPs to USB core via IPA core
- * @skb: packet received from Linux stack
+ * @skb: packet received from Linux network stack
  * @net: the network device being used to send this packet
  *
  * Several conditions needed in order to send the packet to IPA:
- * - we are in a valid state were the queue is not stopped
+ * - Transmit queue for the network driver is currently
+ *   in "send" state
+ * - The driver internal state is in "UP" state.
  * - Filter Tx switch is turned off
- * - The resources required for actual Tx are all up
+ * - The IPA resource manager state for the driver producer client
+ *   is "Granted" which implies that all the resources in the dependency
+ *   graph are valid for data flow.
+ * - outstanding high boundary did not reach.
  *
+ * In case all of the above conditions are met, the network driver will
+ * send the packet by using the IPA API for Tx.
+ * In case the outstanding packet high boundary is reached, the driver will
+ * stop the send queue until enough packet were proceeded by the IPA core.
  */
 static netdev_tx_t ecm_ipa_start_xmit(struct sk_buff *skb,
 					struct net_device *net)
 {
 	int ret;
 	netdev_tx_t status = NETDEV_TX_BUSY;
-	struct ecm_ipa_dev *dev = netdev_priv(net);
+	struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
 
 	if (unlikely(netif_queue_stopped(net))) {
 		ECM_IPA_ERROR("interface queue is stopped\n");
 		goto out;
 	}
 
-	if (unlikely(dev->mode != ECM_IPA_UP)) {
+	if (unlikely(ecm_ipa_ctx->mode != ECM_IPA_UP)) {
 		ECM_IPA_ERROR("can't send without network interface up\n");
 		return -NETDEV_TX_BUSY;
 	}
@@ -406,16 +435,17 @@
 		status = NETDEV_TX_OK;
 		goto out;
 	}
-	ret = resource_request(dev);
+	ret = resource_request(ecm_ipa_ctx);
 	if (ret) {
 		pr_debug("Waiting to resource\n");
 		netif_stop_queue(net);
 		goto resource_busy;
 	}
 
-	if (atomic_read(&dev->outstanding_pkts) >= dev->outstanding_high) {
+	if (atomic_read(&ecm_ipa_ctx->outstanding_pkts) >=
+					ecm_ipa_ctx->outstanding_high) {
 		pr_debug("Outstanding high boundary reached (%d)- stopping queue\n",
-				dev->outstanding_high);
+				ecm_ipa_ctx->outstanding_high);
 		netif_stop_queue(net);
 		status = -NETDEV_TX_BUSY;
 		goto out;
@@ -427,7 +457,7 @@
 		goto fail_tx_packet;
 	}
 
-	atomic_inc(&dev->outstanding_pkts);
+	atomic_inc(&ecm_ipa_ctx->outstanding_pkts);
 	net->stats.tx_packets++;
 	net->stats.tx_bytes += skb->len;
 	status = NETDEV_TX_OK;
@@ -435,7 +465,7 @@
 
 fail_tx_packet:
 out:
-	resource_release(dev);
+	resource_release(ecm_ipa_ctx);
 resource_busy:
 	return status;
 }
@@ -447,14 +477,15 @@
  * @evt: event type
  * @data: data provided with event
  *
- * IPA will pass a packet with skb->data pointing to Ethernet packet frame
+ * IPA will pass a packet to the Linux network stack with skb->data pointing
+ * to Ethernet packet frame.
  */
 static void ecm_ipa_packet_receive_notify(void *priv,
 		enum ipa_dp_evt_type evt,
 		unsigned long data)
 {
 	struct sk_buff *skb = (struct sk_buff *)data;
-	struct ecm_ipa_dev *dev = priv;
+	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
 	int result;
 
 	if (evt != IPA_RECEIVE)	{
@@ -462,8 +493,8 @@
 		return;
 	}
 
-	skb->dev = dev->net;
-	skb->protocol = eth_type_trans(skb, dev->net);
+	skb->dev = ecm_ipa_ctx->net;
+	skb->protocol = eth_type_trans(skb, ecm_ipa_ctx->net);
 	if (rx_filter(skb)) {
 		pr_debug("packet got filtered out on Rx path\n");
 		dev_kfree_skb_any(skb);
@@ -473,19 +504,28 @@
 	result = netif_rx(skb);
 	if (result)
 		ECM_IPA_ERROR("fail on netif_rx\n");
-	dev->net->stats.rx_packets++;
-	dev->net->stats.rx_bytes += skb->len;
+	ecm_ipa_ctx->net->stats.rx_packets++;
+	ecm_ipa_ctx->net->stats.rx_bytes += skb->len;
 
 	return;
 }
 
+/** ecm_ipa_stop() - called when network device transitions to the down
+ *     state.
+ *  @net: the network device being stopped.
+ *
+ * This API is used by Linux network stack to notify the network driver that
+ * its state was changed to "down"
+ * The driver will stop the "send" queue and change its internal
+ * state to "Connected".
+ */
 static int ecm_ipa_stop(struct net_device *net)
 {
-	struct ecm_ipa_dev *dev = netdev_priv(net);
+	struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
 
 	ECM_IPA_LOG_ENTRY();
 
-	if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_CONNECTED)) {
+	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
 		ECM_IPA_ERROR("can't do network interface down without up\n");
 		return -EPERM;
 	}
@@ -493,34 +533,44 @@
 	netif_stop_queue(net);
 	pr_debug("network device stopped\n");
 
-	dev->mode = ECM_IPA_CONNECTED;
-	ECM_IPA_MODE(dev);
+	ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
+	ECM_IPA_MODE(ecm_ipa_ctx);
 
 	ECM_IPA_LOG_EXIT();
 	return 0;
 }
 
+/** ecm_ipa_disconnect() - called when the USB cable is unplugged.
+ * @priv: same value that was set by ecm_ipa_init(), this
+ *  parameter holds the network device pointer.
+ *
+ * Once the USB cable is unplugged the USB driver will notify the network
+ * interface driver.
+ * The internal driver state will returned to its initialized state and
+ * Linux network stack will be informed for carrier off and the send queue
+ * will be stopped.
+ */
 int ecm_ipa_disconnect(void *priv)
 {
-	struct ecm_ipa_dev *dev = priv;
+	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
 
 	ECM_IPA_LOG_ENTRY();
-	NULL_CHECK(dev);
+	NULL_CHECK(ecm_ipa_ctx);
 	pr_debug("priv=0x%p\n", priv);
 
-	if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_INITIALIZED)) {
+	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_INITIALIZED)) {
 		ECM_IPA_ERROR("can't disconnect without connect first\n");
 		return -EPERM;
 	}
 
-	netif_carrier_off(dev->net);
+	netif_carrier_off(ecm_ipa_ctx->net);
 	pr_debug("carrier_off notifcation was sent\n");
 
-	netif_stop_queue(dev->net);
+	netif_stop_queue(ecm_ipa_ctx->net);
 	pr_debug("queue stopped\n");
 
-	dev->mode = ECM_IPA_INITIALIZED;
-	ECM_IPA_MODE(dev);
+	ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
+	ECM_IPA_MODE(ecm_ipa_ctx);
 
 	ECM_IPA_LOG_EXIT();
 
@@ -530,33 +580,43 @@
 
 
 /**
- * ecm_ipa_cleanup() - destroys all
- * ecm information
- * @priv: main driver context parameters
+ * ecm_ipa_cleanup() - unregister the network interface driver and free
+ *  internal data structs.
+ * @priv: same value that was set by ecm_ipa_init(), this
+ *   parameter holds the network device pointer.
  *
+ * This function shall be called once the network interface is not
+ * needed anymore, e.g: when the USB composition does not support ECM.
+ * This function shall be called after the pipes were disconnected.
+ * Detailed description:
+ *  - delete the driver dependency defined for IPA resource manager and
+ *   destroy the producer resource.
+ *  -  remove the debugfs entries
+ *  - deregister the network interface from Linux network stack
+ *  - free all internal data structs
  */
 void ecm_ipa_cleanup(void *priv)
 {
-	struct ecm_ipa_dev *dev = priv;
+	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
 
 	ECM_IPA_LOG_ENTRY();
 
 	pr_debug("priv=0x%p\n", priv);
 
-	if (!dev) {
-		ECM_IPA_ERROR("dev NULL pointer\n");
+	if (!ecm_ipa_ctx) {
+		ECM_IPA_ERROR("ecm_ipa_ctx NULL pointer\n");
 		return;
 	}
 
-	if (!ecm_ipa_state_validate(dev->mode, ECM_IPA_LOADED))
+	if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_LOADED))
 		ECM_IPA_ERROR("can't clean driver without cable disconnect\n");
 
 
-	ecm_ipa_destory_rm_resource(dev);
-	ecm_ipa_debugfs_destroy(dev);
+	ecm_ipa_destory_rm_resource(ecm_ipa_ctx);
+	ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
 
-	unregister_netdev(dev->net);
-	free_netdev(dev->net);
+	unregister_netdev(ecm_ipa_ctx->net);
+	free_netdev(ecm_ipa_ctx->net);
 
 	pr_debug("cleanup done\n");
 	ecm_ipa_ctx = NULL;
@@ -567,34 +627,15 @@
 EXPORT_SYMBOL(ecm_ipa_cleanup);
 
 /**
- * @ecm_ipa_rx_dp_notify: supplied callback to be called by the IPA
- * driver upon data packets received from USB pipe into IPA core.
- * @ecm_ipa_rt_dp_notify: supplied callback to be called by the IPA
- * driver upon exception packets sent from IPA pipe into USB core.
- * @priv: should be passed later on to ecm_ipa_configure, hold the network
- * structure allocated for STD ECM interface.
- *
- * Shall be called prior to pipe connection.
- * The out parameters (the callbacks) shall be supplied to ipa_connect.
- * Detailed description:
- *  - set the callbacks to be used by the caller upon ipa_connect
- *  - allocate the network device
- *  - set the priv argument with a reference to the network device
- *
- * Returns negative errno, or zero on success
- */
-
-
-/**
  * ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
  *				Headers will be commited to HW
- * @dev: main driver context parameters
+ * @ecm_ipa_ctx: main driver context parameters
  * @dst_mac: destination MAC address
  * @src_mac: source MAC address
  *
  * Returns negative errno, or zero on success
  */
-static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *dev,
+static int ecm_ipa_rules_cfg(struct ecm_ipa_dev *ecm_ipa_ctx,
 		const void *dst_mac, const void *src_mac)
 {
 	struct ipa_ioc_add_hdr *hdrs;
@@ -646,8 +687,8 @@
 		result = ipv6_hdr->status;
 		goto out_free_mem;
 	}
-	dev->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
-	dev->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
+	ecm_ipa_ctx->eth_ipv4_hdr_hdl = ipv4_hdr->hdr_hdl;
+	ecm_ipa_ctx->eth_ipv6_hdr_hdl = ipv6_hdr->hdr_hdl;
 	ECM_IPA_LOG_EXIT();
 out_free_mem:
 	kfree(hdrs);
@@ -655,7 +696,14 @@
 	return result;
 }
 
-static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *dev)
+/**
+ * ecm_ipa_rules_destroy() - remove the IPA core configuration done for
+ *  the driver data path.
+ *  @ecm_ipa_ctx: the driver context
+ *
+ *  Revert the work done on ecm_ipa_rules_cfg.
+ */
+static void ecm_ipa_rules_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
 {
 	struct ipa_ioc_del_hdr *del_hdr;
 	struct ipa_hdr_del *ipv4;
@@ -668,9 +716,9 @@
 	del_hdr->commit = 1;
 	del_hdr->num_hdls = 2;
 	ipv4 = &del_hdr->hdl[0];
-	ipv4->hdl = dev->eth_ipv4_hdr_hdl;
+	ipv4->hdl = ecm_ipa_ctx->eth_ipv4_hdr_hdl;
 	ipv6 = &del_hdr->hdl[1];
-	ipv6->hdl = dev->eth_ipv6_hdr_hdl;
+	ipv6->hdl = ecm_ipa_ctx->eth_ipv6_hdr_hdl;
 	result = ipa_del_hdr(del_hdr);
 	if (result || ipv4->status || ipv6->status)
 		ECM_IPA_ERROR("ipa_del_hdr failed");
@@ -764,25 +812,25 @@
 static void ecm_ipa_rm_notify(void *user_data, enum ipa_rm_event event,
 		unsigned long data)
 {
-	struct ecm_ipa_dev *dev = user_data;
+	struct ecm_ipa_dev *ecm_ipa_ctx = user_data;
 	ECM_IPA_LOG_ENTRY();
 	if (event == IPA_RM_RESOURCE_GRANTED &&
-			netif_queue_stopped(dev->net)) {
+			netif_queue_stopped(ecm_ipa_ctx->net)) {
 		pr_debug("Resource Granted - waking queue\n");
-		netif_wake_queue(dev->net);
+		netif_wake_queue(ecm_ipa_ctx->net);
 	} else {
 		pr_debug("Resource released\n");
 	}
 	ECM_IPA_LOG_EXIT();
 }
 
-static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *dev)
+static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx)
 {
 	struct ipa_rm_create_params create_params = {0};
 	int result;
 	ECM_IPA_LOG_ENTRY();
 	create_params.name = IPA_RM_RESOURCE_STD_ECM_PROD;
-	create_params.reg_params.user_data = dev;
+	create_params.reg_params.user_data = ecm_ipa_ctx;
 	create_params.reg_params.notify_cb = ecm_ipa_rm_notify;
 	result = ipa_rm_create_resource(&create_params);
 	if (result) {
@@ -814,7 +862,7 @@
 	return result;
 }
 
-static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *dev)
+static void ecm_ipa_destory_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx)
 {
 	int result;
 
@@ -832,26 +880,26 @@
 
 static bool rx_filter(struct sk_buff *skb)
 {
-	struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
-	return !dev->rx_enable;
+	struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(skb->dev);
+	return !ecm_ipa_ctx->rx_enable;
 }
 
 static bool tx_filter(struct sk_buff *skb)
 {
-	struct ecm_ipa_dev *dev = netdev_priv(skb->dev);
-	return !dev->tx_enable;
+	struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(skb->dev);
+	return !ecm_ipa_ctx->tx_enable;
 }
 
-static bool rm_enabled(struct ecm_ipa_dev *dev)
+static bool rm_enabled(struct ecm_ipa_dev *ecm_ipa_ctx)
 {
-	return dev->rm_enable;
+	return ecm_ipa_ctx->rm_enable;
 }
 
-static int resource_request(struct ecm_ipa_dev *dev)
+static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx)
 {
 	int result = 0;
 
-	if (!rm_enabled(dev))
+	if (!rm_enabled(ecm_ipa_ctx))
 		goto out;
 	result = ipa_rm_inactivity_timer_request_resource(
 			IPA_RM_RESOURCE_STD_ECM_PROD);
@@ -859,9 +907,9 @@
 	return result;
 }
 
-static void resource_release(struct ecm_ipa_dev *dev)
+static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx)
 {
-	if (!rm_enabled(dev))
+	if (!rm_enabled(ecm_ipa_ctx))
 		goto out;
 	ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
 out:
@@ -883,22 +931,23 @@
 		unsigned long data)
 {
 	struct sk_buff *skb = (struct sk_buff *)data;
-	struct ecm_ipa_dev *dev = priv;
+	struct ecm_ipa_dev *ecm_ipa_ctx = priv;
 
-	if (!dev) {
-		ECM_IPA_ERROR("dev is NULL pointer\n");
+	if (!ecm_ipa_ctx) {
+		ECM_IPA_ERROR("ecm_ipa_ctx is NULL pointer\n");
 		return;
 	}
 	if (evt != IPA_WRITE_DONE) {
 		ECM_IPA_ERROR("unsupported event on Tx callback\n");
 		return;
 	}
-	atomic_dec(&dev->outstanding_pkts);
-	if (netif_queue_stopped(dev->net) &&
-		atomic_read(&dev->outstanding_pkts) < (dev->outstanding_low)) {
+	atomic_dec(&ecm_ipa_ctx->outstanding_pkts);
+	if (netif_queue_stopped(ecm_ipa_ctx->net) &&
+		atomic_read(&ecm_ipa_ctx->outstanding_pkts) <
+					(ecm_ipa_ctx->outstanding_low)) {
 		pr_debug("Outstanding low boundary reached (%d) - waking up queue\n",
-				dev->outstanding_low);
-		netif_wake_queue(dev->net);
+				ecm_ipa_ctx->outstanding_low);
+		netif_wake_queue(ecm_ipa_ctx->net);
 	}
 
 	dev_kfree_skb_any(skb);
@@ -907,9 +956,9 @@
 
 static int ecm_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
 {
-	struct ecm_ipa_dev *dev = inode->i_private;
+	struct ecm_ipa_dev *ecm_ipa_ctx = inode->i_private;
 	ECM_IPA_LOG_ENTRY();
-	file->private_data = &(dev->outstanding_pkts);
+	file->private_data = &(ecm_ipa_ctx->outstanding_pkts);
 	ECM_IPA_LOG_EXIT();
 	return 0;
 }
@@ -917,25 +966,25 @@
 static ssize_t ecm_ipa_debugfs_enable_write_dma(struct file *file,
 		const char __user *buf, size_t count, loff_t *ppos)
 {
-	struct ecm_ipa_dev *dev = file->private_data;
+	struct ecm_ipa_dev *ecm_ipa_ctx = file->private_data;
 	int result;
 	ECM_IPA_LOG_ENTRY();
-	file->private_data = &dev->dma_enable;
+	file->private_data = &ecm_ipa_ctx->dma_enable;
 	result = ecm_ipa_debugfs_enable_write(file, buf, count, ppos);
-	if (dev->dma_enable)
-		ecm_ipa_ep_registers_dma_cfg(dev->usb_to_ipa_hdl);
+	if (ecm_ipa_ctx->dma_enable)
+		ecm_ipa_ep_registers_dma_cfg(ecm_ipa_ctx->usb_to_ipa_hdl);
 	else
-		ecm_ipa_ep_registers_cfg(dev->usb_to_ipa_hdl,
-				dev->usb_to_ipa_hdl);
+		ecm_ipa_ep_registers_cfg(ecm_ipa_ctx->usb_to_ipa_hdl,
+				ecm_ipa_ctx->usb_to_ipa_hdl);
 	ECM_IPA_LOG_EXIT();
 	return result;
 }
 
 static int ecm_ipa_debugfs_dma_open(struct inode *inode, struct file *file)
 {
-	struct ecm_ipa_dev *dev = inode->i_private;
+	struct ecm_ipa_dev *ecm_ipa_ctx = inode->i_private;
 	ECM_IPA_LOG_ENTRY();
-	file->private_data = dev;
+	file->private_data = ecm_ipa_ctx;
 	ECM_IPA_LOG_EXIT();
 	return 0;
 }
@@ -997,7 +1046,7 @@
 }
 
 
-static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *dev)
+static int ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx)
 {
 	const mode_t flags_read_write = S_IRUGO | S_IWUGO;
 	const mode_t flags_read_only = S_IRUGO;
@@ -1005,52 +1054,54 @@
 
 	ECM_IPA_LOG_ENTRY();
 
-	if (!dev)
+	if (!ecm_ipa_ctx)
 		return -EINVAL;
 
-	dev->directory = debugfs_create_dir("ecm_ipa", NULL);
-	if (!dev->directory) {
+	ecm_ipa_ctx->directory = debugfs_create_dir("ecm_ipa", NULL);
+	if (!ecm_ipa_ctx->directory) {
 		ECM_IPA_ERROR("could not create debugfs directory entry\n");
 		goto fail_directory;
 	}
 	file = debugfs_create_bool("tx_enable", flags_read_write,
-			dev->directory, &dev->tx_enable);
+			ecm_ipa_ctx->directory, &ecm_ipa_ctx->tx_enable);
 	if (!file) {
 		ECM_IPA_ERROR("could not create debugfs tx file\n");
 		goto fail_file;
 	}
 	file = debugfs_create_bool("rx_enable", flags_read_write,
-			dev->directory, &dev->rx_enable);
+			ecm_ipa_ctx->directory, &ecm_ipa_ctx->rx_enable);
 	if (!file) {
 		ECM_IPA_ERROR("could not create debugfs rx file\n");
 		goto fail_file;
 	}
 	file = debugfs_create_bool("rm_enable", flags_read_write,
-			dev->directory, &dev->rm_enable);
+			ecm_ipa_ctx->directory, &ecm_ipa_ctx->rm_enable);
 	if (!file) {
 		ECM_IPA_ERROR("could not create debugfs rm file\n");
 		goto fail_file;
 	}
 	file = debugfs_create_u8("outstanding_high", flags_read_write,
-			dev->directory, &dev->outstanding_high);
+			ecm_ipa_ctx->directory, &ecm_ipa_ctx->outstanding_high);
 	if (!file) {
 		ECM_IPA_ERROR("could not create outstanding_high file\n");
 		goto fail_file;
 	}
 	file = debugfs_create_u8("outstanding_low", flags_read_write,
-			dev->directory, &dev->outstanding_low);
+			ecm_ipa_ctx->directory, &ecm_ipa_ctx->outstanding_low);
 	if (!file) {
 		ECM_IPA_ERROR("could not create outstanding_low file\n");
 		goto fail_file;
 	}
 	file = debugfs_create_file("dma_enable", flags_read_write,
-			dev->directory, dev, &ecm_ipa_debugfs_dma_ops);
+			ecm_ipa_ctx->directory,
+			ecm_ipa_ctx, &ecm_ipa_debugfs_dma_ops);
 	if (!file) {
 		ECM_IPA_ERROR("could not create debugfs dma file\n");
 		goto fail_file;
 	}
 	file = debugfs_create_file("outstanding", flags_read_only,
-			dev->directory, dev, &ecm_ipa_debugfs_atomic_ops);
+			ecm_ipa_ctx->directory,
+			ecm_ipa_ctx, &ecm_ipa_debugfs_atomic_ops);
 	if (!file) {
 		ECM_IPA_ERROR("could not create outstanding file\n");
 		goto fail_file;
@@ -1060,14 +1111,14 @@
 
 	return 0;
 fail_file:
-	debugfs_remove_recursive(dev->directory);
+	debugfs_remove_recursive(ecm_ipa_ctx->directory);
 fail_directory:
 	return -EFAULT;
 }
 
-static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *dev)
+static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx)
 {
-	debugfs_remove_recursive(dev->directory);
+	debugfs_remove_recursive(ecm_ipa_ctx->directory);
 }
 
 /**
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index fe151b5..acd42ae3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -107,4 +107,10 @@
 	help
 	  OpenFirmware SLIMBUS accessors
 
+config OF_CORESIGHT
+	def_bool y
+	depends on CORESIGHT
+	help
+	  OpenFirmware CoreSight accessors
+
 endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index c3a31c8..61a99f2 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -15,3 +15,4 @@
 obj-$(CONFIG_OF_SPMI)	+= of_spmi.o
 obj-$(CONFIG_OF_MTD)	+= of_mtd.o
 obj-$(CONFIG_OF_SLIMBUS)	+= of_slimbus.o
+obj-$(CONFIG_OF_CORESIGHT) += of_coresight.o
diff --git a/drivers/coresight/of_coresight.c b/drivers/of/of_coresight.c
similarity index 100%
rename from drivers/coresight/of_coresight.c
rename to drivers/of/of_coresight.c
diff --git a/drivers/platform/msm/ipa/ipa_bridge.c b/drivers/platform/msm/ipa/ipa_bridge.c
index 3ff604c..919a119 100644
--- a/drivers/platform/msm/ipa/ipa_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_bridge.c
@@ -12,7 +12,7 @@
 
 #include <linux/delay.h>
 #include <linux/ratelimit.h>
-#include <mach/msm_smsm.h>
+#include <mach/msm_smem.h>
 #include "ipa_i.h"
 
 /*
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 64e8d7a..fc85dba 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -129,15 +129,40 @@
 	[HSIC_BAM]  = hsic_cons_release_resource,
 };
 
-static enum ipa_rm_event cur_prod_state[MAX_BAMS];
-static enum ipa_rm_event cur_cons_state[MAX_BAMS];
-static int sched_lpm;
-static int lpm_wait_handshake;
-static struct completion prod_avail[MAX_BAMS];
-static struct completion cons_avail[MAX_BAMS];
-static struct completion cons_released[MAX_BAMS];
-static struct completion prod_released[MAX_BAMS];
+struct usb_bam_ipa_handshake_info {
+	enum ipa_rm_event cur_prod_state[MAX_BAMS];
+	enum ipa_rm_event cur_cons_state[MAX_BAMS];
 
+	int lpm_wait_handshake;
+	int connect_complete;
+	bool lpm_wait_pipes;
+	int bus_suspend;
+	bool in_lpm;
+
+	int (*wake_cb)(void *);
+	void *wake_param;
+	void (*start)(void *, enum usb_bam_pipe_dir);
+	void (*stop)(void *, enum usb_bam_pipe_dir);
+	void *start_stop_param;
+
+	u32 src_idx;
+	u32 dst_idx;
+	bool cons_stopped;
+	bool prod_stopped;
+
+	struct completion prod_avail[MAX_BAMS];
+	struct completion cons_avail[MAX_BAMS];
+	struct completion cons_released[MAX_BAMS];
+	struct completion prod_released[MAX_BAMS];
+
+	struct mutex suspend_resume_mutex;
+	struct work_struct resume_work;
+	struct work_struct suspend_work;
+	struct work_struct finish_suspend_work;
+};
+
+static spinlock_t usb_bam_ipa_handshake_info_lock;
+static struct usb_bam_ipa_handshake_info info;
 static spinlock_t usb_bam_peer_handshake_info_lock;
 static struct usb_bam_peer_handshake_info peer_handshake_info;
 static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
@@ -457,6 +482,7 @@
 		pr_err("%s: ipa_connect failed\n", __func__);
 		return ret;
 	}
+	pipe_connect->ipa_clnt_hdl = clnt_hdl;
 
 	*pipe = sps_alloc_endpoint();
 	if (*pipe == NULL) {
@@ -579,6 +605,31 @@
 	return 0;
 }
 
+static void usb_bam_resume_core(enum usb_bam cur_bam)
+{
+	struct usb_phy *trans = usb_get_transceiver();
+
+	if (cur_bam != HSUSB_BAM)
+		return;
+	BUG_ON(trans == NULL);
+	pr_debug("%s: resume core", __func__);
+	pm_runtime_resume(trans->dev);
+}
+
+static void usb_bam_start_lpm(bool disconnect)
+{
+	struct usb_phy *trans = usb_get_transceiver();
+	BUG_ON(trans == NULL);
+		pr_debug("%s: Going to LPM\n", __func__);
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	info.lpm_wait_handshake = false;
+		info.lpm_wait_pipes = 0;
+	if (disconnect)
+		pm_runtime_put_noidle(trans->dev);
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+	pm_runtime_suspend(trans->dev);
+}
+
 int usb_bam_connect(u8 idx, u32 *bam_pipe_idx)
 {
 	int ret;
@@ -608,26 +659,136 @@
 	}
 
 	spin_lock(&usb_bam_lock);
-
 	/* Check if BAM requires RESET before connect and reset of first pipe */
 	if ((pdata->reset_on_connect[pipe_connect->bam_type] == true) &&
 	    (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0))
 		sps_device_reset(ctx.h_bam[pipe_connect->bam_type]);
+	spin_unlock(&usb_bam_lock);
 
 	ret = connect_pipe(idx, bam_pipe_idx);
 	if (ret) {
 		pr_err("%s: pipe connection[%d] failure\n", __func__, idx);
-		spin_unlock(&usb_bam_lock);
 		return ret;
 	}
 
 	pipe_connect->enabled = 1;
+	spin_lock(&usb_bam_lock);
 	ctx.pipes_enabled_per_bam[pipe_connect->bam_type] += 1;
-
 	spin_unlock(&usb_bam_lock);
+
 	return 0;
 }
 
+static int ipa_suspend_pipes(void)
+{
+	struct usb_bam_pipe_connect *dst_pipe_connect, *src_pipe_connect;
+	int ret1, ret2;
+
+	dst_pipe_connect = &usb_bam_connections[info.dst_idx];
+	src_pipe_connect = &usb_bam_connections[info.src_idx];
+
+	if (dst_pipe_connect->ipa_clnt_hdl == -1 ||
+		src_pipe_connect->ipa_clnt_hdl == -1) {
+		pr_err("%s: One of handles is -1, not connected?", __func__);
+	}
+
+	ret1 = ipa_suspend(dst_pipe_connect->ipa_clnt_hdl);
+	if (ret1)
+		pr_err("%s: ipa_suspend on dst failed with %d", __func__, ret1);
+	ret2 = ipa_suspend(src_pipe_connect->ipa_clnt_hdl);
+	if (ret2)
+		pr_err("%s: ipa_suspend on src failed with %d", __func__, ret2);
+
+	return ret1 | ret2;
+}
+
+static int ipa_resume_pipes(void)
+{
+	struct usb_bam_pipe_connect *dst_pipe_connect, *src_pipe_connect;
+	int ret1, ret2;
+
+	src_pipe_connect = &usb_bam_connections[info.src_idx];
+	dst_pipe_connect = &usb_bam_connections[info.dst_idx];
+
+	if (dst_pipe_connect->ipa_clnt_hdl == -1 ||
+		src_pipe_connect->ipa_clnt_hdl == -1) {
+		pr_err("%s: One of handles is -1, not connected?", __func__);
+	}
+
+	ret1 = ipa_resume(dst_pipe_connect->ipa_clnt_hdl);
+	if (ret1)
+		pr_err("%s: ipa_resume on dst failed with %d", __func__, ret1);
+	ret2 = ipa_resume(src_pipe_connect->ipa_clnt_hdl);
+	if (ret2)
+		pr_err("%s: ipa_resume on src failed with %d", __func__, ret2);
+
+	return ret1 | ret2;
+}
+
+static void usb_bam_finish_suspend(void)
+{
+	int ret;
+	u32 cons_empty;
+	struct sps_pipe *cons_pipe = ctx.usb_bam_sps.sps_pipes[info.dst_idx];
+	struct usb_bam_pipe_connect *pipe_connect = &
+			usb_bam_connections[info.dst_idx];
+	enum usb_bam cur_bam = pipe_connect->bam_type;
+
+	if (cur_bam != HSUSB_BAM) {
+		pr_err("%s: Wrong type of BAM=%s\n", __func__,
+			bam_enable_strings[cur_bam]);
+		return;
+	}
+
+	mutex_lock(&info.suspend_resume_mutex);
+
+	/* If resume was called don't finish this work */
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	if (!info.bus_suspend) {
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		pr_err("%s: Bus suspend in progress\n", __func__);
+		goto no_lpm;
+	}
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+	ret = sps_is_pipe_empty(cons_pipe, &cons_empty);
+	if (ret) {
+		pr_err("%s: sps_is_pipe_empty failed with %d\n", __func__, ret);
+		goto no_lpm;
+	}
+
+	/* Stop CONS transfers and go to lpm if no more data in the pipe */
+	if (cons_empty) {
+		if (info.stop && !info.cons_stopped)
+			info.stop(info.start_stop_param,
+					PEER_PERIPHERAL_TO_USB);
+		pr_err("%s: Starting LPM on Bus Suspend\n", __func__);
+		info.cons_stopped = 1;
+		if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED) {
+			ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+				ipa_rm_resource_cons[cur_bam]);
+		}
+		ipa_suspend_pipes();
+		mutex_unlock(&info.suspend_resume_mutex);
+		usb_bam_start_lpm(0);
+		return;
+	}
+
+no_lpm:
+
+	/* Finish the handshake. Resume Sequence will start automatically
+	   by the data in the pipes */
+	if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+		ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
+				ipa_rm_resource_cons[cur_bam]);
+	mutex_unlock(&info.suspend_resume_mutex);
+}
+
+void usb_bam_finish_suspend_(struct work_struct *w)
+{
+	usb_bam_finish_suspend();
+}
+
 static void usb_prod_notify_cb(void *user_data, enum ipa_rm_event event,
 	unsigned long data)
 {
@@ -637,14 +798,14 @@
 	case IPA_RM_RESOURCE_GRANTED:
 		pr_debug("%s: %s_PROD resource granted\n",
 			__func__, bam_enable_strings[*cur_bam]);
-		cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
-		complete_all(&prod_avail[*cur_bam]);
+		info.cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_GRANTED;
+		complete_all(&info.prod_avail[*cur_bam]);
 		break;
 	case IPA_RM_RESOURCE_RELEASED:
 		pr_debug("%s: %s_PROD resource released\n",
 			__func__, bam_enable_strings[*cur_bam]);
-		cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
-		complete_all(&prod_released[*cur_bam]);
+		info.cur_prod_state[*cur_bam] = IPA_RM_RESOURCE_RELEASED;
+		complete_all(&info.prod_released[*cur_bam]);
 		break;
 	default:
 		break;
@@ -657,12 +818,33 @@
 	pr_debug("%s: Request %s_CONS resource\n",
 			__func__, bam_enable_strings[cur_bam]);
 
-	cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
-	complete_all(&cons_avail[cur_bam]);
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+	complete_all(&info.cons_avail[cur_bam]);
 
-	if (ctx.pipes_enabled_per_bam[cur_bam])
+	spin_lock(&usb_bam_lock);
+	if (ctx.pipes_enabled_per_bam[cur_bam] && info.connect_complete &&
+				!info.bus_suspend && !info.prod_stopped) {
+		spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		pr_debug("%s: ACK on cons_request", __func__);
 		return 0;
+	}
 
+	/* A2 wakeup from LPM */
+	if (cur_bam == HSUSB_BAM && ctx.pipes_enabled_per_bam[cur_bam] &&
+		info.connect_complete && info.bus_suspend) {
+		info.bus_suspend = 0;
+		spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		if (info.wake_cb)
+			info.wake_cb(info.wake_param);
+	} else {
+		spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+	}
+
+	pr_debug("%s: EINPROGRESS on cons_request", __func__);
 	return -EINPROGRESS;
 }
 
@@ -681,12 +863,23 @@
 	pr_debug("%s: Release %s_CONS resource\n",
 			__func__, bam_enable_strings[cur_bam]);
 
-	cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
-	complete_all(&cons_released[cur_bam]);
+	info.cur_cons_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+	complete_all(&info.cons_released[cur_bam]);
 
-	if (!ctx.pipes_enabled_per_bam[cur_bam])
+	spin_lock(&usb_bam_lock);
+	if (!ctx.pipes_enabled_per_bam[cur_bam]) {
+		spin_unlock(&usb_bam_lock);
+		pr_debug("%s: ACK on cons_release", __func__);
 		return 0;
+	}
+	spin_unlock(&usb_bam_lock);
 
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	if (cur_bam == HSUSB_BAM && info.bus_suspend)
+		queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+	pr_debug("%s: EINPROGRESS cons_release", __func__);
 	return -EINPROGRESS;
 }
 
@@ -747,24 +940,24 @@
 
 	pr_debug("%s Request %s_PROD_RES\n", __func__,
 		bam_enable_strings[cur_bam]);
-	if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+	if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
 		pr_debug("%s: CONS already granted for some reason\n",
 			__func__);
-	if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
+	if (info.cur_prod_state[cur_bam] == IPA_RM_RESOURCE_GRANTED)
 		pr_debug("%s: PROD already granted for some reason\n",
 			__func__);
 
-	init_completion(&prod_avail[cur_bam]);
-	init_completion(&cons_avail[cur_bam]);
+	init_completion(&info.prod_avail[cur_bam]);
+	init_completion(&info.cons_avail[cur_bam]);
 
 	ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
 	if (!ret) {
-		cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
-		complete_all(&prod_avail[cur_bam]);
+		info.cur_prod_state[cur_bam] = IPA_RM_RESOURCE_GRANTED;
+		complete_all(&info.prod_avail[cur_bam]);
 		pr_debug("%s: PROD_GRANTED without wait\n", __func__);
 	} else if (ret == -EINPROGRESS) {
 		pr_debug("%s: Waiting for PROD_GRANTED\n", __func__);
-		if (!wait_for_completion_timeout(&prod_avail[cur_bam],
+		if (!wait_for_completion_timeout(&info.prod_avail[cur_bam],
 			USB_BAM_TIMEOUT))
 			pr_err("%s: Timeout wainting for PROD_GRANTED\n",
 				__func__);
@@ -772,6 +965,261 @@
 		pr_err("%s: ipa_rm_request_resource ret =%d\n", __func__, ret);
 }
 
+void wait_for_cons_granted(enum usb_bam cur_bam)
+{
+	pr_debug("%s: Waiting for CONS\n", __func__);
+	if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_GRANTED) {
+		if (!wait_for_completion_timeout(&info.cons_avail[cur_bam],
+						USB_BAM_TIMEOUT*6))
+			pr_err("%s: Timeout wainting for CONS_REQUEST\n",
+			__func__);
+		pr_err("%s: Finished waiting for CONS\n", __func__);
+	}
+
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	info.connect_complete = 1;
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+	pr_debug("%s: CONS is granted\n", __func__);
+
+	if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
+		pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+		ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+				 ipa_rm_resource_cons[HSUSB_BAM]);
+	}
+}
+
+void usb_bam_wait_for_cons_granted(
+	struct usb_bam_connect_ipa_params *ipa_params)
+{
+	struct usb_bam_pipe_connect *pipe_connect;
+	enum usb_bam cur_bam;
+	u8 src_idx;
+
+	src_idx = ipa_params->src_idx;
+	pipe_connect = &usb_bam_connections[src_idx];
+	cur_bam = pipe_connect->bam_type;
+
+	wait_for_cons_granted(cur_bam);
+}
+
+static void wait_for_prod_release(enum usb_bam cur_bam)
+{
+	int ret;
+
+	if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+		pr_debug("%s consumer already released\n", __func__);
+	 if (info.cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+		pr_debug("%s producer already released\n", __func__);
+
+	init_completion(&info.prod_released[cur_bam]);
+	init_completion(&info.cons_released[cur_bam]);
+	pr_debug("%s: Releasing %s_PROD\n", __func__,
+				bam_enable_strings[cur_bam]);
+	ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
+	if (!ret) {
+		pr_debug("%s: Released without waiting\n", __func__);
+		info.cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
+		complete_all(&info.prod_released[cur_bam]);
+	} else if (ret == -EINPROGRESS) {
+		pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
+		if (!wait_for_completion_timeout(&info.prod_released[cur_bam],
+						USB_BAM_TIMEOUT))
+			pr_err("%s: Timeout waiting for PROD_RELEASED\n",
+			__func__);
+	} else
+		pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
+}
+
+static int check_pipes_empty(u8 src_idx, u8 dst_idx)
+{
+	struct sps_pipe *prod_pipe, *cons_pipe;
+	u32 prod_empty, cons_empty;
+
+	/* If we have any remaints in the pipes we don't go to sleep */
+	prod_pipe = ctx.usb_bam_sps.sps_pipes[src_idx];
+	cons_pipe = ctx.usb_bam_sps.sps_pipes[dst_idx];
+	if (sps_is_pipe_empty(prod_pipe, &prod_empty) ||
+			sps_is_pipe_empty(cons_pipe, &cons_empty)) {
+		pr_err("%s: sps_is_pipe_empty failed with\n", __func__);
+		return 0;
+	}
+	if (!prod_empty || !cons_empty) {
+		pr_err("%s: pipes not empty prod=%d cond=%d", __func__,
+			prod_empty, cons_empty);
+		return 0;
+	}
+
+	return 1;
+}
+
+void usb_bam_suspend(struct usb_bam_connect_ipa_params *ipa_params)
+{
+	struct usb_bam_pipe_connect *pipe_connect;
+	enum usb_bam cur_bam;
+	u8 src_idx, dst_idx;
+
+	if (!ipa_params) {
+		pr_err("%s: Invalid ipa params\n", __func__);
+		return;
+	}
+
+	src_idx = ipa_params->src_idx;
+	dst_idx = ipa_params->dst_idx;
+
+	if (src_idx >= ctx.max_connections || dst_idx >= ctx.max_connections) {
+		pr_err("%s: Invalid connection index src=%d dst=%d\n",
+			__func__, src_idx, dst_idx);
+	}
+
+	pipe_connect = &usb_bam_connections[src_idx];
+	cur_bam = pipe_connect->bam_type;
+	if (cur_bam != HSUSB_BAM)
+		return;
+
+	info.src_idx = src_idx;
+	info.dst_idx = dst_idx;
+
+	pr_err("%s: Starting suspend sequence(BAM=%s)\n", __func__,
+			bam_enable_strings[cur_bam]);
+
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	info.bus_suspend = 1;
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+	/* Stop PROD transfers */
+	if (info.stop) {
+		spin_lock(&usb_bam_ipa_handshake_info_lock);
+		info.stop(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+		info.prod_stopped = true;
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+	}
+
+	/* Don't go to LPM if data in the pipes */
+	if (!check_pipes_empty(src_idx, dst_idx)) {
+		pr_err("%s: pipes not empty, won't start suspend", __func__);
+		return;
+	}
+
+	queue_work(ctx.usb_bam_wq, &info.suspend_work);
+}
+
+static void usb_bam_start_suspend(struct work_struct *w)
+{
+	pr_debug("%s: enter", __func__);
+	mutex_lock(&info.suspend_resume_mutex);
+
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	if (!info.bus_suspend) {
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		pr_err("%s: Resume started, not suspending", __func__);
+		return;
+	}
+
+	/* Stop PROD transfers in case they were started */
+	if (info.stop && !info.prod_stopped) {
+		info.stop(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+		info.prod_stopped = true;
+	}
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+	/* Don't start LPM seq if data in the pipes */
+	if (!check_pipes_empty(info.src_idx, info.dst_idx)) {
+		mutex_unlock(&info.suspend_resume_mutex);
+		return;
+	}
+
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	info.lpm_wait_handshake = true;
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+	wait_for_prod_release(HSUSB_BAM);
+
+	mutex_unlock(&info.suspend_resume_mutex);
+	if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_RELEASED)
+		usb_bam_finish_suspend();
+	else
+		pr_debug("Consumer not released yet\n");
+}
+
+static void usb_bam_finish_resume(struct work_struct *w)
+{
+	struct usb_phy *trans = usb_get_transceiver();
+
+	BUG_ON(trans == NULL);
+	pr_debug("%s: enter", __func__);
+	mutex_lock(&info.suspend_resume_mutex);
+	/* Suspend happened in the meantime */
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	if (info.bus_suspend) {
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		pr_err("%s: Bus suspended, not resuming", __func__);
+		mutex_unlock(&info.suspend_resume_mutex);
+		return;
+	}
+	info.lpm_wait_handshake = true;
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+	wait_for_prod_granted(HSUSB_BAM);
+	wait_for_cons_granted(HSUSB_BAM);
+	if (info.cons_stopped) {
+		ipa_resume_pipes();
+		if (info.start) {
+			pr_debug("%s: Enqueue CONS transfer", __func__);
+			info.start(info.start_stop_param,
+				PEER_PERIPHERAL_TO_USB);
+			info.cons_stopped = 0;
+		}
+	}
+
+	if (info.start) {
+		spin_lock(&usb_bam_ipa_handshake_info_lock);
+		info.start(info.start_stop_param, USB_TO_PEER_PERIPHERAL);
+		info.prod_stopped = false;
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
+	}
+	if (info.cur_cons_state[HSUSB_BAM] == IPA_RM_RESOURCE_GRANTED) {
+		pr_debug("%s: Notify CONS_GRANTED\n", __func__);
+		ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+				 ipa_rm_resource_cons[HSUSB_BAM]);
+	}
+	mutex_unlock(&info.suspend_resume_mutex);
+	pr_debug("%s: done", __func__);
+}
+
+void usb_bam_resume(struct usb_bam_connect_ipa_params *ipa_params)
+{
+	enum usb_bam cur_bam;
+	u8 src_idx, dst_idx;
+	struct usb_bam_pipe_connect *pipe_connect;
+
+	pr_debug("%s: Resuming\n", __func__);
+
+	if (!ipa_params) {
+		pr_err("%s: Invalid ipa params\n", __func__);
+		return;
+	}
+
+	src_idx = ipa_params->src_idx;
+	dst_idx = ipa_params->dst_idx;
+
+	if (src_idx >= ctx.max_connections || dst_idx >= ctx.max_connections) {
+		pr_err("%s: Invalid connection index src=%d dst=%d\n",
+			__func__, src_idx, dst_idx);
+		return;
+	}
+
+	pipe_connect = &usb_bam_connections[src_idx];
+	cur_bam = pipe_connect->bam_type;
+	if (cur_bam != HSUSB_BAM)
+		return;
+
+	info.in_lpm = false;
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	info.bus_suspend = 0;
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+	queue_work(ctx.usb_bam_wq, &info.resume_work);
+}
+
 int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
 {
 	u8 idx;
@@ -800,27 +1248,38 @@
 	pipe_connect = &usb_bam_connections[idx];
 	cur_bam = pipe_connect->bam_type;
 
-	if (cur_bam == HSUSB_BAM) {
-		spin_lock(&usb_bam_lock);
-		sched_lpm = 0;
-		lpm_wait_handshake = 1;
-		spin_unlock(&usb_bam_lock);
-	}
-
 	if (pipe_connect->enabled) {
-		pr_debug("%s: connection %d was already established\n",
+		pr_err("%s: connection %d was already established\n",
 			__func__, idx);
 		return 0;
 	}
 
+	pr_debug("%s: enter", __func__);
+	mutex_lock(&info.suspend_resume_mutex);
+
 	spin_lock(&usb_bam_lock);
+	if (ctx.pipes_enabled_per_bam[cur_bam] == 0) {
+		spin_unlock(&usb_bam_lock);
+		if (cur_bam == HSUSB_BAM) {
+			spin_lock(&usb_bam_ipa_handshake_info_lock);
+			info.lpm_wait_handshake = 1;
+			info.connect_complete = 0;
+			info.lpm_wait_pipes = 1;
+			info.bus_suspend = 0;
+			info.cons_stopped = 0;
+			info.prod_stopped = 0;
+			spin_unlock(&usb_bam_ipa_handshake_info_lock);
+		}
+		usb_bam_resume_core(cur_bam);
+	} else
+		spin_unlock(&usb_bam_lock);
 
 	 /* Check if BAM requires RESET before connect and reset first pipe */
+	 spin_lock(&usb_bam_lock);
 	 if ((pdata->reset_on_connect[cur_bam] == true) &&
 		 (ctx.pipes_enabled_per_bam[cur_bam] == 0))
 			sps_device_reset(ctx.h_bam[cur_bam]);
-
-	spin_unlock(&usb_bam_lock);
+		spin_unlock(&usb_bam_lock);
 
 	if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
 		pr_debug("%s: Starting connect sequence\n", __func__);
@@ -830,23 +1289,19 @@
 	ret = connect_pipe_ipa(idx, ipa_params);
 	if (ret) {
 		pr_err("%s: pipe connection failure\n", __func__);
+		mutex_unlock(&info.suspend_resume_mutex);
 		return ret;
 	}
 
 	spin_lock(&usb_bam_lock);
-
 	pipe_connect->enabled = 1;
 	ctx.pipes_enabled_per_bam[cur_bam] += 1;
-
-	if (ipa_params->dir == PEER_PERIPHERAL_TO_USB &&
-		cur_cons_state[cur_bam] == IPA_RM_RESOURCE_GRANTED) {
-		pr_debug("%s: Notify CONS_GRANTED\n", __func__);
-		ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
-					 ipa_rm_resource_cons[cur_bam]);
-		pr_debug("%s: Ended connect sequence\n", __func__);
-	}
-
 	spin_unlock(&usb_bam_lock);
+	if (ipa_params->dir == PEER_PERIPHERAL_TO_USB && cur_bam == HSUSB_BAM)
+		wait_for_cons_granted(cur_bam);
+
+	mutex_unlock(&info.suspend_resume_mutex);
+	pr_debug("%s: done", __func__);
 
 	return 0;
 }
@@ -904,6 +1359,14 @@
 			usb_bam_set_inactivity_timer(pipe_connect->bam_type);
 		spin_unlock(&usb_bam_lock);
 
+		/* A2 wakeup not from LPM (CONS was up) */
+		wait_for_prod_granted(pipe_connect->bam_type);
+		if (info.start) {
+			pr_debug("%s: Enqueue PROD transfer", __func__);
+			info.start(info.start_stop_param,
+					USB_TO_PEER_PERIPHERAL);
+		}
+
 		break;
 
 	case USB_BAM_EVENT_INACTIVITY:
@@ -1111,9 +1574,22 @@
 int usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
 	void *param)
 {
+	info.wake_cb = callback;
+	info.wake_param = param;
 	return __usb_bam_register_wake_cb(idx, callback, param, true);
 }
 
+int usb_bam_register_start_stop_cbs(
+	void (*start)(void *, enum usb_bam_pipe_dir),
+	void (*stop)(void *, enum usb_bam_pipe_dir),
+	void *param)
+{
+	info.start = start;
+	info.stop = stop;
+	info.start_stop_param = param;
+	return 0;
+}
+
 int usb_bam_register_peer_reset_cb(int (*callback)(void *), void *param)
 {
 	u32 ret = 0;
@@ -1156,78 +1632,29 @@
 		return 0;
 	}
 
-	spin_lock(&usb_bam_lock);
-
 	ret = disconnect_pipe(idx);
 	if (ret) {
 		pr_err("%s: src pipe disconnection failure\n", __func__);
-		spin_unlock(&usb_bam_lock);
 		return ret;
 	}
 
 	pipe_connect->enabled = 0;
-
+	spin_lock(&usb_bam_lock);
 	if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0)
 		pr_err("%s: wrong pipes enabled counter for bam_type=%d\n",
 			__func__, pipe_connect->bam_type);
 	else
 		ctx.pipes_enabled_per_bam[pipe_connect->bam_type] -= 1;
-
 	spin_unlock(&usb_bam_lock);
 
 	return 0;
 }
 
-static void usb_bam_start_lpm(void)
-{
-	struct usb_phy *trans = usb_get_transceiver();
-	BUG_ON(trans == NULL);
-	spin_lock(&usb_bam_lock);
-	lpm_wait_handshake = 0;
-	if (sched_lpm) {
-		pr_debug("%s: Going to LPM\n", __func__);
-		spin_unlock(&usb_bam_lock);
-		pm_runtime_resume(trans->dev);
-		pm_runtime_put_noidle(trans->dev);
-		pm_runtime_suspend(trans->dev);
-		return;
-	}
-	spin_unlock(&usb_bam_lock);
-}
-
-static void wait_for_prod_release(enum usb_bam cur_bam)
-{
-	int ret;
-
-	if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
-		pr_debug("%s consumer already released\n", __func__);
-	 if (cur_prod_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
-		pr_debug("%s producer already released\n", __func__);
-
-	init_completion(&prod_released[cur_bam]);
-	init_completion(&cons_released[cur_bam]);
-	pr_debug("%s: Releasing %s_PROD\n", __func__,
-				bam_enable_strings[cur_bam]);
-	ret = ipa_rm_release_resource(ipa_rm_resource_prod[cur_bam]);
-	if (!ret) {
-		pr_debug("%s: Released without waiting\n", __func__);
-		cur_prod_state[cur_bam] = IPA_RM_RESOURCE_RELEASED;
-		complete_all(&prod_released[cur_bam]);
-	} else if (ret == -EINPROGRESS) {
-		pr_debug("%s: Waiting for PROD_RELEASED\n", __func__);
-		if (!wait_for_completion_timeout(&prod_released[cur_bam],
-						USB_BAM_TIMEOUT))
-			pr_err("%s: Timeout waiting for PROD_RELEASED\n",
-			__func__);
-	} else
-		pr_err("%s: ipa_rm_request_resource ret =%d", __func__, ret);
-}
-
 static void wait_for_cons_release(enum usb_bam cur_bam)
 {
 	 pr_debug("%s: Waiting for CONS release\n", __func__);
-	 if (cur_prod_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
-		if (!wait_for_completion_timeout(&cons_released[cur_bam],
+	 if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_RELEASED) {
+		if (!wait_for_completion_timeout(&info.cons_released[cur_bam],
 						  USB_BAM_TIMEOUT))
 			pr_err("%s: Timeout wainting for CONS_RELEASE\n",
 				__func__);
@@ -1244,13 +1671,17 @@
 	struct sps_connect *sps_connection;
 	enum usb_bam cur_bam;
 
-
 	if (!ipa_params->prod_clnt_hdl && !ipa_params->cons_clnt_hdl) {
 		pr_err("%s: Both of the handles is missing\n", __func__);
 		return -EINVAL;
 	}
 
 	pr_debug("%s: Starting disconnect sequence\n", __func__);
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	info.connect_complete = 0;
+	spin_unlock(&usb_bam_ipa_handshake_info_lock);
+
+	mutex_lock(&info.suspend_resume_mutex);
 	/* Delay USB core to go into lpm before we finish our handshake */
 	if (ipa_params->prod_clnt_hdl) {
 		idx = ipa_params->dst_idx;
@@ -1258,12 +1689,15 @@
 
 		/* Do the release handshake with the A2 via RM */
 		cur_bam = pipe_connect->bam_type;
+		info.lpm_wait_pipes = 1;
 		wait_for_prod_release(cur_bam);
 		/* close USB -> IPA pipe */
+		usb_bam_resume_core(cur_bam);
 		ret = ipa_disconnect(ipa_params->prod_clnt_hdl);
 		if (ret) {
 			pr_err("%s: dst pipe disconnection failure\n",
 				__func__);
+			mutex_unlock(&info.suspend_resume_mutex);
 			return ret;
 		}
 		sps_connection = &ctx.usb_bam_sps.sps_connections[idx];
@@ -1274,6 +1708,7 @@
 		if (ret) {
 			pr_err("%s: failure to disconnect pipe %d\n",
 				__func__, idx);
+			mutex_unlock(&info.suspend_resume_mutex);
 			return ret;
 		}
 	}
@@ -1288,6 +1723,7 @@
 		if (ret) {
 			pr_err("%s: src pipe disconnection failure\n",
 				__func__);
+			mutex_unlock(&info.suspend_resume_mutex);
 			return ret;
 		}
 
@@ -1299,17 +1735,24 @@
 		if (ret) {
 			pr_err("%s: failure to disconnect pipe %d\n",
 				__func__, idx);
+			mutex_unlock(&info.suspend_resume_mutex);
 			return ret;
 		}
-		pr_debug("%s: Notify CONS release\n", __func__);
 
-		if (cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED)
+		pipe_connect->ipa_clnt_hdl = -1;
+
+		if (info.cur_cons_state[cur_bam] == IPA_RM_RESOURCE_RELEASED) {
+			pr_debug("%s Notify CONS _RELEASED\n", __func__);
 			ipa_rm_notify_completion(IPA_RM_RESOURCE_RELEASED,
 				ipa_rm_resource_cons[cur_bam]);
+		}
 		pr_debug("%s Ended disconnect sequence\n", __func__);
-		usb_bam_start_lpm();
+		mutex_unlock(&info.suspend_resume_mutex);
+		usb_bam_start_lpm(1);
+		return 0;
 	}
 
+	mutex_unlock(&info.suspend_resume_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(usb_bam_disconnect_ipa);
@@ -1810,18 +2253,23 @@
 		ctx.pipes_enabled_per_bam[i] = 0;
 		ctx.inactivity_timer_ms[i] = 0;
 		ctx.is_bam_inactivity[i] = false;
-		init_completion(&prod_avail[i]);
-		complete(&prod_avail[i]);
-		init_completion(&cons_avail[i]);
-		complete(&cons_avail[i]);
-		init_completion(&cons_released[i]);
-		complete(&cons_released[i]);
-		init_completion(&prod_released[i]);
-		complete(&prod_released[i]);
-		cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
-		cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+		init_completion(&info.prod_avail[i]);
+		complete(&info.prod_avail[i]);
+		init_completion(&info.cons_avail[i]);
+		complete(&info.cons_avail[i]);
+		init_completion(&info.cons_released[i]);
+		complete(&info.cons_released[i]);
+		init_completion(&info.prod_released[i]);
+		complete(&info.prod_released[i]);
+		info.cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
+		info.cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
 	}
 
+	INIT_WORK(&info.resume_work, usb_bam_finish_resume);
+	INIT_WORK(&info.suspend_work, usb_bam_start_suspend);
+	INIT_WORK(&info.finish_suspend_work, usb_bam_finish_suspend_);
+	mutex_init(&info.suspend_resume_mutex);
+
 	spin_lock_init(&usb_bam_peer_handshake_info_lock);
 	INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
 
@@ -1837,8 +2285,8 @@
 		destroy_workqueue(ctx.usb_bam_wq);
 		return ret;
 	}
+	spin_lock_init(&usb_bam_ipa_handshake_info_lock);
 	usb_bam_ipa_create_resources();
-
 	spin_lock_init(&usb_bam_lock);
 
 	return ret;
@@ -1911,14 +2359,14 @@
 
 bool msm_bam_lpm_ok(void)
 {
-	spin_lock(&usb_bam_lock);
-	if (lpm_wait_handshake) {
-		sched_lpm = 1;
-		spin_unlock(&usb_bam_lock);
+	spin_lock(&usb_bam_ipa_handshake_info_lock);
+	if (info.lpm_wait_handshake || info.lpm_wait_pipes) {
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 		pr_err("%s: Scheduling LPM for later\n", __func__);
 		return 0;
 	} else {
-		spin_unlock(&usb_bam_lock);
+		info.in_lpm = 1;
+		spin_unlock(&usb_bam_ipa_handshake_info_lock);
 		pr_err("%s: Going to LPM now\n", __func__);
 		return 1;
 	}
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index 5313593..c53bcd2 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -790,6 +790,15 @@
 	return 0;
 }
 
+static int pm8xxx_ccadc_suspend(struct device *dev)
+{
+	struct pm8xxx_ccadc_chip *chip = dev_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&chip->calib_ccadc_work);
+
+	return 0;
+}
+
 #define CCADC_CALIB_TEMP_THRESH 20
 static int pm8xxx_ccadc_resume(struct device *dev)
 {
@@ -823,8 +832,11 @@
 				|| delta_temp > CCADC_CALIB_TEMP_THRESH) {
 			the_chip->last_calib_time = current_time_sec;
 			the_chip->last_calib_temp = batt_temp;
-			cancel_delayed_work(&the_chip->calib_ccadc_work);
 			schedule_delayed_work(&the_chip->calib_ccadc_work, 0);
+		} else {
+			schedule_delayed_work(&the_chip->calib_ccadc_work,
+				msecs_to_jiffies(the_chip->calib_delay_ms -
+					(time_since_last_calib * 1000)));
 		}
 	}
 
@@ -832,6 +844,7 @@
 }
 
 static const struct dev_pm_ops pm8xxx_ccadc_pm_ops = {
+	.suspend	= pm8xxx_ccadc_suspend,
 	.resume		= pm8xxx_ccadc_resume,
 };
 
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 1ece59b..eac8953 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -117,7 +117,9 @@
 	u8				revision1;
 	u8				revision2;
 	int				battery_present;
+	int				battery_status;
 	bool				new_battery;
+	bool				done_charging;
 	bool				last_soc_invalid;
 	/* platform data */
 	int				r_sense_uohm;
@@ -140,7 +142,6 @@
 
 	struct delayed_work		calculate_soc_delayed_work;
 	struct work_struct		recalc_work;
-	struct work_struct		battery_insertion_work;
 
 	struct mutex			bms_output_lock;
 	struct mutex			last_ocv_uv_mutex;
@@ -189,6 +190,8 @@
 	struct single_row_lut		*adjusted_fcc_temp_lut;
 
 	struct qpnp_adc_tm_btm_param	vbat_monitor_params;
+	struct qpnp_adc_tm_btm_param	die_temp_monitor_params;
+	int				temperature_margin;
 	unsigned int			vadc_v0625;
 	unsigned int			vadc_v1250;
 
@@ -223,7 +226,6 @@
 };
 
 static enum power_supply_property msm_bms_power_props[] = {
-	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_CAPACITY,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
 	POWER_SUPPLY_PROP_RESISTANCE,
@@ -372,12 +374,17 @@
 static inline int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip,
 					uint16_t reading)
 {
-	int uv;
+	int64_t uv;
+	int rc;
 
 	uv = vadc_reading_to_uv(reading);
-	pr_debug("%u raw converted into %d uv\n", reading, uv);
+	pr_debug("%u raw converted into %lld uv\n", reading, uv);
 	uv = adjust_vbatt_reading(chip, uv);
-	pr_debug("adjusted into %d uv\n", uv);
+	pr_debug("adjusted into %lld uv\n", uv);
+	rc = qpnp_vbat_sns_comp_result(&uv);
+	if (rc)
+		pr_debug("could not compensate vbatt\n");
+	pr_debug("compensated into %lld uv\n", uv);
 	return uv;
 }
 
@@ -581,7 +588,7 @@
 		pr_err("cc reenable failed: %d\n", rc);
 }
 
-static bool is_battery_charging(struct qpnp_bms_chip *chip)
+static int get_battery_status(struct qpnp_bms_chip *chip)
 {
 	union power_supply_propval ret = {0,};
 
@@ -591,12 +598,17 @@
 		/* if battery has been registered, use the status property */
 		chip->batt_psy->get_property(chip->batt_psy,
 					POWER_SUPPLY_PROP_STATUS, &ret);
-		return ret.intval == POWER_SUPPLY_STATUS_CHARGING;
+		return ret.intval;
 	}
 
 	/* Default to false if the battery power supply is not registered. */
 	pr_debug("battery power supply is not registered\n");
-	return false;
+	return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+static bool is_battery_charging(struct qpnp_bms_chip *chip)
+{
+	return get_battery_status(chip) == POWER_SUPPLY_STATUS_CHARGING;
 }
 
 static bool is_battery_present(struct qpnp_bms_chip *chip)
@@ -619,20 +631,7 @@
 
 static bool is_battery_full(struct qpnp_bms_chip *chip)
 {
-	union power_supply_propval ret = {0,};
-
-	if (chip->batt_psy == NULL)
-		chip->batt_psy = power_supply_get_by_name("battery");
-	if (chip->batt_psy) {
-		/* if battery has been registered, use the status property */
-		chip->batt_psy->get_property(chip->batt_psy,
-					POWER_SUPPLY_PROP_STATUS, &ret);
-		return ret.intval == POWER_SUPPLY_STATUS_FULL;
-	}
-
-	/* Default to true if the battery power supply is not registered. */
-	pr_debug("battery power supply is not registered\n");
-	return true;
+	return get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL;
 }
 
 static int get_simultaneous_batt_v_and_i(struct qpnp_bms_chip *chip,
@@ -769,6 +768,19 @@
 		raw->cc = 0;
 		raw->last_good_ocv_uv = chip->last_ocv_uv;
 		chip->new_battery = false;
+	} else if (chip->done_charging) {
+		chip->done_charging = false;
+		/* if we just finished charging, reset CC and fake 100% */
+		chip->ocv_reading_at_100 = raw->last_good_ocv_raw;
+		chip->last_ocv_uv = chip->max_voltage_uv;
+		raw->last_good_ocv_uv = chip->max_voltage_uv;
+		raw->cc = 0;
+		reset_cc(chip);
+		chip->last_ocv_temp = batt_temp;
+		chip->software_cc_uah = 0;
+		chip->last_cc_uah = INT_MIN;
+		pr_debug("EOC Battery full ocv_reading = 0x%x\n",
+				chip->ocv_reading_at_100);
 	} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
 		convert_and_store_ocv(chip, raw, batt_temp);
 		/* forget the old cc value upon ocv */
@@ -777,21 +789,10 @@
 		raw->last_good_ocv_uv = chip->last_ocv_uv;
 	}
 
-	/* fake a high OCV if done charging */
-	if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+	/* stop faking a high OCV if we get a new OCV */
+	if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw)
 		chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
-	} else {
-		/*
-		 * force 100% ocv by selecting the highest voltage the
-		 * battery could ever reach
-		 */
-		raw->last_good_ocv_uv = chip->max_voltage_uv;
-		chip->last_ocv_uv = chip->max_voltage_uv;
-		chip->last_ocv_temp = batt_temp;
-		reset_cc(chip);
-		chip->software_cc_uah = 0;
-		raw->cc = 0;
-	}
+
 	pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
 			raw->last_good_ocv_raw, raw->last_good_ocv_uv);
 	pr_debug("cc_raw= 0x%llx\n", raw->cc);
@@ -1811,6 +1812,7 @@
 	if (chip->use_voltage_soc) {
 		soc = calculate_soc_from_voltage(chip);
 	} else {
+		qpnp_iadc_calibrate_for_trim();
 		rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
 		if (rc) {
 			pr_err("error reading vadc LR_MUX1_BATT_THERM = %d, rc = %d\n",
@@ -2244,11 +2246,56 @@
 	return 0;
 }
 
-static void battery_insertion_work(struct work_struct *work)
+static void charging_began(struct qpnp_bms_chip *chip)
 {
-	struct qpnp_bms_chip *chip = container_of(work,
-				struct qpnp_bms_chip,
-				battery_insertion_work);
+	mutex_lock(&chip->last_soc_mutex);
+	chip->charge_start_tm_sec = 0;
+	chip->catch_up_time_sec = 0;
+	mutex_unlock(&chip->last_soc_mutex);
+
+	mutex_lock(&chip->last_ocv_uv_mutex);
+	chip->soc_at_cv = -EINVAL;
+	chip->prev_chg_soc = -EINVAL;
+	mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+
+static void charging_ended(struct qpnp_bms_chip *chip)
+{
+	mutex_lock(&chip->last_soc_mutex);
+	chip->charge_start_tm_sec = 0;
+	chip->catch_up_time_sec = 0;
+	mutex_unlock(&chip->last_soc_mutex);
+
+	mutex_lock(&chip->last_ocv_uv_mutex);
+	chip->soc_at_cv = -EINVAL;
+	chip->prev_chg_soc = -EINVAL;
+	if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL)
+		chip->done_charging = true;
+	mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+
+static void battery_status_check(struct qpnp_bms_chip *chip)
+{
+	int status = get_battery_status(chip);
+
+	if (chip->battery_status != status) {
+		if (status == POWER_SUPPLY_STATUS_CHARGING) {
+			pr_debug("charging started\n");
+			charging_began(chip);
+		} else if (chip->battery_status
+				== POWER_SUPPLY_STATUS_CHARGING) {
+			pr_debug("charging ended\n");
+			charging_ended(chip);
+		}
+		chip->battery_status = status;
+		/* a new battery was inserted or removed, so force a soc
+		 * recalculation to update the SoC */
+		schedule_work(&chip->recalc_work);
+	}
+}
+
+static void battery_insertion_check(struct qpnp_bms_chip *chip)
+{
 	bool present = is_battery_present(chip);
 
 	mutex_lock(&chip->vbat_monitor_mutex);
@@ -2300,18 +2347,13 @@
 	return chip->fcc_mah * 1000;
 }
 
-static int get_prop_bms_present(struct qpnp_bms_chip *chip)
-{
-	return is_battery_present(chip);
-}
-
-static void set_prop_bms_present(struct qpnp_bms_chip *chip, int present)
-{
-	schedule_work(&chip->battery_insertion_work);
-}
-
 static void qpnp_bms_external_power_changed(struct power_supply *psy)
 {
+	struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
+								bms_psy);
+
+	battery_insertion_check(chip);
+	battery_status_check(chip);
 }
 
 static int qpnp_bms_power_get_property(struct power_supply *psy,
@@ -2334,26 +2376,6 @@
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 		val->intval = get_prop_bms_charge_full_design(chip);
 		break;
-	case POWER_SUPPLY_PROP_PRESENT:
-		val->intval = get_prop_bms_present(chip);
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int qpnp_bms_power_set_property(struct power_supply *psy,
-					enum power_supply_property psp,
-					const union power_supply_propval *val)
-{
-	struct qpnp_bms_chip *chip = container_of(psy, struct qpnp_bms_chip,
-								bms_psy);
-
-	switch (psp) {
-	case POWER_SUPPLY_PROP_PRESENT:
-		set_prop_bms_present(chip, val->intval);
-		break;
 	default:
 		return -EINVAL;
 	}
@@ -2572,6 +2594,7 @@
 	SPMI_PROP_READ(ocv_low_threshold_uv,
 			"ocv-voltage-low-threshold-uv", rc);
 	SPMI_PROP_READ(low_voltage_threshold, "low-voltage-threshold", rc);
+	SPMI_PROP_READ(temperature_margin, "tm-temp-margin", rc);
 
 	if (chip->adjust_soc_low_threshold >= 45)
 		chip->adjust_soc_low_threshold = 45;
@@ -2599,6 +2622,7 @@
 	chip->last_soc = -EINVAL;
 	chip->last_soc_est = -EINVAL;
 	chip->battery_present = -EINVAL;
+	chip->battery_status = POWER_SUPPLY_STATUS_UNKNOWN;
 	chip->last_cc_uah = INT_MIN;
 	chip->ocv_reading_at_100 = OCV_RAW_UNINITIALIZED;
 	chip->prev_last_good_ocv_raw = OCV_RAW_UNINITIALIZED;
@@ -2745,6 +2769,64 @@
 	return 0;
 }
 
+static int refresh_die_temp_monitor(struct qpnp_bms_chip *chip)
+{
+	struct qpnp_vadc_result result;
+	int rc;
+
+	rc = qpnp_vadc_read(DIE_TEMP, &result);
+
+	pr_debug("low = %lld, high = %lld\n",
+			result.physical - chip->temperature_margin,
+			result.physical + chip->temperature_margin);
+	chip->die_temp_monitor_params.high_temp = result.physical
+						+ chip->temperature_margin;
+	chip->die_temp_monitor_params.low_temp = result.physical
+						- chip->temperature_margin;
+	chip->die_temp_monitor_params.state_request =
+						ADC_TM_HIGH_LOW_THR_ENABLE;
+	return qpnp_adc_tm_channel_measure(&chip->die_temp_monitor_params);
+}
+
+static void btm_notify_die_temp(enum qpnp_tm_state state, void *ctx)
+{
+	struct qpnp_bms_chip *chip = ctx;
+	struct qpnp_vadc_result result;
+	int rc;
+
+	rc = qpnp_vadc_read(DIE_TEMP, &result);
+
+	if (state == ADC_TM_LOW_STATE)
+		pr_debug("low state triggered\n");
+	else if (state == ADC_TM_HIGH_STATE)
+		pr_debug("high state triggered\n");
+	pr_debug("die temp = %lld, raw = 0x%x\n",
+			result.physical, result.adc_code);
+	schedule_work(&chip->recalc_work);
+	refresh_die_temp_monitor(chip);
+}
+
+static int setup_die_temp_monitoring(struct qpnp_bms_chip *chip)
+{
+	int rc = qpnp_adc_tm_is_ready();
+	if (rc) {
+		pr_info("adc tm is not ready yet: %d, defer probe\n", rc);
+		return -EPROBE_DEFER;
+	}
+	chip->die_temp_monitor_params.channel = DIE_TEMP;
+	chip->die_temp_monitor_params.btm_ctx = (void *)chip;
+	chip->die_temp_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
+	chip->die_temp_monitor_params.threshold_notification =
+						&btm_notify_die_temp;
+	refresh_die_temp_monitor(chip);
+	if (rc) {
+		pr_err("tm setup failed: %d\n", rc);
+		return rc;
+	}
+	pr_debug("setup complete\n");
+	return 0;
+}
+
 static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
 {
 	struct qpnp_bms_chip *chip;
@@ -2844,7 +2926,6 @@
 	INIT_DELAYED_WORK(&chip->calculate_soc_delayed_work,
 			calculate_soc_work);
 	INIT_WORK(&chip->recalc_work, recalculate_work);
-	INIT_WORK(&chip->battery_insertion_work, battery_insertion_work);
 
 	read_shutdown_soc_and_iavg(chip);
 
@@ -2857,6 +2938,12 @@
 		goto error_setup;
 	}
 
+	rc = setup_die_temp_monitoring(chip);
+	if (rc < 0) {
+		pr_err("failed to set up die temp notifications: %d\n", rc);
+		goto error_setup;
+	}
+
 	calculate_soc_work(&(chip->calculate_soc_delayed_work.work));
 
 	/* setup & register the battery power supply */
@@ -2865,7 +2952,6 @@
 	chip->bms_psy.properties = msm_bms_power_props;
 	chip->bms_psy.num_properties = ARRAY_SIZE(msm_bms_power_props);
 	chip->bms_psy.get_property = qpnp_bms_power_get_property;
-	chip->bms_psy.set_property = qpnp_bms_power_set_property;
 	chip->bms_psy.external_power_changed =
 		qpnp_bms_external_power_changed;
 	chip->bms_psy.supplied_to = qpnp_bms_supplicants;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 4be1760..3d8a75d 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -729,9 +729,6 @@
 		}
 	}
 
-	if (chip->bms_psy)
-		power_supply_set_present(chip->bms_psy, batt_present);
-
 	return IRQ_HANDLED;
 }
 
@@ -928,6 +925,10 @@
 	"battery",
 };
 
+static char *pm_batt_supplied_to[] = {
+	"bms",
+};
+
 #define USB_WALL_THRESHOLD_MA	500
 static int
 qpnp_power_get_property_mains(struct power_supply *psy,
@@ -2111,7 +2112,6 @@
 	struct qpnp_chg_chip	*chip;
 	struct resource *resource;
 	struct spmi_resource *spmi_resource;
-	bool present;
 	int rc = 0;
 
 	chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -2268,14 +2268,6 @@
 		if (rc)
 			goto fail_chg_enable;
 
-		/* if bms exists, notify it of the presence of the battery */
-		if (!chip->bms_psy)
-			chip->bms_psy = power_supply_get_by_name("bms");
-		if (chip->bms_psy) {
-			present = get_prop_batt_present(chip);
-			power_supply_set_present(chip->bms_psy, present);
-		}
-
 		chip->batt_psy.name = "battery";
 		chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
 		chip->batt_psy.properties = msm_batt_power_props;
@@ -2287,6 +2279,9 @@
 				qpnp_batt_property_is_writeable;
 		chip->batt_psy.external_power_changed =
 				qpnp_batt_external_power_changed;
+		chip->batt_psy.supplied_to = pm_batt_supplied_to;
+		chip->batt_psy.num_supplicants =
+				ARRAY_SIZE(pm_batt_supplied_to);
 
 		rc = power_supply_register(chip->dev, &chip->batt_psy);
 		if (rc < 0) {
@@ -2361,6 +2356,11 @@
 	power_supply_set_present(chip->usb_psy,
 			qpnp_chg_is_usb_chg_plugged_in(chip));
 
+	/* Set USB psy online to avoid userspace from shutting down if battery
+	 * capacity is at zero and no chargers online. */
+	if (qpnp_chg_is_usb_chg_plugged_in(chip))
+		power_supply_set_online(chip->usb_psy, 1);
+
 	pr_info("success chg_dis = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
 			chip->charging_disabled,
 			qpnp_chg_is_usb_chg_plugged_in(chip),
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 22f8dc9..a1b02be 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -798,8 +798,6 @@
 {
 	struct usb_request		*req = mbim->not_port.notify_req;
 	struct usb_cdc_notification	*event;
-	struct usb_composite_dev	*cdev = mbim->cdev;
-	__le32				*data;
 	int				status;
 
 	pr_debug("notify_state: %d", mbim->not_port.notify_state);
@@ -836,36 +834,6 @@
 		}
 
 		return;
-
-	case NCM_NOTIFY_CONNECT:
-		event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
-		if (mbim->is_open)
-			event->wValue = cpu_to_le16(1);
-		else
-			event->wValue = cpu_to_le16(0);
-		event->wLength = 0;
-		req->length = sizeof *event;
-
-		pr_info("notify connect %s\n",
-			mbim->is_open ? "true" : "false");
-		mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
-		break;
-
-	case NCM_NOTIFY_SPEED:
-		event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
-		event->wValue = cpu_to_le16(0);
-		event->wLength = cpu_to_le16(8);
-		req->length = NCM_STATUS_BYTECOUNT;
-
-		/* SPEED_CHANGE data is up/down speeds in bits/sec */
-		data = req->buf + sizeof *event;
-		data[0] = cpu_to_le32(mbim_bitrate(cdev->gadget));
-		data[1] = data[0];
-
-		pr_info("notify speed %d\n",
-			mbim_bitrate(cdev->gadget));
-		mbim->not_port.notify_state = NCM_NOTIFY_CONNECT;
-		break;
 	}
 
 	event->bmRequestType = 0xA1;
@@ -888,22 +856,6 @@
 	}
 }
 
-/*
- * Context: mbim->lock held
- */
-static void mbim_notify(struct f_mbim *mbim)
-{
-	/*
-	 * If mbim_notify() is called before the second (CONNECT)
-	 * notification is sent, then it will reset to send the SPEED
-	 * notificaion again (and again, and again), but it's not a problem
-	 */
-	pr_debug("dev:%p\n", mbim);
-
-	mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
-	mbim_do_notify(mbim);
-}
-
 static void mbim_notify_complete(struct usb_ep *ep, struct usb_request *req)
 {
 	struct f_mbim			*mbim = req->context;
@@ -1391,7 +1343,7 @@
 
 		mbim->data_alt_int = alt;
 		spin_lock(&mbim->lock);
-		mbim_notify(mbim);
+		mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
 		spin_unlock(&mbim->lock);
 	} else {
 		goto fail;
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index a395d15..5e68296 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -599,7 +599,7 @@
 			DBG(cdev, "activate ecm\n");
 			if (ecm->xport != USB_GADGET_XPORT_BAM2BAM_IPA) {
 				net = gether_qc_connect_name(&ecm->port,
-								"ecm0");
+								"ecm0", true);
 				if (IS_ERR(net))
 					return PTR_ERR(net);
 			}
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 8b01176..baea664 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -725,7 +725,7 @@
 		rndis->port.cdc_filter = 0;
 
 		DBG(cdev, "RNDIS RX/TX early activation ...\n");
-		net = gether_qc_connect_name(&rndis->port, "rndis0");
+		net = gether_qc_connect_name(&rndis->port, "rndis0", false);
 		if (IS_ERR(net))
 			return PTR_ERR(net);
 
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 1017900..1288bfd 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -74,7 +74,7 @@
 static unsigned int rndis_ul_max_pkt_per_xfer = 1;
 module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(rndis_ul_max_pkt_per_xfer,
-	"Disable RNDIS Multi-packet support in DownLink");
+	"Maximum packets per transfer for UL aggregation");
 
 struct f_rndis {
 	struct gether			port;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 07f4d26..bff7eb1 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -947,6 +947,10 @@
 	rndis_per_dev_params[configNr].dev = dev;
 	rndis_per_dev_params[configNr].filter = cdc_filter;
 
+	/* reset aggregation stats for every set_alt */
+	rndis_ul_max_xfer_size_rcvd = 0;
+	rndis_ul_max_pkt_per_xfer_rcvd = 0;
+
 	return 0;
 }
 
@@ -1060,7 +1064,7 @@
 			struct sk_buff *skb,
 			struct sk_buff_head *list)
 {
-	int num_pkts = 1;
+	int num_pkts = 0;
 
 	if (skb->len > rndis_ul_max_xfer_size_rcvd)
 		rndis_ul_max_xfer_size_rcvd = skb->len;
@@ -1072,6 +1076,8 @@
 
 		/* some rndis hosts send extra byte to avoid zlp, ignore it */
 		if (skb->len == 1) {
+			if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
+				rndis_ul_max_pkt_per_xfer_rcvd = num_pkts;
 			dev_kfree_skb_any(skb);
 			return 0;
 		}
@@ -1105,6 +1111,8 @@
 			return -EINVAL;
 		}
 
+		num_pkts++;
+
 		skb_pull(skb, data_offset + 8);
 
 		if (msg_len == skb->len) {
@@ -1122,8 +1130,6 @@
 		skb_pull(skb, msg_len - sizeof *hdr);
 		skb_trim(skb2, data_len);
 		skb_queue_tail(list, skb2);
-
-		num_pkts++;
 	}
 
 	if (num_pkts > rndis_ul_max_pkt_per_xfer_rcvd)
@@ -1148,7 +1154,9 @@
 			 "speed     : %d\n"
 			 "cable     : %s\n"
 			 "vendor ID : 0x%08X\n"
-			 "vendor    : %s\n",
+			 "vendor    : %s\n"
+			 "ul-max-xfer-size:%d max-xfer-size-rcvd: %d\n"
+			 "ul-max-pkts-per-xfer:%d max-pkts-per-xfer-rcvd:%d\n",
 			 param->confignr, (param->used) ? "y" : "n",
 			 ({ char *s = "?";
 			 switch (param->state) {
@@ -1162,7 +1170,13 @@
 			 param->medium,
 			 (param->media_state) ? 0 : param->speed*100,
 			 (param->media_state) ? "disconnected" : "connected",
-			 param->vendorID, param->vendorDescr);
+			 param->vendorID, param->vendorDescr,
+			 param->max_pkt_per_xfer *
+				 (param->dev->mtu + sizeof(struct ethhdr) +
+				  sizeof(struct rndis_packet_msg_type) + 22),
+			 rndis_ul_max_xfer_size_rcvd,
+			 param->max_pkt_per_xfer,
+			 rndis_ul_max_pkt_per_xfer_rcvd);
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index c05f683..b71f903 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -539,9 +539,12 @@
 	struct bam_ch_info *d = &port->data_ch;
 	int status;
 
-	if (!port->port_usb)
+	if (!port->port_usb) {
+		pr_err("%s: port->port_usb is NULL", __func__);
 		return;
+	}
 
+	pr_debug("%s: enqueue\n", __func__);
 	status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
 	if (status)
 		pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
@@ -552,14 +555,69 @@
 	struct bam_ch_info *d = &port->data_ch;
 	int status;
 
-	if (!port->port_usb)
+	if (!port->port_usb) {
+		pr_err("%s: port->port_usb is NULL", __func__);
 		return;
+	}
 
+	pr_debug("%s: enqueue\n", __func__);
 	status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
 	if (status)
 		pr_err("%s: error enqueuing transfer, %d\n", __func__, status);
 }
 
+static void gbam_stop_endless_rx(struct gbam_port *port)
+{
+	struct bam_ch_info *d = &port->data_ch;
+	int status;
+
+	if (!port->port_usb) {
+		pr_err("%s: port->port_usb is NULL", __func__);
+		return;
+	}
+	pr_debug("%s: dequeue\n", __func__);
+
+	status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
+	if (status)
+		pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+
+}
+static void gbam_stop_endless_tx(struct gbam_port *port)
+{
+	struct bam_ch_info *d = &port->data_ch;
+	int status;
+
+	if (!port->port_usb) {
+		pr_err("%s: port->port_usb is NULL", __func__);
+		return;
+	}
+
+	pr_debug("%s: dequeue\n", __func__);
+	status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
+	if (status)
+		pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
+static void gbam_start(void *param, enum usb_bam_pipe_dir dir)
+{
+	struct gbam_port *port = param;
+
+	if (dir == USB_TO_PEER_PERIPHERAL)
+		gbam_start_endless_rx(port);
+	else
+		gbam_start_endless_tx(port);
+}
+
+static void gbam_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+	struct gbam_port *port = param;
+
+	if (dir == USB_TO_PEER_PERIPHERAL)
+		gbam_stop_endless_rx(port);
+	else
+		gbam_stop_endless_tx(port);
+}
+
 static void gbam_start_io(struct gbam_port *port)
 {
 	unsigned long		flags;
@@ -1409,6 +1467,10 @@
 	pr_debug("%s: suspended port %d\n", __func__, port_num);
 
 	usb_bam_register_wake_cb(d->dst_connection_idx, gbam_wake_cb, port);
+	if (trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		usb_bam_register_start_stop_cbs(gbam_start, gbam_stop, port);
+		usb_bam_suspend(&d->ipa_params);
+	}
 }
 
 void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
@@ -1426,4 +1488,6 @@
 	pr_debug("%s: resumed port %d\n", __func__, port_num);
 
 	usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+	if (trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+		usb_bam_resume(&d->ipa_params);
 }
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 2abe2ef..081a09c 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -92,6 +92,7 @@
 	if (!port->port_usb)
 		return;
 
+	pr_debug("%s: enqueue\n", __func__);
 	status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
 	if (status)
 		pr_err("error enqueuing transfer, %d\n", status);
@@ -105,11 +106,40 @@
 	if (!port->port_usb)
 		return;
 
+	pr_debug("%s: enqueue\n", __func__);
 	status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
 	if (status)
 		pr_err("error enqueuing transfer, %d\n", status);
 }
 
+static void bam_data_stop_endless_rx(struct bam_data_port *port)
+{
+	struct bam_data_ch_info *d = &port->data_ch;
+	int status;
+
+	if (!port->port_usb)
+		return;
+
+	pr_debug("%s: dequeue\n", __func__);
+	status = usb_ep_dequeue(port->port_usb->out, d->rx_req);
+	if (status)
+		pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+
+}
+static void bam_data_stop_endless_tx(struct bam_data_port *port)
+{
+	struct bam_data_ch_info *d = &port->data_ch;
+	int status;
+
+	if (!port->port_usb)
+		return;
+
+	pr_debug("%s: dequeue\n", __func__);
+	status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
+	if (status)
+		pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
+}
+
 static int bam_data_peer_reset_cb(void *param)
 {
 	struct bam_data_port	*port = (struct bam_data_port *)param;
@@ -529,9 +559,28 @@
 	return usb_gadget_wakeup(d_port->cdev->gadget);
 }
 
+static void bam_data_start(void *param, enum usb_bam_pipe_dir dir)
+{
+	struct bam_data_port *port = param;
+
+	if (dir == USB_TO_PEER_PERIPHERAL)
+		bam_data_start_endless_rx(port);
+	else
+		bam_data_start_endless_tx(port);
+}
+
+static void bam_data_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+	struct bam_data_port *port = param;
+
+	if (dir == USB_TO_PEER_PERIPHERAL)
+		bam_data_stop_endless_rx(port);
+	else
+		bam_data_stop_endless_tx(port);
+}
+
 void bam_data_suspend(u8 port_num)
 {
-
 	struct bam_data_port	*port;
 	struct bam_data_ch_info *d;
 
@@ -540,6 +589,11 @@
 
 	pr_debug("%s: suspended port %d\n", __func__, port_num);
 	usb_bam_register_wake_cb(d->dst_connection_idx, bam_data_wake_cb, port);
+	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
+		usb_bam_register_start_stop_cbs(bam_data_start, bam_data_stop,
+									port);
+		usb_bam_suspend(&d->ipa_params);
+	}
 }
 
 void bam_data_resume(u8 port_num)
@@ -553,5 +607,6 @@
 
 	pr_debug("%s: resumed port %d\n", __func__, port_num);
 	usb_bam_register_wake_cb(d->dst_connection_idx, NULL, NULL);
+	if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA)
+		usb_bam_resume(&d->ipa_params);
 }
-
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index d4c21dd..dbffa4e 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -70,7 +70,7 @@
 	struct sk_buff_head	rx_frames;
 
 	unsigned		header_len;
-	unsigned		ul_max_pkts_per_xfer;
+	unsigned int		ul_max_pkts_per_xfer;
 	struct sk_buff		*(*wrap)(struct gether *, struct sk_buff *skb);
 	int			(*unwrap)(struct gether *,
 						struct sk_buff *skb,
diff --git a/drivers/usb/gadget/u_qc_ether.c b/drivers/usb/gadget/u_qc_ether.c
index e10ec25..044da47 100644
--- a/drivers/usb/gadget/u_qc_ether.c
+++ b/drivers/usb/gadget/u_qc_ether.c
@@ -354,12 +354,13 @@
  *	current device speed, and any framing wrapper(s) set up.
  * @netname: name for network device (for example, "usb")
  * Context: irqs blocked
+ * @netif_enable: if true, net interface will be turned on
  *
  * This is called to let the network layer know the connection
  * is active ("carrier detect").
  */
 struct net_device *gether_qc_connect_name(struct qc_gether *link,
-		const char *netname)
+		const char *netname, bool netif_enable)
 {
 	struct net_device *net_dev;
 	struct eth_qc_dev *dev;
@@ -390,9 +391,11 @@
 	}
 	spin_unlock(&dev->lock);
 
-	netif_carrier_on(dev->net);
-	if (netif_running(dev->net))
-		netif_wake_queue(dev->net);
+	if (netif_enable) {
+		netif_carrier_on(dev->net);
+		if (netif_running(dev->net))
+			netif_wake_queue(dev->net);
+	}
 
 	return dev->net;
 }
diff --git a/drivers/usb/gadget/u_qc_ether.h b/drivers/usb/gadget/u_qc_ether.h
index 25562da..5d9f738 100644
--- a/drivers/usb/gadget/u_qc_ether.h
+++ b/drivers/usb/gadget/u_qc_ether.h
@@ -82,7 +82,7 @@
 
 /* connect/disconnect is handled by individual functions */
 struct net_device *gether_qc_connect_name(struct qc_gether *link,
-		const char *netname);
+		const char *netname, bool netif_enable);
 void gether_qc_disconnect_name(struct qc_gether *link, const char *netname);
 
 /* each configuration may bind one instance of an ethernet link */
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index d4d7ee9..833bab2 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -870,7 +870,7 @@
 		return 0;
 
 	if (motg->pdata->delay_lpm_hndshk_on_disconnect && !msm_bam_lpm_ok())
-		return 0;
+		return -EBUSY;
 
 	disable_irq(motg->irq);
 	host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 2c58e49..43eda51 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,4 +1,5 @@
 mdss-mdp3-objs = mdp3.o mdp3_dma.o mdp3_ctrl.o
+mdss-mdp3-objs += mdp3_ppp.o mdp3_ppp_hwio.o mdp3_ppp_data.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp3.o
 
 mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 290e317..5223e66 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -48,11 +48,12 @@
 #include "mdss_fb.h"
 #include "mdp3_hwio.h"
 #include "mdp3_ctrl.h"
+#include "mdp3_ppp.h"
 
 #define MDP_CORE_HW_VERSION	0x03040310
 struct mdp3_hw_resource *mdp3_res;
 
-#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)		\
+#define MDP_BUS_VECTOR_ENTRY_DMA(ab_val, ib_val)		\
 	{						\
 		.src = MSM_BUS_MASTER_MDP_PORT0,	\
 		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
@@ -60,20 +61,59 @@
 		.ib = (ib_val),				\
 	}
 
-static struct msm_bus_vectors mdp_bus_vectors[] = {
-	MDP_BUS_VECTOR_ENTRY(0, 0),
-	MDP_BUS_VECTOR_ENTRY(SZ_128M, SZ_256M),
-	MDP_BUS_VECTOR_ENTRY(SZ_256M, SZ_512M),
+static struct msm_bus_vectors mdp_bus_dma_vectors[] = {
+	MDP_BUS_VECTOR_ENTRY_DMA(0, 0),
+	MDP_BUS_VECTOR_ENTRY_DMA(SZ_128M, SZ_256M),
+	MDP_BUS_VECTOR_ENTRY_DMA(SZ_256M, SZ_512M),
+};
+static struct msm_bus_paths
+	mdp_bus_dma_usecases[ARRAY_SIZE(mdp_bus_dma_vectors)];
+static struct msm_bus_scale_pdata mdp_bus_dma_scale_table = {
+	.usecase = mdp_bus_dma_usecases,
+	.num_usecases = ARRAY_SIZE(mdp_bus_dma_usecases),
+	.name = "mdp3",
 };
 
-static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+#define MDP_BUS_VECTOR_ENTRY_PPP(ab_val, ib_val)		\
+	{						\
+		.src = MSM_BUS_MASTER_MDPE,	\
+		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
+		.ab = (ab_val),				\
+		.ib = (ib_val),				\
+	}
 
-static struct msm_bus_scale_pdata mdp_bus_scale_table = {
-	.usecase = mdp_bus_usecases,
-	.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+static struct msm_bus_vectors mdp_bus_ppp_vectors[] = {
+	MDP_BUS_VECTOR_ENTRY_PPP(0, 0),
+	MDP_BUS_VECTOR_ENTRY_PPP(SZ_128M, SZ_256M),
+	MDP_BUS_VECTOR_ENTRY_PPP(SZ_256M, SZ_512M),
+};
+
+static struct msm_bus_paths
+	mdp_bus_ppp_usecases[ARRAY_SIZE(mdp_bus_ppp_vectors)];
+
+static struct msm_bus_scale_pdata mdp_bus_ppp_scale_table = {
+	.usecase = mdp_bus_ppp_usecases,
+	.num_usecases = ARRAY_SIZE(mdp_bus_ppp_usecases),
 	.name = "mdp3",
 };
 
+struct mdp3_bus_handle_map mdp3_bus_handle[MDP3_BUS_HANDLE_MAX] = {
+	[MDP3_BUS_HANDLE_DMA] = {
+		.bus_vector = mdp_bus_dma_vectors,
+		.usecases = mdp_bus_dma_usecases,
+		.scale_pdata = &mdp_bus_dma_scale_table,
+		.current_bus_idx = 0,
+		.handle = 0,
+	},
+	[MDP3_BUS_HANDLE_PPP] = {
+		.bus_vector = mdp_bus_ppp_vectors,
+		.usecases = mdp_bus_ppp_usecases,
+		.scale_pdata = &mdp_bus_ppp_scale_table,
+		.current_bus_idx = 0,
+		.handle = 0,
+	},
+};
+
 struct mdp3_iommu_domain_map mdp3_iommu_domains[MDP3_IOMMU_DOMAIN_MAX] = {
 	[MDP3_IOMMU_DOMAIN] = {
 		.domain_type = MDP3_IOMMU_DOMAIN,
@@ -213,71 +253,106 @@
 
 static int mdp3_bus_scale_register(void)
 {
+	int i;
+
 	if (!mdp3_res->bus_handle) {
-		struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
-		int i;
+		pr_err("No bus handle\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
+		struct mdp3_bus_handle_map *bus_handle =
+			&mdp3_res->bus_handle[i];
 
-		for (i = 0; i < bus_pdata->num_usecases; i++) {
-			mdp_bus_usecases[i].num_paths = 1;
-			mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
-		}
+		if (!bus_handle->handle) {
+			int j;
+			struct msm_bus_scale_pdata *bus_pdata =
+				bus_handle->scale_pdata;
 
-		mdp3_res->bus_handle = msm_bus_scale_register_client(bus_pdata);
-		if (!mdp3_res->bus_handle) {
-			pr_err("not able to get bus scale\n");
-			return -ENOMEM;
+			for (j = 0; j < bus_pdata->num_usecases; j++) {
+				bus_handle->usecases[j].num_paths = 1;
+				bus_handle->usecases[j].vectors =
+					&bus_handle->bus_vector[j];
+			}
+
+			bus_handle->handle =
+				msm_bus_scale_register_client(bus_pdata);
+			if (!bus_handle->handle) {
+				pr_err("not able to get bus scale i=%d\n", i);
+				return -ENOMEM;
+			}
+			pr_debug("register bus_hdl=%x\n",
+				bus_handle->handle);
 		}
-		pr_debug("register bus_hdl=%x\n", mdp3_res->bus_handle);
 	}
 	return 0;
 }
 
 static void mdp3_bus_scale_unregister(void)
 {
-	pr_debug("unregister bus_handle=%x\n", mdp3_res->bus_handle);
-
-	if (mdp3_res->bus_handle)
-		msm_bus_scale_unregister_client(mdp3_res->bus_handle);
+	int i;
+	for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
+		pr_debug("unregister index=%d bus_handle=%x\n",
+			i, mdp3_res->bus_handle[i].handle);
+		if (mdp3_res->bus_handle[i].handle) {
+			msm_bus_scale_unregister_client(
+			   mdp3_res->bus_handle[i].handle);
+			mdp3_res->bus_handle[i].handle = 0;
+		}
+	}
 }
 
 int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota)
 {
-	static int current_bus_idx;
+	struct mdp3_bus_handle_map *bus_handle;
+	int cur_bus_idx;
 	int bus_idx;
+	int client_idx;
 	int rc;
 
-	if (mdp3_res->bus_handle < 1) {
-		pr_err("invalid bus handle %d\n", mdp3_res->bus_handle);
+	if (client == MDP3_CLIENT_DMA_P) {
+		client_idx  = MDP3_BUS_HANDLE_DMA;
+	} else if (client == MDP3_CLIENT_PPP) {
+		client_idx  = MDP3_BUS_HANDLE_PPP;
+	} else {
+		pr_err("invalid client %d\n", client);
+		return -EINVAL;
+	}
+
+	bus_handle = &mdp3_res->bus_handle[client_idx];
+	cur_bus_idx = bus_handle->current_bus_idx;
+
+	if (bus_handle->handle < 1) {
+		pr_err("invalid bus handle %d\n", bus_handle->handle);
 		return -EINVAL;
 	}
 
 	if ((ab_quota | ib_quota) == 0) {
 		bus_idx = 0;
 	} else {
-		int num_cases = mdp_bus_scale_table.num_usecases;
+		int num_cases = bus_handle->scale_pdata->num_usecases;
 		struct msm_bus_vectors *vect = NULL;
 
-		bus_idx = (current_bus_idx % (num_cases - 1)) + 1;
+		bus_idx = (cur_bus_idx % (num_cases - 1)) + 1;
 
 		/* aligning to avoid performing updates for small changes */
 		ab_quota = ALIGN(ab_quota, SZ_64M);
 		ib_quota = ALIGN(ib_quota, SZ_64M);
 
-		vect = mdp_bus_scale_table.usecase[current_bus_idx].vectors;
+		vect = bus_handle->scale_pdata->usecase[cur_bus_idx].vectors;
 		if ((ab_quota == vect->ab) && (ib_quota == vect->ib)) {
 			pr_debug("skip bus scaling, no change in vectors\n");
 			return 0;
 		}
 
-		vect = mdp_bus_scale_table.usecase[bus_idx].vectors;
+		vect = bus_handle->scale_pdata->usecase[bus_idx].vectors;
 		vect->ab = ab_quota;
 		vect->ib = ib_quota;
 
 		pr_debug("bus scale idx=%d ab=%llu ib=%llu\n", bus_idx,
 				vect->ab, vect->ib);
 	}
-	current_bus_idx = bus_idx;
-	rc = msm_bus_scale_client_update_request(mdp3_res->bus_handle, bus_idx);
+	bus_handle->current_bus_idx = bus_idx;
+	rc = msm_bus_scale_client_update_request(bus_handle->handle, bus_idx);
 	return rc;
 }
 
@@ -298,7 +373,7 @@
 		mdp3_res->clock_ref_count[clk_idx]--;
 
 	count = mdp3_res->clock_ref_count[clk_idx];
-	if (count == 1) {
+	if (count == 1 && enable) {
 		pr_debug("clk=%d en=%d\n", clk_idx, enable);
 		ret = clk_prepare_enable(clk);
 	} else if (count == 0) {
@@ -655,6 +730,7 @@
 		pr_err("fail to attach DMA-P context 0\n");
 		return rc;
 	}
+	mdp3_res->bus_handle = mdp3_bus_handle;
 	rc = mdp3_bus_scale_register();
 	if (rc) {
 		pr_err("unable to register bus scaling\n");
@@ -800,9 +876,28 @@
 	return ret;
 }
 
+int mdp3_ppp_iommu_attach(void)
+{
+	int rc;
+	rc = mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_0);
+	rc |= mdp3_iommu_attach(MDP3_IOMMU_CTX_PPP_1);
+	return rc;
+}
+
+int mdp3_ppp_iommu_dettach(void)
+{
+	int rc;
+	rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_0);
+	rc = mdp3_iommu_dettach(MDP3_IOMMU_CTX_PPP_1);
+	return rc;
+}
+
 static int mdp3_init(struct msm_fb_data_type *mfd)
 {
-	return mdp3_ctrl_init(mfd);
+	int rc;
+	rc = mdp3_ctrl_init(mfd);
+	rc |= mdp3_ppp_res_init();
+	return rc;
 }
 
 u32 mdp3_fb_stride(u32 fb_index, u32 xres, int bpp)
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 7e395e1..878fe25 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -35,6 +35,12 @@
 };
 
 enum {
+	MDP3_BUS_HANDLE_DMA,
+	MDP3_BUS_HANDLE_PPP,
+	MDP3_BUS_HANDLE_MAX,
+};
+
+enum {
 	MDP3_IOMMU_DOMAIN,
 	MDP3_IOMMU_DOMAIN_MAX
 };
@@ -48,10 +54,16 @@
 };
 
 enum {
-	MDP3_BW_CLIENT_DMA_P,
-	MDP3_BW_CLIENT_DMA_S,
-	MDP3_BW_CLIENT_DMA_E,
-	MDP3_BW_CLIENT_PPP,
+	MDP3_CLIENT_DMA_P,
+	MDP3_CLIENT_PPP,
+};
+
+struct mdp3_bus_handle_map {
+	struct msm_bus_vectors *bus_vector;
+	struct msm_bus_paths *usecases;
+	struct msm_bus_scale_pdata *scale_pdata;
+	int current_bus_idx;
+	u32 handle;
 };
 
 struct mdp3_iommu_domain_map {
@@ -86,12 +98,14 @@
 
 	struct clk *clocks[MDP3_MAX_CLK];
 	int clock_ref_count[MDP3_MAX_CLK];
+	unsigned long dma_core_clk_request;
+	unsigned long ppp_core_clk_request;
 
 	char __iomem *mdp_base;
 	size_t mdp_reg_size;
 
 	u32 irq;
-	u32 bus_handle;
+	struct mdp3_bus_handle_map *bus_handle;
 
 	struct ion_client *ion_client;
 	struct mdp3_iommu_domain_map *domains;
@@ -130,6 +144,8 @@
 int mdp3_bus_scale_set_quota(int client, u64 ab_quota, u64 ib_quota);
 int mdp3_put_img(struct mdp3_img_data *data);
 int mdp3_get_img(struct msmfb_data *img, struct mdp3_img_data *data);
+int mdp3_ppp_iommu_attach(void);
+int mdp3_ppp_iommu_dettach(void);
 
 #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 f5ac5e9..3d990c2 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -22,6 +22,7 @@
 
 #include "mdp3_ctrl.h"
 #include "mdp3.h"
+#include "mdp3_ppp.h"
 
 #define MDP_VSYNC_CLK_RATE	19200000
 #define VSYNC_PERIOD 16
@@ -127,6 +128,53 @@
 	return 0;
 }
 
+static int mdp3_ctrl_blit_req(struct msm_fb_data_type *mfd, void __user *p)
+{
+	const int MAX_LIST_WINDOW = 16;
+	struct mdp_blit_req req_list[MAX_LIST_WINDOW];
+	struct mdp_blit_req_list req_list_header;
+	int rc, count, i, req_list_count;
+
+	if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
+		return -EFAULT;
+	p += sizeof(req_list_header);
+	count = req_list_header.count;
+	if (count < 0 || count >= MAX_BLIT_REQ)
+		return -EINVAL;
+	while (count > 0) {
+		/*
+		 * Access the requests through a narrow window to decrease copy
+		 * overhead and make larger requests accessible to the
+		 * coherency management code.
+		 * NOTE: The window size is intended to be larger than the
+		 *       typical request size, but not require more than 2
+		 *       kbytes of stack storage.
+		 */
+		req_list_count = count;
+		if (req_list_count > MAX_LIST_WINDOW)
+			req_list_count = MAX_LIST_WINDOW;
+		if (copy_from_user(&req_list, p,
+				sizeof(struct mdp_blit_req)*req_list_count))
+			return -EFAULT;
+		/*
+		 * Do the blit DMA, if required -- returning early only if
+		 * there is a failure.
+		 */
+		for (i = 0; i < req_list_count; i++) {
+			if (!(req_list[i].flags & MDP_NO_BLIT)) {
+				/* Do the actual blit. */
+				rc = mdp3_ppp_start_blit(mfd, &(req_list[i]));
+				if (rc)
+					return rc;
+			}
+		}
+
+		/* Go to next window of requests. */
+		count -= req_list_count;
+		p += sizeof(struct mdp_blit_req)*req_list_count;
+	}
+	return 0;
+}
 
 static ssize_t mdp3_vsync_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -181,9 +229,9 @@
 		ab = panel_info->xres * panel_info->yres * 4;
 		ab *= panel_info->mipi.frame_rate;
 		ib = (ab * 3) / 2;
-		rc = mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, ab, ib);
+		rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, ab, ib);
 	} else {
-		rc = mdp3_bus_scale_set_quota(MDP3_BW_CLIENT_DMA_P, 0, 0);
+		rc = mdp3_bus_scale_set_quota(MDP3_CLIENT_DMA_P, 0, 0);
 	}
 	return rc;
 }
@@ -394,6 +442,12 @@
 		goto on_error;
 	}
 
+	rc = mdp3_ppp_init();
+	if (rc) {
+		pr_err("ppp init failed\n");
+		goto on_error;
+	}
+
 	rc = mdp3_ctrl_intf_init(mfd, mdp3_session->intf);
 	if (rc) {
 		pr_err("display interface init failed\n");
@@ -701,6 +755,9 @@
 			rc = -EFAULT;
 		}
 		break;
+	case MSMFB_BLIT:
+		rc = mdp3_ctrl_blit_req(mfd, argp);
+		break;
 	case MSMFB_METADATA_GET:
 		rc = copy_from_user(&metadata, argp, sizeof(metadata));
 		if (rc)
diff --git a/drivers/video/msm/mdss/mdp3_hwio.h b/drivers/video/msm/mdss/mdp3_hwio.h
index 2763f46..1c5bf46 100644
--- a/drivers/video/msm/mdss/mdp3_hwio.h
+++ b/drivers/video/msm/mdss/mdp3_hwio.h
@@ -148,6 +148,70 @@
 #define MDP3_REG_DSI_CMD_MODE_ID_MAP			0xF1000
 #define MDP3_REG_DSI_CMD_MODE_TRIGGER_EN		0xF1004
 
+#define MDP3_PPP_CSC_PFMVn(n)		(0x40400 + (4 * (n)))
+#define MDP3_PPP_CSC_PRMVn(n)		(0x40440 + (4 * (n)))
+#define MDP3_PPP_CSC_PBVn(n)		(0x40500 + (4 * (n)))
+#define MDP3_PPP_CSC_PLVn(n)		(0x40580 + (4 * (n)))
+
+#define MDP3_PPP_CSC_SFMVn(n)		(0x40480 + (4 * (n)))
+#define MDP3_PPP_CSC_SRMVn(n)		(0x404C0 + (4 * (n)))
+#define MDP3_PPP_CSC_SBVn(n)		(0x40540 + (4 * (n)))
+#define MDP3_PPP_CSC_SLVn(n)		(0x405C0 + (4 * (n)))
+
+#define MDP3_PPP_SCALE_PHASEX_INIT	0x1013C
+#define MDP3_PPP_SCALE_PHASEY_INIT	0x10140
+#define MDP3_PPP_SCALE_PHASEX_STEP	0x10144
+#define MDP3_PPP_SCALE_PHASEY_STEP	0x10148
+
+#define MDP3_PPP_OP_MODE			0x10138
+
+#define MDP3_PPP_PRE_LUT			0x40800
+#define MDP3_PPP_POST_LUT			0x40C00
+#define MDP3_PPP_LUTn(n)			((4 * (n)))
+
+#define MDP3_PPP_BG_EDGE_REP		0x101BC
+#define MDP3_PPP_SRC_EDGE_REP		0x101B8
+
+#define MDP3_PPP_STRIDE_MASK		0x3FFF
+#define MDP3_PPP_STRIDE1_OFFSET		16
+
+#define MDP3_PPP_XY_MASK			0x0FFF
+#define MDP3_PPP_XY_OFFSET			16
+
+#define MDP3_PPP_SRC_SIZE			0x10108
+#define MDP3_PPP_SRCP0_ADDR			0x1010C
+#define MDP3_PPP_SRCP1_ADDR			0x10110
+#define MDP3_PPP_SRCP3_ADDR			0x10118
+#define MDP3_PPP_SRC_YSTRIDE1_ADDR	0x1011C
+#define MDP3_PPP_SRC_YSTRIDE2_ADDR	0x10120
+#define MDP3_PPP_SRC_FORMAT			0x10124
+#define MDP3_PPP_SRC_UNPACK_PATTERN1	0x10128
+#define MDP3_PPP_SRC_UNPACK_PATTERN2	0x1012C
+
+#define MDP3_PPP_OUT_FORMAT			0x10150
+#define MDP3_PPP_OUT_PACK_PATTERN1	0x10154
+#define MDP3_PPP_OUT_PACK_PATTERN2	0x10158
+#define MDP3_PPP_OUT_SIZE			0x10164
+#define MDP3_PPP_OUTP0_ADDR			0x10168
+#define MDP3_PPP_OUTP1_ADDR			0x1016C
+#define MDP3_PPP_OUTP3_ADDR			0x10174
+#define MDP3_PPP_OUT_YSTRIDE1_ADDR	0x10178
+#define MDP3_PPP_OUT_YSTRIDE2_ADDR	0x1017C
+#define MDP3_PPP_OUT_XY				0x1019C
+
+#define MDP3_PPP_BGP0_ADDR			0x101C0
+#define MDP3_PPP_BGP1_ADDR			0x101C4
+#define MDP3_PPP_BGP3_ADDR			0x101C8
+#define MDP3_PPP_BG_YSTRIDE1_ADDR	0x101CC
+#define MDP3_PPP_BG_YSTRIDE2_ADDR	0x101D0
+#define MDP3_PPP_BG_FORMAT			0x101D4
+#define MDP3_PPP_BG_UNPACK_PATTERN1	0x101D8
+#define MDP3_PPP_BG_UNPACK_PATTERN2	0x101DC
+
+#define MDP3_PPP_BLEND_PARAM		0x1014C
+
+#define MDP3_PPP_BLEND_BG_ALPHA_SEL	0x70010
+
 /*interrupt mask*/
 
 #define MDP3_INTR_DP0_ROI_DONE_BIT			BIT(0)
@@ -212,5 +276,6 @@
 
 #define MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT		BIT(0)
 #define MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT		BIT(1)
+#define MDP3_PPP_DONE MDP3_INTR_DP0_ROI_DONE
 
 #endif /* MDP3_HWIO_H */
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
new file mode 100644
index 0000000..7164086
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -0,0 +1,760 @@
+/* Copyright (c) 2007, 2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/file.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include "linux/proc_fs.h"
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+#include "mdp3_hwio.h"
+#include "mdp3.h"
+
+#define MDP_IS_IMGTYPE_BAD(x) ((x) >= MDP_IMGTYPE_LIMIT)
+
+static const bool valid_fmt[MDP_IMGTYPE_LIMIT] = {
+	[MDP_RGB_565] = true,
+	[MDP_BGR_565] = true,
+	[MDP_RGB_888] = true,
+	[MDP_BGR_888] = true,
+	[MDP_BGRA_8888] = true,
+	[MDP_RGBA_8888] = true,
+	[MDP_ARGB_8888] = true,
+	[MDP_XRGB_8888] = true,
+	[MDP_RGBX_8888] = true,
+	[MDP_Y_CRCB_H2V2] = true,
+	[MDP_Y_CBCR_H2V2] = true,
+	[MDP_Y_CBCR_H2V2_ADRENO] = true,
+	[MDP_YCRYCB_H2V1] = true,
+	[MDP_Y_CBCR_H2V1] = true,
+	[MDP_Y_CRCB_H2V1] = true,
+};
+
+struct ppp_status {
+	int busy;
+	spinlock_t ppp_lock;
+	struct completion ppp_comp;
+	struct mutex config_mutex;
+};
+
+static struct ppp_status *ppp_stat;
+
+
+int ppp_get_bpp(uint32_t format, uint32_t fb_format)
+{
+	int bpp = -EINVAL;
+	if (format == MDP_FB_FORMAT)
+		format = fb_format;
+
+	bpp = ppp_bpp(format);
+	if (bpp <= 0)
+		pr_err("%s incorrect format %d\n", __func__, format);
+	return bpp;
+}
+
+int mdp3_ppp_get_img(struct mdp_img *img, struct mdp_blit_req *req,
+		struct mdp3_img_data *data)
+{
+	struct msmfb_data fb_data;
+	fb_data.flags = img->priv;
+	fb_data.memory_id = img->memory_id;
+	fb_data.offset = 0;
+
+	return mdp3_get_img(&fb_data, data);
+}
+
+/* Check format */
+int mdp3_ppp_verify_fmt(struct mdp_blit_req *req)
+{
+	if (MDP_IS_IMGTYPE_BAD(req->src.format) ||
+	    MDP_IS_IMGTYPE_BAD(req->dst.format)) {
+		pr_err("%s: Color format out of range\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!valid_fmt[req->src.format] ||
+	    !valid_fmt[req->dst.format]) {
+		pr_err("%s: Color format not supported\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* Check resolution */
+int mdp3_ppp_verify_res(struct mdp_blit_req *req)
+{
+	if ((req->src.width == 0) || (req->src.height == 0) ||
+	    (req->src_rect.w == 0) || (req->src_rect.h == 0) ||
+	    (req->dst.width == 0) || (req->dst.height == 0) ||
+	    (req->dst_rect.w == 0) || (req->dst_rect.h == 0)) {
+		pr_err("%s: Height/width can't be 0\n", __func__);
+		return -EINVAL;
+	}
+
+	if (((req->src_rect.x + req->src_rect.w) > req->src.width) ||
+	    ((req->src_rect.y + req->src_rect.h) > req->src.height)) {
+		pr_err("%s: src roi larger than boundary\n", __func__);
+		return -EINVAL;
+	}
+
+	if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) ||
+	    ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) {
+		pr_err("%s: dst roi larger than boundary\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* scaling range check */
+int mdp3_ppp_verify_scale(struct mdp_blit_req *req)
+{
+	u32 src_width, src_height, dst_width, dst_height;
+
+	src_width = req->src_rect.w;
+	src_height = req->src_rect.h;
+
+	if (req->flags & MDP_ROT_90) {
+		dst_width = req->dst_rect.h;
+		dst_height = req->dst_rect.w;
+	} else {
+		dst_width = req->dst_rect.w;
+		dst_height = req->dst_rect.h;
+	}
+
+	switch (req->dst.format) {
+	case MDP_Y_CRCB_H2V2:
+	case MDP_Y_CBCR_H2V2:
+		src_width = (src_width / 2) * 2;
+		src_height = (src_height / 2) * 2;
+		dst_width = (dst_width / 2) * 2;
+		dst_height = (dst_height / 2) * 2;
+		break;
+
+	case MDP_Y_CRCB_H2V1:
+	case MDP_Y_CBCR_H2V1:
+	case MDP_YCRYCB_H2V1:
+		src_width = (src_width / 2) * 2;
+		dst_width = (dst_width / 2) * 2;
+		break;
+
+	default:
+		break;
+	}
+
+	if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width >
+	     MDP_MAX_X_SCALE_FACTOR)
+	    || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width <
+		MDP_MIN_X_SCALE_FACTOR)) {
+		pr_err("%s: x req scale factor beyond capability\n", __func__);
+		return -EINVAL;
+	}
+
+	if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height >
+	     MDP_MAX_Y_SCALE_FACTOR)
+	    || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height <
+		MDP_MIN_Y_SCALE_FACTOR)) {
+		pr_err("%s: y req scale factor beyond capability\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* operation check */
+int mdp3_ppp_verify_op(struct mdp_blit_req *req)
+{
+	if (req->flags & MDP_DEINTERLACE) {
+		pr_err("\n%s(): deinterlace not supported", __func__);
+		return -EINVAL;
+	}
+
+	if (req->flags & MDP_SHARPENING) {
+		pr_err("\n%s(): sharpening not supported", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int mdp3_ppp_verify_req(struct mdp_blit_req *req)
+{
+	int rc;
+
+	if (req == NULL) {
+		pr_err("%s: req == null\n", __func__);
+		return -EINVAL;
+	}
+
+	rc = mdp3_ppp_verify_fmt(req);
+	rc |= mdp3_ppp_verify_res(req);
+	rc |= mdp3_ppp_verify_scale(req);
+	rc |= mdp3_ppp_verify_op(req);
+
+	return rc;
+}
+
+int mdp3_ppp_pipe_wait(void)
+{
+	int ret = 1;
+	int wait;
+	unsigned long flag;
+
+	/*
+	 * wait 5 secs for operation to complete before declaring
+	 * the MDP hung
+	 */
+	spin_lock_irqsave(&ppp_stat->ppp_lock, flag);
+	wait = ppp_stat->busy;
+	spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
+
+	if (wait) {
+		ret = wait_for_completion_interruptible_timeout(
+		   &ppp_stat->ppp_comp, 5 * HZ);
+		if (!ret)
+			pr_err("%s: Timed out waiting for the MDP.\n",
+				__func__);
+	}
+
+	return ret;
+}
+
+uint32_t mdp3_calc_tpval(struct ppp_img_desc *img, uint32_t old_tp)
+{
+	uint32_t tpVal;
+	uint8_t plane_tp;
+
+	tpVal = 0;
+	if ((img->color_fmt == MDP_RGB_565)
+	    || (img->color_fmt == MDP_BGR_565)) {
+		/* transparent color conversion into 24 bpp */
+		plane_tp = (uint8_t) ((old_tp & 0xF800) >> 11);
+		tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16;
+		plane_tp = (uint8_t) (old_tp & 0x1F);
+		tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8;
+
+		plane_tp = (uint8_t) ((old_tp & 0x7E0) >> 5);
+		tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4));
+	} else {
+		/* 24bit RGB to RBG conversion */
+		tpVal = (old_tp & 0xFF00) >> 8;
+		tpVal |= (old_tp & 0xFF) << 8;
+		tpVal |= (old_tp & 0xFF0000);
+	}
+
+	return tpVal;
+}
+
+static void mdp3_ppp_intr_handler(int type, void *arg)
+{
+	spin_lock(&ppp_stat->ppp_lock);
+	ppp_stat->busy = false;
+	spin_unlock(&ppp_stat->ppp_lock);
+	complete(&ppp_stat->ppp_comp);
+	mdp3_irq_disable_nosync(type);
+}
+
+static int mdp3_ppp_callback_setup(void)
+{
+	int rc;
+	struct mdp3_intr_cb ppp_done_cb = {
+		.cb = mdp3_ppp_intr_handler,
+		.data = NULL,
+	};
+
+	rc = mdp3_set_intr_callback(MDP3_PPP_DONE, &ppp_done_cb);
+	return rc;
+}
+
+void mdp3_ppp_kickoff(void)
+{
+	unsigned long flag;
+	mdp3_irq_enable(MDP3_PPP_DONE);
+
+	init_completion(&ppp_stat->ppp_comp);
+
+	spin_lock_irqsave(&ppp_stat->ppp_lock, flag);
+	ppp_stat->busy = true;
+	spin_unlock_irqrestore(&ppp_stat->ppp_lock, flag);
+	ppp_enable();
+
+	mdp3_ppp_pipe_wait();
+}
+
+int mdp3_ppp_turnon(struct ppp_blit_op *blit_op, int on_off)
+{
+	unsigned long clk_rate = 0, dst_rate = 0, src_rate = 0;
+	int ab = 0;
+	int ib = 0;
+	if (on_off) {
+		dst_rate = blit_op->dst.roi.width * blit_op->dst.roi.height;
+		src_rate = blit_op->src.roi.width * blit_op->src.roi.height;
+		clk_rate = max(dst_rate, src_rate);
+		clk_rate = clk_rate * 36 * 12;
+
+		ab = blit_op->dst.roi.width * blit_op->dst.roi.height *
+			ppp_bpp(blit_op->dst.color_fmt) * 2 +
+			blit_op->src.roi.width * blit_op->src.roi.height *
+			ppp_bpp(blit_op->src.color_fmt);
+		ab = ab * 120;
+		ib = (ab * 3) / 2;
+	}
+	mdp3_clk_enable(on_off);
+	mdp3_bus_scale_set_quota(MDP3_CLIENT_PPP, ab, ib);
+	return 0;
+}
+
+void mdp3_start_ppp(struct ppp_blit_op *blit_op)
+{
+	/* Wait for the pipe to clear */
+	do { } while (mdp3_ppp_pipe_wait() <= 0);
+	mutex_lock(&ppp_stat->config_mutex);
+	config_ppp_op_mode(blit_op);
+	mdp3_ppp_kickoff();
+	mutex_unlock(&ppp_stat->config_mutex);
+}
+
+static void mdp3_ppp_process_req(struct ppp_blit_op *blit_op,
+	struct mdp_blit_req *req, struct mdp3_img_data *src_data,
+	struct mdp3_img_data *dst_data)
+{
+	unsigned long srcp0_start, srcp0_len, dst_start, dst_len;
+	uint32_t dst_width, dst_height;
+
+	srcp0_start = (unsigned long) src_data->addr;
+	srcp0_len = (unsigned long) src_data->len;
+	dst_start = (unsigned long) dst_data->addr;
+	dst_len = (unsigned long) dst_data->len;
+
+	blit_op->dst.prop.width = req->dst.width;
+	blit_op->dst.prop.height = req->dst.height;
+
+	blit_op->dst.color_fmt = req->dst.format;
+	blit_op->dst.p0 = (void *) dst_start;
+	blit_op->dst.p0 += req->dst.offset;
+
+	blit_op->dst.roi.x = req->dst_rect.x;
+	blit_op->dst.roi.y = req->dst_rect.y;
+	blit_op->dst.roi.width = req->dst_rect.w;
+	blit_op->dst.roi.height = req->dst_rect.h;
+
+	blit_op->src.roi.x = req->src_rect.x;
+	blit_op->src.roi.y = req->src_rect.y;
+	blit_op->src.roi.width = req->src_rect.w;
+	blit_op->src.roi.height = req->src_rect.h;
+
+	blit_op->src.prop.width = req->src.width;
+	blit_op->src.color_fmt = req->src.format;
+
+
+	blit_op->src.p0 = (void *) (srcp0_start + req->src.offset);
+	if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO)
+		blit_op->src.p1 =
+			(void *) ((uint32_t) blit_op->src.p0 +
+				ALIGN((ALIGN(req->src.width, 32) *
+				ALIGN(req->src.height, 32)), 4096));
+	else
+		blit_op->src.p1 = (void *) ((uint32_t) blit_op->src.p0 +
+			req->src.width * req->src.height);
+
+	if (req->flags & MDP_IS_FG)
+		blit_op->mdp_op |= MDPOP_LAYER_IS_FG;
+
+	/* blending check */
+	if (req->transp_mask != MDP_TRANSP_NOP) {
+		blit_op->mdp_op |= MDPOP_TRANSP;
+		blit_op->blend.trans_color =
+			mdp3_calc_tpval(&blit_op->src, req->transp_mask);
+	} else {
+		blit_op->blend.trans_color = 0;
+	}
+
+	req->alpha &= 0xff;
+	if (req->alpha < MDP_ALPHA_NOP) {
+		blit_op->mdp_op |= MDPOP_ALPHAB;
+		blit_op->blend.const_alpha = req->alpha;
+	} else {
+		blit_op->blend.const_alpha = 0xff;
+	}
+
+	/* rotation check */
+	if (req->flags & MDP_FLIP_LR)
+		blit_op->mdp_op |= MDPOP_LR;
+	if (req->flags & MDP_FLIP_UD)
+		blit_op->mdp_op |= MDPOP_UD;
+	if (req->flags & MDP_ROT_90)
+		blit_op->mdp_op |= MDPOP_ROT90;
+	if (req->flags & MDP_DITHER)
+		blit_op->mdp_op |= MDPOP_DITHER;
+
+	if (req->flags & MDP_BLEND_FG_PREMULT)
+		blit_op->mdp_op |= MDPOP_FG_PM_ALPHA;
+
+	/* scale check */
+	if (req->flags & MDP_ROT_90) {
+		dst_width = req->dst_rect.h;
+		dst_height = req->dst_rect.w;
+	} else {
+		dst_width = req->dst_rect.w;
+		dst_height = req->dst_rect.h;
+	}
+
+	if ((blit_op->src.roi.width != dst_width) ||
+			(blit_op->src.roi.height != dst_height))
+		blit_op->mdp_op |= MDPOP_ASCALE;
+
+	if (req->flags & MDP_BLUR)
+		blit_op->mdp_op |= MDPOP_ASCALE | MDPOP_BLUR;
+}
+
+static void mdp3_ppp_tile_workaround(struct ppp_blit_op *blit_op,
+	struct mdp_blit_req *req)
+{
+	int dst_h, src_w, i;
+	uint32_t mdp_op = blit_op->mdp_op;
+
+	src_w = req->src_rect.w;
+	dst_h = blit_op->dst.roi.height;
+	/* bg tile fetching HW workaround */
+	for (i = 0; i < (req->dst_rect.h / 16); i++) {
+		/* this tile size */
+		blit_op->dst.roi.height = 16;
+		blit_op->src.roi.width =
+			(16 * req->src_rect.w) / req->dst_rect.h;
+
+		/* if it's out of scale range... */
+		if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+			 blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR)
+			blit_op->src.roi.width =
+				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+				MDP_MAX_X_SCALE_FACTOR;
+		else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+			  blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR)
+			blit_op->src.roi.width =
+				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+				MDP_MIN_X_SCALE_FACTOR;
+
+		mdp3_start_ppp(blit_op);
+
+		/* next tile location */
+		blit_op->dst.roi.y += 16;
+		blit_op->src.roi.x += blit_op->src.roi.width;
+
+		/* this is for a remainder update */
+		dst_h -= 16;
+		src_w -= blit_op->src.roi.width;
+		/* restore mdp_op since MDPOP_ASCALE have been cleared */
+		blit_op->mdp_op = mdp_op;
+	}
+
+	if ((dst_h < 0) || (src_w < 0))
+		pr_err
+			("msm_fb: mdp_blt_ex() unexpected result! line:%d\n",
+			 __LINE__);
+
+	/* remainder update */
+	if ((dst_h > 0) && (src_w > 0)) {
+		u32 tmp_v;
+
+		blit_op->dst.roi.height = dst_h;
+		blit_op->src.roi.width = src_w;
+
+		if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+			 blit_op->src.roi.width) > MDP_MAX_X_SCALE_FACTOR) {
+			tmp_v =
+				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+				MDP_MAX_X_SCALE_FACTOR +
+				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
+				MDP_MAX_X_SCALE_FACTOR ? 1 : 0;
+
+			/* move x location as roi width gets bigger */
+			blit_op->src.roi.x -= tmp_v - blit_op->src.roi.width;
+			blit_op->src.roi.width = tmp_v;
+		} else if (((MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+			 blit_op->src.roi.width) < MDP_MIN_X_SCALE_FACTOR) {
+			tmp_v =
+				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) /
+				MDP_MIN_X_SCALE_FACTOR +
+				(MDP_SCALE_Q_FACTOR * blit_op->dst.roi.height) %
+				MDP_MIN_X_SCALE_FACTOR ? 1 : 0;
+
+			/*
+			 * we don't move x location for continuity of
+			 * source image
+			 */
+			blit_op->src.roi.width = tmp_v;
+		}
+
+
+		mdp3_start_ppp(blit_op);
+	}
+}
+
+static int mdp3_ppp_blit_addr(struct msm_fb_data_type *mfd,
+	struct mdp_blit_req *req, struct mdp3_img_data *src_data,
+	struct mdp3_img_data *dst_data)
+{
+	struct ppp_blit_op blit_op;
+
+	memset(&blit_op, 0, sizeof(blit_op));
+
+	if (req->dst.format == MDP_FB_FORMAT)
+		req->dst.format =  mfd->fb_imgType;
+	if (req->src.format == MDP_FB_FORMAT)
+		req->src.format = mfd->fb_imgType;
+
+	if (mdp3_ppp_verify_req(req)) {
+		pr_err("%s: invalid image!\n", __func__);
+		return -EINVAL;
+	}
+
+	mdp3_ppp_process_req(&blit_op, req, src_data, dst_data);
+
+	mdp3_ppp_turnon(&blit_op, 1);
+
+	if (((blit_op.mdp_op & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
+	     (req->src.format == MDP_ARGB_8888) ||
+	     (req->src.format == MDP_BGRA_8888) ||
+	     (req->src.format == MDP_RGBA_8888)) &&
+	    (blit_op.mdp_op & MDPOP_ROT90) && (req->dst_rect.w <= 16)) {
+		mdp3_ppp_tile_workaround(&blit_op, req);
+	} else {
+		mdp3_start_ppp(&blit_op);
+	}
+
+	/* MDP cmd block disable */
+	mdp3_ppp_turnon(&blit_op, 0);
+
+	return 0;
+}
+
+static int mdp3_ppp_blit(struct msm_fb_data_type *mfd, struct mdp_blit_req *req)
+{
+	struct mdp3_img_data src_data;
+	struct mdp3_img_data dst_data;
+	int rc;
+	mdp3_ppp_iommu_attach();
+
+	mdp3_ppp_get_img(&req->src, req, &src_data);
+	if (src_data.len == 0) {
+		pr_err("mdp_ppp: couldn't retrieve src img from mem\n");
+		return -EINVAL;
+	}
+
+	mdp3_ppp_get_img(&req->dst, req, &dst_data);
+	if (dst_data.len == 0) {
+		mdp3_put_img(&src_data);
+		pr_err("mdp_ppp: couldn't retrieve dest img from mem\n");
+		return -EINVAL;
+	}
+
+	rc = mdp3_ppp_blit_addr(mfd, req, &src_data, &dst_data);
+	mdp3_put_img(&src_data);
+	mdp3_put_img(&dst_data);
+	mdp3_ppp_iommu_dettach();
+	return rc;
+}
+
+static int mdp3_ppp_blit_workaround(struct msm_fb_data_type *mfd,
+		struct mdp_blit_req *req, unsigned int remainder)
+{
+	int ret;
+	struct mdp_blit_req splitreq;
+	int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1;
+	int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1;
+
+	/* make new request as provide by user */
+	splitreq = *req;
+
+	/* break dest roi at width*/
+	d_y_0 = d_y_1 = req->dst_rect.y;
+	d_h_0 = d_h_1 = req->dst_rect.h;
+	d_x_0 = req->dst_rect.x;
+
+	if (remainder == 14 || remainder == 6)
+		d_w_1 = req->dst_rect.w / 2;
+	else
+		d_w_1 = (req->dst_rect.w - 1) / 2 - 1;
+
+	d_w_0 = req->dst_rect.w - d_w_1;
+	d_x_1 = d_x_0 + d_w_0;
+	/* blit first region */
+	if (((splitreq.flags & 0x07) == 0x07) ||
+		((splitreq.flags & 0x07) == 0x05) ||
+		((splitreq.flags & 0x07) == 0x02) ||
+		((splitreq.flags & 0x07) == 0x0)) {
+
+		if (splitreq.flags & MDP_ROT_90) {
+			s_x_0 = s_x_1 = req->src_rect.x;
+			s_w_0 = s_w_1 = req->src_rect.w;
+			s_y_0 = req->src_rect.y;
+			s_h_1 = (req->src_rect.h * d_w_1) /
+				req->dst_rect.w;
+			s_h_0 = req->src_rect.h - s_h_1;
+			s_y_1 = s_y_0 + s_h_0;
+			if (d_w_1 >= 8 * s_h_1) {
+				s_h_1++;
+				s_y_1--;
+			}
+		} else {
+			s_y_0 = s_y_1 = req->src_rect.y;
+			s_h_0 = s_h_1 = req->src_rect.h;
+			s_x_0 = req->src_rect.x;
+			s_w_1 = (req->src_rect.w * d_w_1) /
+				req->dst_rect.w;
+			s_w_0 = req->src_rect.w - s_w_1;
+			s_x_1 = s_x_0 + s_w_0;
+			if (d_w_1 >= 8 * s_w_1) {
+				s_w_1++;
+				s_x_1--;
+			}
+		}
+
+		splitreq.src_rect.h = s_h_0;
+		splitreq.src_rect.y = s_y_0;
+		splitreq.dst_rect.h = d_h_0;
+		splitreq.dst_rect.y = d_y_0;
+		splitreq.src_rect.x = s_x_0;
+		splitreq.src_rect.w = s_w_0;
+		splitreq.dst_rect.x = d_x_0;
+		splitreq.dst_rect.w = d_w_0;
+	} else {
+		if (splitreq.flags & MDP_ROT_90) {
+			s_x_0 = s_x_1 = req->src_rect.x;
+			s_w_0 = s_w_1 = req->src_rect.w;
+			s_y_0 = req->src_rect.y;
+			s_h_1 = (req->src_rect.h * d_w_0) /
+				req->dst_rect.w;
+			s_h_0 = req->src_rect.h - s_h_1;
+			s_y_1 = s_y_0 + s_h_0;
+			if (d_w_0 >= 8 * s_h_1) {
+				s_h_1++;
+				s_y_1--;
+			}
+		} else {
+			s_y_0 = s_y_1 = req->src_rect.y;
+			s_h_0 = s_h_1 = req->src_rect.h;
+			s_x_0 = req->src_rect.x;
+			s_w_1 = (req->src_rect.w * d_w_0) /
+				req->dst_rect.w;
+			s_w_0 = req->src_rect.w - s_w_1;
+			s_x_1 = s_x_0 + s_w_0;
+			if (d_w_0 >= 8 * s_w_1) {
+				s_w_1++;
+				s_x_1--;
+			}
+		}
+		splitreq.src_rect.h = s_h_0;
+		splitreq.src_rect.y = s_y_0;
+		splitreq.dst_rect.h = d_h_1;
+		splitreq.dst_rect.y = d_y_1;
+		splitreq.src_rect.x = s_x_0;
+		splitreq.src_rect.w = s_w_0;
+		splitreq.dst_rect.x = d_x_1;
+		splitreq.dst_rect.w = d_w_1;
+	}
+
+	/* No need to split in height */
+	ret = mdp3_ppp_blit(mfd, &splitreq);
+
+	if (ret)
+		return ret;
+	/* blit second region */
+	if (((splitreq.flags & 0x07) == 0x07) ||
+		((splitreq.flags & 0x07) == 0x05) ||
+		((splitreq.flags & 0x07) == 0x02) ||
+		((splitreq.flags & 0x07) == 0x0)) {
+		splitreq.src_rect.h = s_h_1;
+		splitreq.src_rect.y = s_y_1;
+		splitreq.dst_rect.h = d_h_1;
+		splitreq.dst_rect.y = d_y_1;
+		splitreq.src_rect.x = s_x_1;
+		splitreq.src_rect.w = s_w_1;
+		splitreq.dst_rect.x = d_x_1;
+		splitreq.dst_rect.w = d_w_1;
+	} else {
+		splitreq.src_rect.h = s_h_1;
+		splitreq.src_rect.y = s_y_1;
+		splitreq.dst_rect.h = d_h_0;
+		splitreq.dst_rect.y = d_y_0;
+		splitreq.src_rect.x = s_x_1;
+		splitreq.src_rect.w = s_w_1;
+		splitreq.dst_rect.x = d_x_0;
+		splitreq.dst_rect.w = d_w_0;
+	}
+
+	/* No need to split in height ... just width */
+	return mdp3_ppp_blit(mfd, &splitreq);
+}
+
+int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
+		struct mdp_blit_req *req)
+{
+	int ret;
+	unsigned int remainder = 0, is_bpp_4 = 0;
+
+	if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) {
+		pr_err("mdp_ppp: src img of zero size!\n");
+		return -EINVAL;
+	}
+	if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
+		return 0;
+
+	if (req->flags & MDP_ROT_90) {
+		if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) ||
+			(req->dst_rect.w != req->src_rect.h))) ||
+			((req->dst_rect.w == 1) && ((req->src_rect.h != 1) ||
+			(req->dst_rect.h != req->src_rect.w)))) {
+			pr_err("mdp_ppp: error scaling when size is 1!\n");
+			return -EINVAL;
+		}
+	} else {
+		if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) ||
+			(req->dst_rect.h != req->src_rect.h))) ||
+			((req->dst_rect.h == 1) && ((req->src_rect.h != 1) ||
+			(req->dst_rect.w != req->src_rect.w)))) {
+			pr_err("mdp_ppp: error scaling when size is 1!\n");
+			return -EINVAL;
+		}
+	}
+
+	/* MDP width split workaround */
+	remainder = (req->dst_rect.w) % 16;
+	ret = ppp_get_bpp(req->dst.format, mfd->fb_imgType);
+	if (ret <= 0) {
+		pr_err("mdp_ppp: incorrect bpp!\n");
+		return -EINVAL;
+	}
+	is_bpp_4 = (ret == 4) ? 1 : 0;
+
+	if ((is_bpp_4 && (remainder == 6 || remainder == 14)))
+		ret = mdp3_ppp_blit_workaround(mfd, req, remainder);
+	else
+		ret = mdp3_ppp_blit(mfd, req);
+
+	return ret;
+}
+
+int mdp3_ppp_res_init(void)
+{
+	ppp_stat = kmalloc(sizeof(struct ppp_status), GFP_KERNEL);
+	spin_lock_init(&ppp_stat->ppp_lock);
+	mutex_init(&ppp_stat->config_mutex);
+	ppp_stat->busy = false;
+	mdp3_ppp_callback_setup();
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdp3_ppp.h b/drivers/video/msm/mdss/mdp3_ppp.h
new file mode 100644
index 0000000..afac419
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp.h
@@ -0,0 +1,413 @@
+/* Copyright (c) 2007, 2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MDP3_PPP_H
+#define MDP3_PPP_H
+#include "mdp3.h"
+#include "mdss_fb.h"
+
+#define PPP_WRITEL(val, off) MDP3_REG_WRITE(off, val)
+
+#define MAX_BLIT_REQ 256
+#define PPP_UPSCALE_MAX 64
+#define PPP_BLUR_SCALE_MAX 128
+#define PPP_LUT_MAX 256
+
+/* MDP PPP Operations */
+#define MDPOP_NOP               0
+#define MDPOP_LR                BIT(0)	/* left to right flip */
+#define MDPOP_UD                BIT(1)	/* up and down flip */
+#define MDPOP_ROT90             BIT(2)	/* rotate image to 90 degree */
+#define MDPOP_ROT180            (MDPOP_UD|MDPOP_LR)
+#define MDPOP_ROT270            (MDPOP_ROT90|MDPOP_UD|MDPOP_LR)
+#define MDPOP_ASCALE            BIT(7)
+#define MDPOP_ALPHAB            BIT(8)	/* enable alpha blending */
+#define MDPOP_TRANSP            BIT(9)	/* enable transparency */
+#define MDPOP_DITHER            BIT(10)	/* enable dither */
+#define MDPOP_SHARPENING		BIT(11) /* enable sharpening */
+#define MDPOP_BLUR				BIT(12) /* enable blur */
+#define MDPOP_FG_PM_ALPHA       BIT(13)
+#define MDPOP_LAYER_IS_FG       BIT(14)
+
+#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD)
+
+#define PPP_OP_CONVERT_YCBCR2RGB BIT(2)
+#define PPP_OP_CONVERT_ON		BIT(3)
+#define PPP_OP_SCALE_X_ON		BIT(0)
+#define PPP_OP_SCALE_Y_ON		BIT(1)
+#define PPP_OP_ROT_ON			BIT(8)
+#define PPP_OP_ROT_90			BIT(9)
+#define PPP_OP_FLIP_LR			BIT(10)
+#define PPP_OP_FLIP_UD			BIT(11)
+#define PPP_OP_BLEND_ON			BIT(12)
+#define PPP_OP_BLEND_CONSTANT_ALPHA BIT(14)
+#define PPP_OP_DITHER_EN		BIT(16)
+#define PPP_BLEND_CALPHA_TRNASP BIT(24)
+
+#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0
+#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0
+#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE BIT(15)
+
+#define PPP_BLEND_BG_USE_ALPHA_SEL      (1 << 0)
+#define PPP_BLEND_BG_ALPHA_REVERSE      (1 << 3)
+#define PPP_BLEND_BG_SRCPIXEL_ALPHA     (0 << 1)
+#define PPP_BLEND_BG_DSTPIXEL_ALPHA     (1 << 1)
+#define PPP_BLEND_BG_CONSTANT_ALPHA     (2 << 1)
+#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24)
+#define PPP_OP_BG_CHROMA_H2V1 BIT(25)
+
+#define CLR_G 0x0
+#define CLR_B 0x1
+#define CLR_R 0x2
+#define CLR_ALPHA 0x3
+
+#define CLR_Y  CLR_G
+#define CLR_CB CLR_B
+#define CLR_CR CLR_R
+
+/* from lsb to msb */
+#define PPP_GET_PACK_PATTERN(a, x, y, z, bit) \
+	(((a)<<(bit*3))|((x)<<(bit*2))|((y)<<bit)|(z))
+
+/* Frame unpacking */
+#define PPP_C0G_8BITS (BIT(1)|BIT(0))
+#define PPP_C1B_8BITS (BIT(3)|BIT(2))
+#define PPP_C2R_8BITS (BIT(5)|BIT(4))
+#define PPP_C3A_8BITS (BIT(7)|BIT(6))
+
+#define PPP_C0G_6BITS BIT(1)
+#define PPP_C1B_6BITS BIT(3)
+#define PPP_C2R_6BITS BIT(5)
+
+#define PPP_C0G_5BITS BIT(0)
+#define PPP_C1B_5BITS BIT(2)
+#define PPP_C2R_5BITS BIT(4)
+
+#define PPP_SRC_C3_ALPHA_EN BIT(8)
+
+#define PPP_SRC_BPP_INTERLVD_1BYTES 0
+#define PPP_SRC_BPP_INTERLVD_2BYTES BIT(9)
+#define PPP_SRC_BPP_INTERLVD_3BYTES BIT(10)
+#define PPP_SRC_BPP_INTERLVD_4BYTES (BIT(10)|BIT(9))
+
+#define PPP_SRC_BPP_ROI_ODD_X BIT(11)
+#define PPP_SRC_BPP_ROI_ODD_Y BIT(12)
+#define PPP_SRC_INTERLVD_2COMPONENTS BIT(13)
+#define PPP_SRC_INTERLVD_3COMPONENTS BIT(14)
+#define PPP_SRC_INTERLVD_4COMPONENTS (BIT(14)|BIT(13))
+
+#define PPP_SRC_UNPACK_TIGHT BIT(17)
+#define PPP_SRC_UNPACK_LOOSE 0
+#define PPP_SRC_UNPACK_ALIGN_LSB 0
+#define PPP_SRC_UNPACK_ALIGN_MSB BIT(18)
+
+#define PPP_SRC_FETCH_PLANES_INTERLVD 0
+#define PPP_SRC_FETCH_PLANES_PSEUDOPLNR BIT(20)
+
+#define PPP_OP_SRC_CHROMA_H2V1 BIT(18)
+#define PPP_OP_SRC_CHROMA_H1V2 BIT(19)
+#define PPP_OP_SRC_CHROMA_420 (BIT(18)|BIT(19))
+#define PPP_OP_SRC_CHROMA_OFFSITE BIT(20)
+
+#define PPP_DST_PACKET_CNT_INTERLVD_2ELEM BIT(9)
+#define PPP_DST_PACKET_CNT_INTERLVD_3ELEM BIT(10)
+#define PPP_DST_PACKET_CNT_INTERLVD_4ELEM (BIT(10)|BIT(9))
+#define PPP_DST_PACKET_CNT_INTERLVD_6ELEM (BIT(11)|BIT(9))
+
+#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
+#define PPP_DST_C3ALPHA_EN BIT(8)
+
+#define PPP_DST_PACK_LOOSE 0
+#define PPP_DST_PACK_TIGHT BIT(13)
+#define PPP_DST_PACK_ALIGN_LSB 0
+#define PPP_DST_PACK_ALIGN_MSB BIT(14)
+
+#define PPP_DST_OUT_SEL_AXI 0
+#define PPP_DST_OUT_SEL_MDDI BIT(15)
+
+#define PPP_DST_BPP_2BYTES BIT(16)
+#define PPP_DST_BPP_3BYTES BIT(17)
+#define PPP_DST_BPP_4BYTES (BIT(17)|BIT(16))
+
+#define PPP_DST_PLANE_INTERLVD 0
+#define PPP_DST_PLANE_PLANAR BIT(18)
+#define PPP_DST_PLANE_PSEUDOPLN BIT(19)
+
+#define PPP_OP_DST_CHROMA_H2V1 BIT(21)
+#define PPP_OP_DST_CHROMA_420 (BIT(21)|BIT(22))
+#define PPP_OP_COLOR_SPACE_YCBCR BIT(17)
+
+#define MDP_SCALE_Q_FACTOR 512
+#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
+#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
+#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
+#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
+
+#define MDP_TOP_LUMA       16
+#define MDP_TOP_CHROMA     0
+#define MDP_BOTTOM_LUMA    19
+#define MDP_BOTTOM_CHROMA  3
+#define MDP_LEFT_LUMA      22
+#define MDP_LEFT_CHROMA    6
+#define MDP_RIGHT_LUMA     25
+#define MDP_RIGHT_CHROMA   9
+
+#define MDP_RGB_565_SRC_REG (PPP_C2R_5BITS | PPP_C0G_6BITS | \
+	PPP_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+	PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+	PPP_SRC_UNPACK_ALIGN_LSB | \
+	PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_RGB_888_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+	PPP_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | \
+	PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+	PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_RGBX_8888_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+	PPP_C1B_8BITS | PPP_C3A_8BITS | \
+	PPP_SRC_C3_ALPHA_EN | PPP_SRC_BPP_INTERLVD_4BYTES | \
+	PPP_SRC_INTERLVD_4COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+	PPP_SRC_UNPACK_ALIGN_LSB | \
+	PPP_SRC_FETCH_PLANES_INTERLVD)
+
+#define MDP_Y_CBCR_H2V2_SRC_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+	PPP_C1B_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+	PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+	PPP_SRC_UNPACK_ALIGN_LSB | \
+	PPP_SRC_FETCH_PLANES_PSEUDOPLNR)
+
+#define MDP_YCRYCB_H2V1_SRC_REG (PPP_C2R_8BITS | \
+	PPP_C0G_8BITS | PPP_C1B_8BITS | \
+	PPP_C3A_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+	PPP_SRC_INTERLVD_4COMPONENTS | \
+	PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB)
+
+#define MDP_Y_CRCB_H2V1_SRC_REG (PPP_C2R_8BITS | \
+	PPP_C0G_8BITS | PPP_C1B_8BITS | \
+	PPP_C3A_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | \
+	PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | \
+	PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR)
+
+#define MDP_RGB_565_DST_REG (PPP_C0G_6BITS | \
+	PPP_C1B_5BITS | PPP_C2R_5BITS | \
+	PPP_DST_PACKET_CNT_INTERLVD_3ELEM | \
+	PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+	PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | \
+	PPP_DST_PLANE_INTERLVD)
+
+#define MDP_RGB_888_DST_REG (PPP_C0G_8BITS | \
+	PPP_C1B_8BITS | PPP_C2R_8BITS | \
+	PPP_DST_PACKET_CNT_INTERLVD_3ELEM | PPP_DST_PACK_TIGHT | \
+	PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | \
+	PPP_DST_BPP_3BYTES | PPP_DST_PLANE_INTERLVD)
+
+#define MDP_RGBX_8888_DST_REG (PPP_C0G_8BITS | \
+	PPP_C1B_8BITS | PPP_C2R_8BITS | PPP_C3A_8BITS | \
+	PPP_DST_C3ALPHA_EN | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | \
+	PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+	PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_4BYTES | \
+	PPP_DST_PLANE_INTERLVD)
+
+#define MDP_Y_CBCR_H2V2_DST_REG (PPP_C2R_8BITS | \
+	PPP_C0G_8BITS | PPP_C1B_8BITS | PPP_C3A_8BITS | \
+	PPP_DST_PACKET_CNT_INTERLVD_2ELEM | \
+	PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+	PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES)
+
+#define MDP_YCRYCB_H2V1_DST_REG (PPP_C2R_8BITS | PPP_C0G_8BITS | \
+	PPP_C1B_8BITS | PPP_C3A_8BITS | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | \
+	PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | \
+	PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | \
+	PPP_DST_PLANE_INTERLVD)
+
+#define MDP_Y_CRCB_H2V1_DST_REG (PPP_C2R_8BITS | \
+	PPP_C0G_8BITS | PPP_C1B_8BITS | PPP_C3A_8BITS | \
+	PPP_DST_PACKET_CNT_INTERLVD_2ELEM | PPP_DST_PACK_TIGHT | \
+	PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | \
+	PPP_DST_BPP_2BYTES)
+
+/* LUT */
+#define MDP_LUT_C0_EN BIT(5)
+#define MDP_LUT_C1_EN BIT(6)
+#define MDP_LUT_C2_EN BIT(7)
+
+/* Dither */
+#define MDP_OP_DITHER_EN BIT(16)
+
+/* Rotator */
+#define MDP_OP_ROT_ON BIT(8)
+#define MDP_OP_ROT_90 BIT(9)
+#define MDP_OP_FLIP_LR BIT(10)
+#define MDP_OP_FLIP_UD BIT(11)
+
+/* Blend */
+#define MDP_OP_BLEND_EN BIT(12)
+#define MDP_OP_BLEND_EQ_SEL BIT(15)
+#define MDP_OP_BLEND_TRANSP_EN BIT(24)
+#define MDP_BLEND_MASK (MDP_OP_BLEND_EN | MDP_OP_BLEND_EQ_SEL | \
+	MDP_OP_BLEND_TRANSP_EN | BIT(14) | BIT(13))
+
+#define MDP_BLEND_ALPHA_SEL 13
+#define MDP_BLEND_ALPHA_MASK 0x3
+#define MDP_BLEND_CONST_ALPHA 24
+#define MDP_BLEND_TRASP_COL_MASK 0xFFFFFF
+
+/* CSC Matrix */
+#define MDP_CSC_RGB2YUV		0
+#define MDP_CSC_YUV2RGB		1
+
+#define MDP_CSC_SIZE	9
+#define MDP_BV_SIZE		3
+#define MDP_LV_SIZE		4
+
+enum ppp_lut_type {
+	LUT_PRE_TABLE = 0,
+	LUT_POST_TABLE,
+};
+
+enum ppp_csc_matrix {
+	CSC_PRIMARY_MATRIX = 0,
+	CSC_SECONDARY_MATRIX,
+};
+
+/* scale tables */
+enum {
+	PPP_DOWNSCALE_PT2TOPT4,
+	PPP_DOWNSCALE_PT4TOPT6,
+	PPP_DOWNSCALE_PT6TOPT8,
+	PPP_DOWNSCALE_PT8TOPT1,
+	PPP_DOWNSCALE_MAX,
+};
+
+struct ppp_table {
+	uint32_t reg;
+	uint32_t val;
+};
+
+struct ppp_csc_table {
+	int direction;			/* MDP_CCS_RGB2YUV or YUV2RGB */
+	uint16_t fwd_matrix[MDP_CCS_SIZE];	/* 3x3 color coefficients */
+	uint16_t rev_matrix[MDP_CCS_SIZE];	/* 3x3 color coefficients */
+	uint16_t bv[MDP_BV_SIZE];	/* 1x3 bias vector */
+	uint16_t lv[MDP_LV_SIZE];	/* 1x3 limit vector */
+};
+
+struct ppp_blend {
+	int const_alpha;
+	int trans_color; /*color keying*/
+};
+
+struct ppp_img_prop {
+	int32_t x;
+	int32_t y;
+	uint32_t width;
+	uint32_t height;
+};
+
+struct ppp_img_desc {
+	struct ppp_img_prop prop;
+	struct ppp_img_prop roi;
+	int color_fmt;
+	void *p0;  /* plane 0 */
+	void *p1;
+	void *p3;
+	int stride0;
+	int stride1;
+	int stride2;
+};
+
+struct ppp_blit_op {
+	struct ppp_img_desc src;
+	struct ppp_img_desc dst;
+	struct ppp_img_desc bg;
+	struct ppp_blend blend;
+	uint32_t mdp_op; /* Operations */
+};
+
+struct ppp_edge_rep {
+	uint32_t dst_roi_width;
+	uint32_t dst_roi_height;
+	uint32_t is_scale_enabled;
+
+	/*
+	 * positions of the luma pixel(relative to the image ) required for
+	 * scaling the ROI
+	 */
+	int32_t luma_interp_point_left;
+	int32_t luma_interp_point_right;
+	int32_t luma_interp_point_top;
+	int32_t luma_interp_point_bottom;
+
+	/*
+	 * positions of the chroma pixel(relative to the image ) required for
+	 * interpolating a chroma value at all required luma positions
+	 */
+	int32_t chroma_interp_point_left;
+	int32_t chroma_interp_point_right;
+	int32_t chroma_interp_point_top;
+	int32_t chroma_interp_point_bottom;
+
+	/*
+	 * a rectangular region within the chroma plane of the "image".
+	 * Chroma pixels falling inside of this rectangle belongs to the ROI
+	 */
+	int32_t chroma_bound_left;
+	int32_t chroma_bound_right;
+	int32_t chroma_bound_top;
+	int32_t chroma_bound_bottom;
+
+	/*
+	 * number of chroma pixels to replicate on the left, right,
+	 * top and bottom edge of the ROI.
+	 */
+	int32_t chroma_repeat_left;
+	int32_t chroma_repeat_right;
+	int32_t chroma_repeat_top;
+	int32_t chroma_repeat_bottom;
+
+	/*
+	 * number of luma pixels to replicate on the left, right,
+	 * top and bottom edge of the ROI.
+	 */
+	int32_t luma_repeat_left;
+	int32_t luma_repeat_right;
+	int32_t luma_repeat_top;
+	int32_t luma_repeat_bottom;
+};
+
+/* func for ppp register values */
+uint32_t ppp_bpp(uint32_t type);
+uint32_t ppp_src_config(uint32_t type);
+uint32_t ppp_out_config(uint32_t type);
+uint32_t ppp_pack_pattern(uint32_t type);
+uint32_t ppp_dst_op_reg(uint32_t type);
+uint32_t ppp_src_op_reg(uint32_t type);
+bool ppp_per_p_alpha(uint32_t type);
+bool ppp_multi_plane(uint32_t type);
+uint32_t *ppp_default_pre_lut(void);
+uint32_t *ppp_default_post_lut(void);
+struct ppp_csc_table *ppp_csc_rgb2yuv(void);
+struct ppp_csc_table *ppp_csc_table2(void);
+void ppp_load_up_lut(void);
+void ppp_load_gaussian_lut(void);
+void ppp_load_x_scale_table(int idx);
+void ppp_load_y_scale_table(int idx);
+
+int mdp3_ppp_start_blit(struct msm_fb_data_type *mfd,
+	struct mdp_blit_req *req);
+int mdp3_ppp_res_init(void);
+int mdp3_ppp_init(void);
+int config_ppp_op_mode(struct ppp_blit_op *blit_op);
+void ppp_enable(void);
+
+#endif
diff --git a/drivers/video/msm/mdss/mdp3_ppp_data.c b/drivers/video/msm/mdss/mdp3_ppp_data.c
new file mode 100644
index 0000000..d68faad
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp_data.c
@@ -0,0 +1,1572 @@
+/* Copyright (c) 2007, 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/types.h>
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+
+/* bg_config_lut not needed since it is same as src */
+const uint32_t src_cfg_lut[MDP_IMGTYPE_LIMIT] = {
+	[MDP_RGB_565] = MDP_RGB_565_SRC_REG,
+	[MDP_BGR_565] = MDP_RGB_565_SRC_REG,
+	[MDP_RGB_888] = MDP_RGB_888_SRC_REG,
+	[MDP_BGR_888] = MDP_RGB_888_SRC_REG,
+	[MDP_BGRA_8888] = MDP_RGBX_8888_SRC_REG,
+	[MDP_RGBA_8888] = MDP_RGBX_8888_SRC_REG,
+	[MDP_ARGB_8888] = MDP_RGBX_8888_SRC_REG,
+	[MDP_XRGB_8888] = MDP_RGBX_8888_SRC_REG,
+	[MDP_RGBX_8888] = MDP_RGBX_8888_SRC_REG,
+	[MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG,
+	[MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_SRC_REG,
+	[MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_SRC_REG,
+	[MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_SRC_REG,
+	[MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
+	[MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_SRC_REG,
+};
+
+const uint32_t out_cfg_lut[MDP_IMGTYPE_LIMIT] = {
+	[MDP_RGB_565] = MDP_RGB_565_DST_REG,
+	[MDP_BGR_565] = MDP_RGB_565_DST_REG,
+	[MDP_RGB_888] = MDP_RGB_888_DST_REG,
+	[MDP_BGR_888] = MDP_RGB_888_DST_REG,
+	[MDP_BGRA_8888] = MDP_RGBX_8888_DST_REG,
+	[MDP_RGBA_8888] = MDP_RGBX_8888_DST_REG,
+	[MDP_ARGB_8888] = MDP_RGBX_8888_DST_REG,
+	[MDP_XRGB_8888] = MDP_RGBX_8888_DST_REG,
+	[MDP_RGBX_8888] = MDP_RGBX_8888_DST_REG,
+	[MDP_Y_CRCB_H2V2] = MDP_Y_CBCR_H2V2_DST_REG,
+	[MDP_Y_CBCR_H2V2] = MDP_Y_CBCR_H2V2_DST_REG,
+	[MDP_Y_CBCR_H2V2_ADRENO] = MDP_Y_CBCR_H2V2_DST_REG,
+	[MDP_YCRYCB_H2V1] = MDP_YCRYCB_H2V1_DST_REG,
+	[MDP_Y_CBCR_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
+	[MDP_Y_CRCB_H2V1] = MDP_Y_CRCB_H2V1_DST_REG,
+};
+
+const uint32_t pack_patt_lut[MDP_IMGTYPE_LIMIT] = {
+	[MDP_RGB_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+	[MDP_BGR_565] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+	[MDP_RGB_888] = PPP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
+	[MDP_BGR_888] = PPP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
+	[MDP_BGRA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+		CLR_G, CLR_B, 8),
+	[MDP_RGBA_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+		CLR_G, CLR_B, 8),
+	[MDP_ARGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+		CLR_G, CLR_B, 8),
+	[MDP_XRGB_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+		CLR_G, CLR_B, 8),
+	[MDP_RGBX_8888] = PPP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R,
+		CLR_G, CLR_B, 8),
+	[MDP_Y_CRCB_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+	[MDP_Y_CBCR_H2V2] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
+	[MDP_Y_CBCR_H2V2_ADRENO] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB,
+		CLR_CR, 8),
+	[MDP_YCRYCB_H2V1] = PPP_GET_PACK_PATTERN(CLR_Y,
+		CLR_CR, CLR_Y, CLR_CB, 8),
+	[MDP_Y_CBCR_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
+	[MDP_Y_CRCB_H2V1] = PPP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
+};
+
+const uint32_t dst_op_reg[MDP_IMGTYPE_LIMIT] = {
+	[MDP_Y_CRCB_H2V2] = PPP_OP_DST_CHROMA_420,
+	[MDP_Y_CBCR_H2V2] = PPP_OP_DST_CHROMA_420,
+	[MDP_Y_CBCR_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+	[MDP_Y_CRCB_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+	[MDP_YCRYCB_H2V1] = PPP_OP_DST_CHROMA_H2V1,
+};
+
+const uint32_t src_op_reg[MDP_IMGTYPE_LIMIT] = {
+	[MDP_Y_CRCB_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR,
+	[MDP_Y_CBCR_H2V2] = PPP_OP_SRC_CHROMA_420 | PPP_OP_COLOR_SPACE_YCBCR,
+	[MDP_Y_CBCR_H2V2_ADRENO] = PPP_OP_SRC_CHROMA_420 |
+			PPP_OP_COLOR_SPACE_YCBCR,
+	[MDP_Y_CBCR_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+	[MDP_Y_CRCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+	[MDP_YCRYCB_H2V1] = PPP_OP_SRC_CHROMA_H2V1,
+};
+
+const uint32_t bytes_per_pixel[MDP_IMGTYPE_LIMIT] = {
+	[MDP_RGB_565] = 2,
+	[MDP_BGR_565] = 2,
+	[MDP_RGB_888] = 3,
+	[MDP_BGR_888] = 3,
+	[MDP_XRGB_8888] = 4,
+	[MDP_ARGB_8888] = 4,
+	[MDP_RGBA_8888] = 4,
+	[MDP_BGRA_8888] = 4,
+	[MDP_RGBX_8888] = 4,
+	[MDP_Y_CBCR_H2V1] = 1,
+	[MDP_Y_CBCR_H2V2] = 1,
+	[MDP_Y_CBCR_H2V2_ADRENO] = 1,
+	[MDP_Y_CRCB_H2V1] = 1,
+	[MDP_Y_CRCB_H2V2] = 1,
+	[MDP_YCRYCB_H2V1] = 2,
+};
+
+const bool per_pixel_alpha[MDP_IMGTYPE_LIMIT] = {
+	[MDP_BGRA_8888] = true,
+	[MDP_RGBA_8888] = true,
+	[MDP_ARGB_8888] = true,
+};
+
+const bool multi_plane[MDP_IMGTYPE_LIMIT] = {
+	[MDP_Y_CRCB_H2V2] = true,
+	[MDP_Y_CBCR_H2V2] = true,
+	[MDP_Y_CBCR_H2V1] = true,
+	[MDP_Y_CRCB_H2V1] = true,
+};
+
+/* lut default */
+uint32_t default_pre_lut_val[PPP_LUT_MAX] = {
+	0x0,
+	0x151515,
+	0x1d1d1d,
+	0x232323,
+	0x272727,
+	0x2b2b2b,
+	0x2f2f2f,
+	0x333333,
+	0x363636,
+	0x393939,
+	0x3b3b3b,
+	0x3e3e3e,
+	0x404040,
+	0x434343,
+	0x454545,
+	0x474747,
+	0x494949,
+	0x4b4b4b,
+	0x4d4d4d,
+	0x4f4f4f,
+	0x515151,
+	0x535353,
+	0x555555,
+	0x565656,
+	0x585858,
+	0x5a5a5a,
+	0x5b5b5b,
+	0x5d5d5d,
+	0x5e5e5e,
+	0x606060,
+	0x616161,
+	0x636363,
+	0x646464,
+	0x666666,
+	0x676767,
+	0x686868,
+	0x6a6a6a,
+	0x6b6b6b,
+	0x6c6c6c,
+	0x6e6e6e,
+	0x6f6f6f,
+	0x707070,
+	0x717171,
+	0x727272,
+	0x747474,
+	0x757575,
+	0x767676,
+	0x777777,
+	0x787878,
+	0x797979,
+	0x7a7a7a,
+	0x7c7c7c,
+	0x7d7d7d,
+	0x7e7e7e,
+	0x7f7f7f,
+	0x808080,
+	0x818181,
+	0x828282,
+	0x838383,
+	0x848484,
+	0x858585,
+	0x868686,
+	0x878787,
+	0x888888,
+	0x898989,
+	0x8a8a8a,
+	0x8b8b8b,
+	0x8c8c8c,
+	0x8d8d8d,
+	0x8e8e8e,
+	0x8f8f8f,
+	0x8f8f8f,
+	0x909090,
+	0x919191,
+	0x929292,
+	0x939393,
+	0x949494,
+	0x959595,
+	0x969696,
+	0x969696,
+	0x979797,
+	0x989898,
+	0x999999,
+	0x9a9a9a,
+	0x9b9b9b,
+	0x9c9c9c,
+	0x9c9c9c,
+	0x9d9d9d,
+	0x9e9e9e,
+	0x9f9f9f,
+	0xa0a0a0,
+	0xa0a0a0,
+	0xa1a1a1,
+	0xa2a2a2,
+	0xa3a3a3,
+	0xa4a4a4,
+	0xa4a4a4,
+	0xa5a5a5,
+	0xa6a6a6,
+	0xa7a7a7,
+	0xa7a7a7,
+	0xa8a8a8,
+	0xa9a9a9,
+	0xaaaaaa,
+	0xaaaaaa,
+	0xababab,
+	0xacacac,
+	0xadadad,
+	0xadadad,
+	0xaeaeae,
+	0xafafaf,
+	0xafafaf,
+	0xb0b0b0,
+	0xb1b1b1,
+	0xb2b2b2,
+	0xb2b2b2,
+	0xb3b3b3,
+	0xb4b4b4,
+	0xb4b4b4,
+	0xb5b5b5,
+	0xb6b6b6,
+	0xb6b6b6,
+	0xb7b7b7,
+	0xb8b8b8,
+	0xb8b8b8,
+	0xb9b9b9,
+	0xbababa,
+	0xbababa,
+	0xbbbbbb,
+	0xbcbcbc,
+	0xbcbcbc,
+	0xbdbdbd,
+	0xbebebe,
+	0xbebebe,
+	0xbfbfbf,
+	0xc0c0c0,
+	0xc0c0c0,
+	0xc1c1c1,
+	0xc1c1c1,
+	0xc2c2c2,
+	0xc3c3c3,
+	0xc3c3c3,
+	0xc4c4c4,
+	0xc5c5c5,
+	0xc5c5c5,
+	0xc6c6c6,
+	0xc6c6c6,
+	0xc7c7c7,
+	0xc8c8c8,
+	0xc8c8c8,
+	0xc9c9c9,
+	0xc9c9c9,
+	0xcacaca,
+	0xcbcbcb,
+	0xcbcbcb,
+	0xcccccc,
+	0xcccccc,
+	0xcdcdcd,
+	0xcecece,
+	0xcecece,
+	0xcfcfcf,
+	0xcfcfcf,
+	0xd0d0d0,
+	0xd0d0d0,
+	0xd1d1d1,
+	0xd2d2d2,
+	0xd2d2d2,
+	0xd3d3d3,
+	0xd3d3d3,
+	0xd4d4d4,
+	0xd4d4d4,
+	0xd5d5d5,
+	0xd6d6d6,
+	0xd6d6d6,
+	0xd7d7d7,
+	0xd7d7d7,
+	0xd8d8d8,
+	0xd8d8d8,
+	0xd9d9d9,
+	0xd9d9d9,
+	0xdadada,
+	0xdbdbdb,
+	0xdbdbdb,
+	0xdcdcdc,
+	0xdcdcdc,
+	0xdddddd,
+	0xdddddd,
+	0xdedede,
+	0xdedede,
+	0xdfdfdf,
+	0xdfdfdf,
+	0xe0e0e0,
+	0xe0e0e0,
+	0xe1e1e1,
+	0xe1e1e1,
+	0xe2e2e2,
+	0xe3e3e3,
+	0xe3e3e3,
+	0xe4e4e4,
+	0xe4e4e4,
+	0xe5e5e5,
+	0xe5e5e5,
+	0xe6e6e6,
+	0xe6e6e6,
+	0xe7e7e7,
+	0xe7e7e7,
+	0xe8e8e8,
+	0xe8e8e8,
+	0xe9e9e9,
+	0xe9e9e9,
+	0xeaeaea,
+	0xeaeaea,
+	0xebebeb,
+	0xebebeb,
+	0xececec,
+	0xececec,
+	0xededed,
+	0xededed,
+	0xeeeeee,
+	0xeeeeee,
+	0xefefef,
+	0xefefef,
+	0xf0f0f0,
+	0xf0f0f0,
+	0xf1f1f1,
+	0xf1f1f1,
+	0xf2f2f2,
+	0xf2f2f2,
+	0xf2f2f2,
+	0xf3f3f3,
+	0xf3f3f3,
+	0xf4f4f4,
+	0xf4f4f4,
+	0xf5f5f5,
+	0xf5f5f5,
+	0xf6f6f6,
+	0xf6f6f6,
+	0xf7f7f7,
+	0xf7f7f7,
+	0xf8f8f8,
+	0xf8f8f8,
+	0xf9f9f9,
+	0xf9f9f9,
+	0xfafafa,
+	0xfafafa,
+	0xfafafa,
+	0xfbfbfb,
+	0xfbfbfb,
+	0xfcfcfc,
+	0xfcfcfc,
+	0xfdfdfd,
+	0xfdfdfd,
+	0xfefefe,
+	0xfefefe,
+	0xffffff,
+	0xffffff,
+};
+
+uint32_t default_post_lut_val[PPP_LUT_MAX] = {
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x0,
+	0x10101,
+	0x10101,
+	0x10101,
+	0x10101,
+	0x10101,
+	0x10101,
+	0x10101,
+	0x10101,
+	0x10101,
+	0x10101,
+	0x20202,
+	0x20202,
+	0x20202,
+	0x20202,
+	0x20202,
+	0x20202,
+	0x30303,
+	0x30303,
+	0x30303,
+	0x30303,
+	0x30303,
+	0x40404,
+	0x40404,
+	0x40404,
+	0x40404,
+	0x40404,
+	0x50505,
+	0x50505,
+	0x50505,
+	0x50505,
+	0x60606,
+	0x60606,
+	0x60606,
+	0x70707,
+	0x70707,
+	0x70707,
+	0x70707,
+	0x80808,
+	0x80808,
+	0x80808,
+	0x90909,
+	0x90909,
+	0xa0a0a,
+	0xa0a0a,
+	0xa0a0a,
+	0xb0b0b,
+	0xb0b0b,
+	0xb0b0b,
+	0xc0c0c,
+	0xc0c0c,
+	0xd0d0d,
+	0xd0d0d,
+	0xe0e0e,
+	0xe0e0e,
+	0xe0e0e,
+	0xf0f0f,
+	0xf0f0f,
+	0x101010,
+	0x101010,
+	0x111111,
+	0x111111,
+	0x121212,
+	0x121212,
+	0x131313,
+	0x131313,
+	0x141414,
+	0x151515,
+	0x151515,
+	0x161616,
+	0x161616,
+	0x171717,
+	0x171717,
+	0x181818,
+	0x191919,
+	0x191919,
+	0x1a1a1a,
+	0x1b1b1b,
+	0x1b1b1b,
+	0x1c1c1c,
+	0x1c1c1c,
+	0x1d1d1d,
+	0x1e1e1e,
+	0x1f1f1f,
+	0x1f1f1f,
+	0x202020,
+	0x212121,
+	0x212121,
+	0x222222,
+	0x232323,
+	0x242424,
+	0x242424,
+	0x252525,
+	0x262626,
+	0x272727,
+	0x272727,
+	0x282828,
+	0x292929,
+	0x2a2a2a,
+	0x2b2b2b,
+	0x2c2c2c,
+	0x2c2c2c,
+	0x2d2d2d,
+	0x2e2e2e,
+	0x2f2f2f,
+	0x303030,
+	0x313131,
+	0x323232,
+	0x333333,
+	0x333333,
+	0x343434,
+	0x353535,
+	0x363636,
+	0x373737,
+	0x383838,
+	0x393939,
+	0x3a3a3a,
+	0x3b3b3b,
+	0x3c3c3c,
+	0x3d3d3d,
+	0x3e3e3e,
+	0x3f3f3f,
+	0x404040,
+	0x414141,
+	0x424242,
+	0x434343,
+	0x444444,
+	0x464646,
+	0x474747,
+	0x484848,
+	0x494949,
+	0x4a4a4a,
+	0x4b4b4b,
+	0x4c4c4c,
+	0x4d4d4d,
+	0x4f4f4f,
+	0x505050,
+	0x515151,
+	0x525252,
+	0x535353,
+	0x545454,
+	0x565656,
+	0x575757,
+	0x585858,
+	0x595959,
+	0x5b5b5b,
+	0x5c5c5c,
+	0x5d5d5d,
+	0x5e5e5e,
+	0x606060,
+	0x616161,
+	0x626262,
+	0x646464,
+	0x656565,
+	0x666666,
+	0x686868,
+	0x696969,
+	0x6a6a6a,
+	0x6c6c6c,
+	0x6d6d6d,
+	0x6f6f6f,
+	0x707070,
+	0x717171,
+	0x737373,
+	0x747474,
+	0x767676,
+	0x777777,
+	0x797979,
+	0x7a7a7a,
+	0x7c7c7c,
+	0x7d7d7d,
+	0x7f7f7f,
+	0x808080,
+	0x828282,
+	0x838383,
+	0x858585,
+	0x868686,
+	0x888888,
+	0x898989,
+	0x8b8b8b,
+	0x8d8d8d,
+	0x8e8e8e,
+	0x909090,
+	0x919191,
+	0x939393,
+	0x959595,
+	0x969696,
+	0x989898,
+	0x9a9a9a,
+	0x9b9b9b,
+	0x9d9d9d,
+	0x9f9f9f,
+	0xa1a1a1,
+	0xa2a2a2,
+	0xa4a4a4,
+	0xa6a6a6,
+	0xa7a7a7,
+	0xa9a9a9,
+	0xababab,
+	0xadadad,
+	0xafafaf,
+	0xb0b0b0,
+	0xb2b2b2,
+	0xb4b4b4,
+	0xb6b6b6,
+	0xb8b8b8,
+	0xbababa,
+	0xbbbbbb,
+	0xbdbdbd,
+	0xbfbfbf,
+	0xc1c1c1,
+	0xc3c3c3,
+	0xc5c5c5,
+	0xc7c7c7,
+	0xc9c9c9,
+	0xcbcbcb,
+	0xcdcdcd,
+	0xcfcfcf,
+	0xd1d1d1,
+	0xd3d3d3,
+	0xd5d5d5,
+	0xd7d7d7,
+	0xd9d9d9,
+	0xdbdbdb,
+	0xdddddd,
+	0xdfdfdf,
+	0xe1e1e1,
+	0xe3e3e3,
+	0xe5e5e5,
+	0xe7e7e7,
+	0xe9e9e9,
+	0xebebeb,
+	0xeeeeee,
+	0xf0f0f0,
+	0xf2f2f2,
+	0xf4f4f4,
+	0xf6f6f6,
+	0xf8f8f8,
+	0xfbfbfb,
+	0xfdfdfd,
+	0xffffff,
+};
+
+struct ppp_csc_table rgb2yuv = {
+	.fwd_matrix = {
+		0x83,
+		0x102,
+		0x32,
+		0xffb5,
+		0xff6c,
+		0xe1,
+		0xe1,
+		0xff45,
+		0xffdc,
+	},
+	.rev_matrix = {
+		0x254,
+		0x0,
+		0x331,
+		0x254,
+		0xff38,
+		0xfe61,
+		0x254,
+		0x409,
+		0x0,
+	},
+	.bv = {
+		0x10,
+		0x80,
+		0x80,
+	},
+	.lv = {
+		0x10,
+		0xeb,
+		0x10,
+		0xf0,
+	},
+};
+
+struct ppp_csc_table default_table2 = {
+	.fwd_matrix = {
+		0x5d,
+		0x13a,
+		0x20,
+		0xffcd,
+		0xff54,
+		0xe1,
+		0xe1,
+		0xff35,
+	},
+	.rev_matrix = {
+		0x254,
+		0x0,
+		0x396,
+		0x254,
+		0xff94,
+		0xfef0,
+		0x254,
+		0x43a,
+		0x0,
+	},
+	.bv = {
+		0x10,
+		0x80,
+		0x80,
+	},
+	.lv = {
+		0x10,
+		0xeb,
+		0x10,
+		0xf0,
+	},
+};
+
+const struct ppp_table upscale_table[PPP_UPSCALE_MAX] = {
+	{ 0x5fffc, 0x0 },
+	{ 0x50200, 0x7fc00000 },
+	{ 0x5fffc, 0xff80000d },
+	{ 0x50204, 0x7ec003f9 },
+	{ 0x5fffc, 0xfec0001c },
+	{ 0x50208, 0x7d4003f3 },
+	{ 0x5fffc, 0xfe40002b },
+	{ 0x5020c, 0x7b8003ed },
+	{ 0x5fffc, 0xfd80003c },
+	{ 0x50210, 0x794003e8 },
+	{ 0x5fffc, 0xfcc0004d },
+	{ 0x50214, 0x76c003e4 },
+	{ 0x5fffc, 0xfc40005f },
+	{ 0x50218, 0x73c003e0 },
+	{ 0x5fffc, 0xfb800071 },
+	{ 0x5021c, 0x708003de },
+	{ 0x5fffc, 0xfac00085 },
+	{ 0x50220, 0x6d0003db },
+	{ 0x5fffc, 0xfa000098 },
+	{ 0x50224, 0x698003d9 },
+	{ 0x5fffc, 0xf98000ac },
+	{ 0x50228, 0x654003d8 },
+	{ 0x5fffc, 0xf8c000c1 },
+	{ 0x5022c, 0x610003d7 },
+	{ 0x5fffc, 0xf84000d5 },
+	{ 0x50230, 0x5c8003d7 },
+	{ 0x5fffc, 0xf7c000e9 },
+	{ 0x50234, 0x580003d7 },
+	{ 0x5fffc, 0xf74000fd },
+	{ 0x50238, 0x534003d8 },
+	{ 0x5fffc, 0xf6c00112 },
+	{ 0x5023c, 0x4e8003d8 },
+	{ 0x5fffc, 0xf6800126 },
+	{ 0x50240, 0x494003da },
+	{ 0x5fffc, 0xf600013a },
+	{ 0x50244, 0x448003db },
+	{ 0x5fffc, 0xf600014d },
+	{ 0x50248, 0x3f4003dd },
+	{ 0x5fffc, 0xf5c00160 },
+	{ 0x5024c, 0x3a4003df },
+	{ 0x5fffc, 0xf5c00172 },
+	{ 0x50250, 0x354003e1 },
+	{ 0x5fffc, 0xf5c00184 },
+	{ 0x50254, 0x304003e3 },
+	{ 0x5fffc, 0xf6000195 },
+	{ 0x50258, 0x2b0003e6 },
+	{ 0x5fffc, 0xf64001a6 },
+	{ 0x5025c, 0x260003e8 },
+	{ 0x5fffc, 0xf6c001b4 },
+	{ 0x50260, 0x214003eb },
+	{ 0x5fffc, 0xf78001c2 },
+	{ 0x50264, 0x1c4003ee },
+	{ 0x5fffc, 0xf80001cf },
+	{ 0x50268, 0x17c003f1 },
+	{ 0x5fffc, 0xf90001db },
+	{ 0x5026c, 0x134003f3 },
+	{ 0x5fffc, 0xfa0001e5 },
+	{ 0x50270, 0xf0003f6 },
+	{ 0x5fffc, 0xfb4001ee },
+	{ 0x50274, 0xac003f9 },
+	{ 0x5fffc, 0xfcc001f5 },
+	{ 0x50278, 0x70003fb },
+	{ 0x5fffc, 0xfe4001fb },
+	{ 0x5027c, 0x34003fe },
+};
+
+const struct ppp_table mdp_gaussian_blur_table[PPP_BLUR_SCALE_MAX] = {
+	/* max variance */
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50280, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50284, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50288, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5028c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50290, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50294, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50298, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5029c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502a0, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502a4, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502a8, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502ac, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502b0, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502b4, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502b8, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502bc, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502c0, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502c4, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502c8, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502cc, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502d0, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502d4, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502d8, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502dc, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502e0, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502e4, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502e8, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502ec, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502f0, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502f4, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502f8, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x502fc, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50300, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50304, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50308, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5030c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50310, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50314, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50318, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5031c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50320, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50324, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50328, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5032c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50330, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50334, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50338, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5033c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50340, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50344, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50348, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5034c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50350, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50354, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50358, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5035c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50360, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50364, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50368, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5036c, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50370, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50374, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x50378, 0x20000080 },
+	{ 0x5fffc, 0x20000080 },
+	{ 0x5037c, 0x20000080 },
+};
+
+const struct ppp_table downscale_x_table_pt2topt4[] = {
+	{ 0x5fffc, 0x740008c },
+	{ 0x50280, 0x33800088 },
+	{ 0x5fffc, 0x800008e },
+	{ 0x50284, 0x33400084 },
+	{ 0x5fffc, 0x8400092 },
+	{ 0x50288, 0x33000080 },
+	{ 0x5fffc, 0x9000094 },
+	{ 0x5028c, 0x3300007b },
+	{ 0x5fffc, 0x9c00098 },
+	{ 0x50290, 0x32400077 },
+	{ 0x5fffc, 0xa40009b },
+	{ 0x50294, 0x32000073 },
+	{ 0x5fffc, 0xb00009d },
+	{ 0x50298, 0x31c0006f },
+	{ 0x5fffc, 0xbc000a0 },
+	{ 0x5029c, 0x3140006b },
+	{ 0x5fffc, 0xc8000a2 },
+	{ 0x502a0, 0x31000067 },
+	{ 0x5fffc, 0xd8000a5 },
+	{ 0x502a4, 0x30800062 },
+	{ 0x5fffc, 0xe4000a8 },
+	{ 0x502a8, 0x2fc0005f },
+	{ 0x5fffc, 0xec000aa },
+	{ 0x502ac, 0x2fc0005b },
+	{ 0x5fffc, 0xf8000ad },
+	{ 0x502b0, 0x2f400057 },
+	{ 0x5fffc, 0x108000b0 },
+	{ 0x502b4, 0x2e400054 },
+	{ 0x5fffc, 0x114000b2 },
+	{ 0x502b8, 0x2e000050 },
+	{ 0x5fffc, 0x124000b4 },
+	{ 0x502bc, 0x2d80004c },
+	{ 0x5fffc, 0x130000b6 },
+	{ 0x502c0, 0x2d000049 },
+	{ 0x5fffc, 0x140000b8 },
+	{ 0x502c4, 0x2c800045 },
+	{ 0x5fffc, 0x150000b9 },
+	{ 0x502c8, 0x2c000042 },
+	{ 0x5fffc, 0x15c000bd },
+	{ 0x502cc, 0x2b40003e },
+	{ 0x5fffc, 0x16c000bf },
+	{ 0x502d0, 0x2a80003b },
+	{ 0x5fffc, 0x17c000bf },
+	{ 0x502d4, 0x2a000039 },
+	{ 0x5fffc, 0x188000c2 },
+	{ 0x502d8, 0x29400036 },
+	{ 0x5fffc, 0x19c000c4 },
+	{ 0x502dc, 0x28800032 },
+	{ 0x5fffc, 0x1ac000c5 },
+	{ 0x502e0, 0x2800002f },
+	{ 0x5fffc, 0x1bc000c7 },
+	{ 0x502e4, 0x2740002c },
+	{ 0x5fffc, 0x1cc000c8 },
+	{ 0x502e8, 0x26c00029 },
+	{ 0x5fffc, 0x1dc000c9 },
+	{ 0x502ec, 0x26000027 },
+	{ 0x5fffc, 0x1ec000cc },
+	{ 0x502f0, 0x25000024 },
+	{ 0x5fffc, 0x200000cc },
+	{ 0x502f4, 0x24800021 },
+	{ 0x5fffc, 0x210000cd },
+	{ 0x502f8, 0x23800020 },
+	{ 0x5fffc, 0x220000ce },
+	{ 0x502fc, 0x2300001d },
+};
+
+static const struct ppp_table downscale_x_table_pt4topt6[] = {
+	{ 0x5fffc, 0x740008c },
+	{ 0x50280, 0x33800088 },
+	{ 0x5fffc, 0x800008e },
+	{ 0x50284, 0x33400084 },
+	{ 0x5fffc, 0x8400092 },
+	{ 0x50288, 0x33000080 },
+	{ 0x5fffc, 0x9000094 },
+	{ 0x5028c, 0x3300007b },
+	{ 0x5fffc, 0x9c00098 },
+	{ 0x50290, 0x32400077 },
+	{ 0x5fffc, 0xa40009b },
+	{ 0x50294, 0x32000073 },
+	{ 0x5fffc, 0xb00009d },
+	{ 0x50298, 0x31c0006f },
+	{ 0x5fffc, 0xbc000a0 },
+	{ 0x5029c, 0x3140006b },
+	{ 0x5fffc, 0xc8000a2 },
+	{ 0x502a0, 0x31000067 },
+	{ 0x5fffc, 0xd8000a5 },
+	{ 0x502a4, 0x30800062 },
+	{ 0x5fffc, 0xe4000a8 },
+	{ 0x502a8, 0x2fc0005f },
+	{ 0x5fffc, 0xec000aa },
+	{ 0x502ac, 0x2fc0005b },
+	{ 0x5fffc, 0xf8000ad },
+	{ 0x502b0, 0x2f400057 },
+	{ 0x5fffc, 0x108000b0 },
+	{ 0x502b4, 0x2e400054 },
+	{ 0x5fffc, 0x114000b2 },
+	{ 0x502b8, 0x2e000050 },
+	{ 0x5fffc, 0x124000b4 },
+	{ 0x502bc, 0x2d80004c },
+	{ 0x5fffc, 0x130000b6 },
+	{ 0x502c0, 0x2d000049 },
+	{ 0x5fffc, 0x140000b8 },
+	{ 0x502c4, 0x2c800045 },
+	{ 0x5fffc, 0x150000b9 },
+	{ 0x502c8, 0x2c000042 },
+	{ 0x5fffc, 0x15c000bd },
+	{ 0x502cc, 0x2b40003e },
+	{ 0x5fffc, 0x16c000bf },
+	{ 0x502d0, 0x2a80003b },
+	{ 0x5fffc, 0x17c000bf },
+	{ 0x502d4, 0x2a000039 },
+	{ 0x5fffc, 0x188000c2 },
+	{ 0x502d8, 0x29400036 },
+	{ 0x5fffc, 0x19c000c4 },
+	{ 0x502dc, 0x28800032 },
+	{ 0x5fffc, 0x1ac000c5 },
+	{ 0x502e0, 0x2800002f },
+	{ 0x5fffc, 0x1bc000c7 },
+	{ 0x502e4, 0x2740002c },
+	{ 0x5fffc, 0x1cc000c8 },
+	{ 0x502e8, 0x26c00029 },
+	{ 0x5fffc, 0x1dc000c9 },
+	{ 0x502ec, 0x26000027 },
+	{ 0x5fffc, 0x1ec000cc },
+	{ 0x502f0, 0x25000024 },
+	{ 0x5fffc, 0x200000cc },
+	{ 0x502f4, 0x24800021 },
+	{ 0x5fffc, 0x210000cd },
+	{ 0x502f8, 0x23800020 },
+	{ 0x5fffc, 0x220000ce },
+	{ 0x502fc, 0x2300001d },
+};
+
+static const struct ppp_table downscale_x_table_pt6topt8[] = {
+	{ 0x5fffc, 0xfe000070 },
+	{ 0x50280, 0x4bc00068 },
+	{ 0x5fffc, 0xfe000078 },
+	{ 0x50284, 0x4bc00060 },
+	{ 0x5fffc, 0xfe000080 },
+	{ 0x50288, 0x4b800059 },
+	{ 0x5fffc, 0xfe000089 },
+	{ 0x5028c, 0x4b000052 },
+	{ 0x5fffc, 0xfe400091 },
+	{ 0x50290, 0x4a80004b },
+	{ 0x5fffc, 0xfe40009a },
+	{ 0x50294, 0x4a000044 },
+	{ 0x5fffc, 0xfe8000a3 },
+	{ 0x50298, 0x4940003d },
+	{ 0x5fffc, 0xfec000ac },
+	{ 0x5029c, 0x48400037 },
+	{ 0x5fffc, 0xff0000b4 },
+	{ 0x502a0, 0x47800031 },
+	{ 0x5fffc, 0xff8000bd },
+	{ 0x502a4, 0x4640002b },
+	{ 0x5fffc, 0xc5 },
+	{ 0x502a8, 0x45000026 },
+	{ 0x5fffc, 0x8000ce },
+	{ 0x502ac, 0x43800021 },
+	{ 0x5fffc, 0x10000d6 },
+	{ 0x502b0, 0x4240001c },
+	{ 0x5fffc, 0x18000df },
+	{ 0x502b4, 0x40800018 },
+	{ 0x5fffc, 0x24000e6 },
+	{ 0x502b8, 0x3f000014 },
+	{ 0x5fffc, 0x30000ee },
+	{ 0x502bc, 0x3d400010 },
+	{ 0x5fffc, 0x40000f5 },
+	{ 0x502c0, 0x3b80000c },
+	{ 0x5fffc, 0x50000fc },
+	{ 0x502c4, 0x39800009 },
+	{ 0x5fffc, 0x6000102 },
+	{ 0x502c8, 0x37c00006 },
+	{ 0x5fffc, 0x7000109 },
+	{ 0x502cc, 0x35800004 },
+	{ 0x5fffc, 0x840010e },
+	{ 0x502d0, 0x33800002 },
+	{ 0x5fffc, 0x9800114 },
+	{ 0x502d4, 0x31400000 },
+	{ 0x5fffc, 0xac00119 },
+	{ 0x502d8, 0x2f4003fe },
+	{ 0x5fffc, 0xc40011e },
+	{ 0x502dc, 0x2d0003fc },
+	{ 0x5fffc, 0xdc00121 },
+	{ 0x502e0, 0x2b0003fb },
+	{ 0x5fffc, 0xf400125 },
+	{ 0x502e4, 0x28c003fa },
+	{ 0x5fffc, 0x11000128 },
+	{ 0x502e8, 0x268003f9 },
+	{ 0x5fffc, 0x12c0012a },
+	{ 0x502ec, 0x244003f9 },
+	{ 0x5fffc, 0x1480012c },
+	{ 0x502f0, 0x224003f8 },
+	{ 0x5fffc, 0x1640012e },
+	{ 0x502f4, 0x200003f8 },
+	{ 0x5fffc, 0x1800012f },
+	{ 0x502f8, 0x1e0003f8 },
+	{ 0x5fffc, 0x1a00012f },
+	{ 0x502fc, 0x1c0003f8 },
+};
+
+static const struct ppp_table downscale_x_table_pt8topt1[] = {
+	{ 0x5fffc, 0x0 },
+	{ 0x50280, 0x7fc00000 },
+	{ 0x5fffc, 0xff80000d },
+	{ 0x50284, 0x7ec003f9 },
+	{ 0x5fffc, 0xfec0001c },
+	{ 0x50288, 0x7d4003f3 },
+	{ 0x5fffc, 0xfe40002b },
+	{ 0x5028c, 0x7b8003ed },
+	{ 0x5fffc, 0xfd80003c },
+	{ 0x50290, 0x794003e8 },
+	{ 0x5fffc, 0xfcc0004d },
+	{ 0x50294, 0x76c003e4 },
+	{ 0x5fffc, 0xfc40005f },
+	{ 0x50298, 0x73c003e0 },
+	{ 0x5fffc, 0xfb800071 },
+	{ 0x5029c, 0x708003de },
+	{ 0x5fffc, 0xfac00085 },
+	{ 0x502a0, 0x6d0003db },
+	{ 0x5fffc, 0xfa000098 },
+	{ 0x502a4, 0x698003d9 },
+	{ 0x5fffc, 0xf98000ac },
+	{ 0x502a8, 0x654003d8 },
+	{ 0x5fffc, 0xf8c000c1 },
+	{ 0x502ac, 0x610003d7 },
+	{ 0x5fffc, 0xf84000d5 },
+	{ 0x502b0, 0x5c8003d7 },
+	{ 0x5fffc, 0xf7c000e9 },
+	{ 0x502b4, 0x580003d7 },
+	{ 0x5fffc, 0xf74000fd },
+	{ 0x502b8, 0x534003d8 },
+	{ 0x5fffc, 0xf6c00112 },
+	{ 0x502bc, 0x4e8003d8 },
+	{ 0x5fffc, 0xf6800126 },
+	{ 0x502c0, 0x494003da },
+	{ 0x5fffc, 0xf600013a },
+	{ 0x502c4, 0x448003db },
+	{ 0x5fffc, 0xf600014d },
+	{ 0x502c8, 0x3f4003dd },
+	{ 0x5fffc, 0xf5c00160 },
+	{ 0x502cc, 0x3a4003df },
+	{ 0x5fffc, 0xf5c00172 },
+	{ 0x502d0, 0x354003e1 },
+	{ 0x5fffc, 0xf5c00184 },
+	{ 0x502d4, 0x304003e3 },
+	{ 0x5fffc, 0xf6000195 },
+	{ 0x502d8, 0x2b0003e6 },
+	{ 0x5fffc, 0xf64001a6 },
+	{ 0x502dc, 0x260003e8 },
+	{ 0x5fffc, 0xf6c001b4 },
+	{ 0x502e0, 0x214003eb },
+	{ 0x5fffc, 0xf78001c2 },
+	{ 0x502e4, 0x1c4003ee },
+	{ 0x5fffc, 0xf80001cf },
+	{ 0x502e8, 0x17c003f1 },
+	{ 0x5fffc, 0xf90001db },
+	{ 0x502ec, 0x134003f3 },
+	{ 0x5fffc, 0xfa0001e5 },
+	{ 0x502f0, 0xf0003f6 },
+	{ 0x5fffc, 0xfb4001ee },
+	{ 0x502f4, 0xac003f9 },
+	{ 0x5fffc, 0xfcc001f5 },
+	{ 0x502f8, 0x70003fb },
+	{ 0x5fffc, 0xfe4001fb },
+	{ 0x502fc, 0x34003fe },
+};
+
+static const struct ppp_table *downscale_x_table[PPP_DOWNSCALE_MAX] = {
+	[PPP_DOWNSCALE_PT2TOPT4] = downscale_x_table_pt2topt4,
+	[PPP_DOWNSCALE_PT4TOPT6] = downscale_x_table_pt4topt6,
+	[PPP_DOWNSCALE_PT6TOPT8] = downscale_x_table_pt6topt8,
+	[PPP_DOWNSCALE_PT8TOPT1] = downscale_x_table_pt8topt1,
+};
+
+static const struct ppp_table downscale_y_table_pt2topt4[] = {
+	{ 0x5fffc, 0x740008c },
+	{ 0x50300, 0x33800088 },
+	{ 0x5fffc, 0x800008e },
+	{ 0x50304, 0x33400084 },
+	{ 0x5fffc, 0x8400092 },
+	{ 0x50308, 0x33000080 },
+	{ 0x5fffc, 0x9000094 },
+	{ 0x5030c, 0x3300007b },
+	{ 0x5fffc, 0x9c00098 },
+	{ 0x50310, 0x32400077 },
+	{ 0x5fffc, 0xa40009b },
+	{ 0x50314, 0x32000073 },
+	{ 0x5fffc, 0xb00009d },
+	{ 0x50318, 0x31c0006f },
+	{ 0x5fffc, 0xbc000a0 },
+	{ 0x5031c, 0x3140006b },
+	{ 0x5fffc, 0xc8000a2 },
+	{ 0x50320, 0x31000067 },
+	{ 0x5fffc, 0xd8000a5 },
+	{ 0x50324, 0x30800062 },
+	{ 0x5fffc, 0xe4000a8 },
+	{ 0x50328, 0x2fc0005f },
+	{ 0x5fffc, 0xec000aa },
+	{ 0x5032c, 0x2fc0005b },
+	{ 0x5fffc, 0xf8000ad },
+	{ 0x50330, 0x2f400057 },
+	{ 0x5fffc, 0x108000b0 },
+	{ 0x50334, 0x2e400054 },
+	{ 0x5fffc, 0x114000b2 },
+	{ 0x50338, 0x2e000050 },
+	{ 0x5fffc, 0x124000b4 },
+	{ 0x5033c, 0x2d80004c },
+	{ 0x5fffc, 0x130000b6 },
+	{ 0x50340, 0x2d000049 },
+	{ 0x5fffc, 0x140000b8 },
+	{ 0x50344, 0x2c800045 },
+	{ 0x5fffc, 0x150000b9 },
+	{ 0x50348, 0x2c000042 },
+	{ 0x5fffc, 0x15c000bd },
+	{ 0x5034c, 0x2b40003e },
+	{ 0x5fffc, 0x16c000bf },
+	{ 0x50350, 0x2a80003b },
+	{ 0x5fffc, 0x17c000bf },
+	{ 0x50354, 0x2a000039 },
+	{ 0x5fffc, 0x188000c2 },
+	{ 0x50358, 0x29400036 },
+	{ 0x5fffc, 0x19c000c4 },
+	{ 0x5035c, 0x28800032 },
+	{ 0x5fffc, 0x1ac000c5 },
+	{ 0x50360, 0x2800002f },
+	{ 0x5fffc, 0x1bc000c7 },
+	{ 0x50364, 0x2740002c },
+	{ 0x5fffc, 0x1cc000c8 },
+	{ 0x50368, 0x26c00029 },
+	{ 0x5fffc, 0x1dc000c9 },
+	{ 0x5036c, 0x26000027 },
+	{ 0x5fffc, 0x1ec000cc },
+	{ 0x50370, 0x25000024 },
+	{ 0x5fffc, 0x200000cc },
+	{ 0x50374, 0x24800021 },
+	{ 0x5fffc, 0x210000cd },
+	{ 0x50378, 0x23800020 },
+	{ 0x5fffc, 0x220000ce },
+	{ 0x5037c, 0x2300001d },
+};
+
+static const struct ppp_table downscale_y_table_pt4topt6[] = {
+	{ 0x5fffc, 0x740008c },
+	{ 0x50300, 0x33800088 },
+	{ 0x5fffc, 0x800008e },
+	{ 0x50304, 0x33400084 },
+	{ 0x5fffc, 0x8400092 },
+	{ 0x50308, 0x33000080 },
+	{ 0x5fffc, 0x9000094 },
+	{ 0x5030c, 0x3300007b },
+	{ 0x5fffc, 0x9c00098 },
+	{ 0x50310, 0x32400077 },
+	{ 0x5fffc, 0xa40009b },
+	{ 0x50314, 0x32000073 },
+	{ 0x5fffc, 0xb00009d },
+	{ 0x50318, 0x31c0006f },
+	{ 0x5fffc, 0xbc000a0 },
+	{ 0x5031c, 0x3140006b },
+	{ 0x5fffc, 0xc8000a2 },
+	{ 0x50320, 0x31000067 },
+	{ 0x5fffc, 0xd8000a5 },
+	{ 0x50324, 0x30800062 },
+	{ 0x5fffc, 0xe4000a8 },
+	{ 0x50328, 0x2fc0005f },
+	{ 0x5fffc, 0xec000aa },
+	{ 0x5032c, 0x2fc0005b },
+	{ 0x5fffc, 0xf8000ad },
+	{ 0x50330, 0x2f400057 },
+	{ 0x5fffc, 0x108000b0 },
+	{ 0x50334, 0x2e400054 },
+	{ 0x5fffc, 0x114000b2 },
+	{ 0x50338, 0x2e000050 },
+	{ 0x5fffc, 0x124000b4 },
+	{ 0x5033c, 0x2d80004c },
+	{ 0x5fffc, 0x130000b6 },
+	{ 0x50340, 0x2d000049 },
+	{ 0x5fffc, 0x140000b8 },
+	{ 0x50344, 0x2c800045 },
+	{ 0x5fffc, 0x150000b9 },
+	{ 0x50348, 0x2c000042 },
+	{ 0x5fffc, 0x15c000bd },
+	{ 0x5034c, 0x2b40003e },
+	{ 0x5fffc, 0x16c000bf },
+	{ 0x50350, 0x2a80003b },
+	{ 0x5fffc, 0x17c000bf },
+	{ 0x50354, 0x2a000039 },
+	{ 0x5fffc, 0x188000c2 },
+	{ 0x50358, 0x29400036 },
+	{ 0x5fffc, 0x19c000c4 },
+	{ 0x5035c, 0x28800032 },
+	{ 0x5fffc, 0x1ac000c5 },
+	{ 0x50360, 0x2800002f },
+	{ 0x5fffc, 0x1bc000c7 },
+	{ 0x50364, 0x2740002c },
+	{ 0x5fffc, 0x1cc000c8 },
+	{ 0x50368, 0x26c00029 },
+	{ 0x5fffc, 0x1dc000c9 },
+	{ 0x5036c, 0x26000027 },
+	{ 0x5fffc, 0x1ec000cc },
+	{ 0x50370, 0x25000024 },
+	{ 0x5fffc, 0x200000cc },
+	{ 0x50374, 0x24800021 },
+	{ 0x5fffc, 0x210000cd },
+	{ 0x50378, 0x23800020 },
+	{ 0x5fffc, 0x220000ce },
+	{ 0x5037c, 0x2300001d },
+};
+
+static const struct ppp_table downscale_y_table_pt6topt8[] = {
+	{ 0x5fffc, 0xfe000070 },
+	{ 0x50300, 0x4bc00068 },
+	{ 0x5fffc, 0xfe000078 },
+	{ 0x50304, 0x4bc00060 },
+	{ 0x5fffc, 0xfe000080 },
+	{ 0x50308, 0x4b800059 },
+	{ 0x5fffc, 0xfe000089 },
+	{ 0x5030c, 0x4b000052 },
+	{ 0x5fffc, 0xfe400091 },
+	{ 0x50310, 0x4a80004b },
+	{ 0x5fffc, 0xfe40009a },
+	{ 0x50314, 0x4a000044 },
+	{ 0x5fffc, 0xfe8000a3 },
+	{ 0x50318, 0x4940003d },
+	{ 0x5fffc, 0xfec000ac },
+	{ 0x5031c, 0x48400037 },
+	{ 0x5fffc, 0xff0000b4 },
+	{ 0x50320, 0x47800031 },
+	{ 0x5fffc, 0xff8000bd },
+	{ 0x50324, 0x4640002b },
+	{ 0x5fffc, 0xc5 },
+	{ 0x50328, 0x45000026 },
+	{ 0x5fffc, 0x8000ce },
+	{ 0x5032c, 0x43800021 },
+	{ 0x5fffc, 0x10000d6 },
+	{ 0x50330, 0x4240001c },
+	{ 0x5fffc, 0x18000df },
+	{ 0x50334, 0x40800018 },
+	{ 0x5fffc, 0x24000e6 },
+	{ 0x50338, 0x3f000014 },
+	{ 0x5fffc, 0x30000ee },
+	{ 0x5033c, 0x3d400010 },
+	{ 0x5fffc, 0x40000f5 },
+	{ 0x50340, 0x3b80000c },
+	{ 0x5fffc, 0x50000fc },
+	{ 0x50344, 0x39800009 },
+	{ 0x5fffc, 0x6000102 },
+	{ 0x50348, 0x37c00006 },
+	{ 0x5fffc, 0x7000109 },
+	{ 0x5034c, 0x35800004 },
+	{ 0x5fffc, 0x840010e },
+	{ 0x50350, 0x33800002 },
+	{ 0x5fffc, 0x9800114 },
+	{ 0x50354, 0x31400000 },
+	{ 0x5fffc, 0xac00119 },
+	{ 0x50358, 0x2f4003fe },
+	{ 0x5fffc, 0xc40011e },
+	{ 0x5035c, 0x2d0003fc },
+	{ 0x5fffc, 0xdc00121 },
+	{ 0x50360, 0x2b0003fb },
+	{ 0x5fffc, 0xf400125 },
+	{ 0x50364, 0x28c003fa },
+	{ 0x5fffc, 0x11000128 },
+	{ 0x50368, 0x268003f9 },
+	{ 0x5fffc, 0x12c0012a },
+	{ 0x5036c, 0x244003f9 },
+	{ 0x5fffc, 0x1480012c },
+	{ 0x50370, 0x224003f8 },
+	{ 0x5fffc, 0x1640012e },
+	{ 0x50374, 0x200003f8 },
+	{ 0x5fffc, 0x1800012f },
+	{ 0x50378, 0x1e0003f8 },
+	{ 0x5fffc, 0x1a00012f },
+	{ 0x5037c, 0x1c0003f8 },
+};
+
+static const struct ppp_table downscale_y_table_pt8topt1[] = {
+	{ 0x5fffc, 0x0 },
+	{ 0x50300, 0x7fc00000 },
+	{ 0x5fffc, 0xff80000d },
+	{ 0x50304, 0x7ec003f9 },
+	{ 0x5fffc, 0xfec0001c },
+	{ 0x50308, 0x7d4003f3 },
+	{ 0x5fffc, 0xfe40002b },
+	{ 0x5030c, 0x7b8003ed },
+	{ 0x5fffc, 0xfd80003c },
+	{ 0x50310, 0x794003e8 },
+	{ 0x5fffc, 0xfcc0004d },
+	{ 0x50314, 0x76c003e4 },
+	{ 0x5fffc, 0xfc40005f },
+	{ 0x50318, 0x73c003e0 },
+	{ 0x5fffc, 0xfb800071 },
+	{ 0x5031c, 0x708003de },
+	{ 0x5fffc, 0xfac00085 },
+	{ 0x50320, 0x6d0003db },
+	{ 0x5fffc, 0xfa000098 },
+	{ 0x50324, 0x698003d9 },
+	{ 0x5fffc, 0xf98000ac },
+	{ 0x50328, 0x654003d8 },
+	{ 0x5fffc, 0xf8c000c1 },
+	{ 0x5032c, 0x610003d7 },
+	{ 0x5fffc, 0xf84000d5 },
+	{ 0x50330, 0x5c8003d7 },
+	{ 0x5fffc, 0xf7c000e9 },
+	{ 0x50334, 0x580003d7 },
+	{ 0x5fffc, 0xf74000fd },
+	{ 0x50338, 0x534003d8 },
+	{ 0x5fffc, 0xf6c00112 },
+	{ 0x5033c, 0x4e8003d8 },
+	{ 0x5fffc, 0xf6800126 },
+	{ 0x50340, 0x494003da },
+	{ 0x5fffc, 0xf600013a },
+	{ 0x50344, 0x448003db },
+	{ 0x5fffc, 0xf600014d },
+	{ 0x50348, 0x3f4003dd },
+	{ 0x5fffc, 0xf5c00160 },
+	{ 0x5034c, 0x3a4003df },
+	{ 0x5fffc, 0xf5c00172 },
+	{ 0x50350, 0x354003e1 },
+	{ 0x5fffc, 0xf5c00184 },
+	{ 0x50354, 0x304003e3 },
+	{ 0x5fffc, 0xf6000195 },
+	{ 0x50358, 0x2b0003e6 },
+	{ 0x5fffc, 0xf64001a6 },
+	{ 0x5035c, 0x260003e8 },
+	{ 0x5fffc, 0xf6c001b4 },
+	{ 0x50360, 0x214003eb },
+	{ 0x5fffc, 0xf78001c2 },
+	{ 0x50364, 0x1c4003ee },
+	{ 0x5fffc, 0xf80001cf },
+	{ 0x50368, 0x17c003f1 },
+	{ 0x5fffc, 0xf90001db },
+	{ 0x5036c, 0x134003f3 },
+	{ 0x5fffc, 0xfa0001e5 },
+	{ 0x50370, 0xf0003f6 },
+	{ 0x5fffc, 0xfb4001ee },
+	{ 0x50374, 0xac003f9 },
+	{ 0x5fffc, 0xfcc001f5 },
+	{ 0x50378, 0x70003fb },
+	{ 0x5fffc, 0xfe4001fb },
+	{ 0x5037c, 0x34003fe },
+};
+
+static const struct ppp_table *downscale_y_table[PPP_DOWNSCALE_MAX] = {
+	[PPP_DOWNSCALE_PT2TOPT4] = downscale_y_table_pt2topt4,
+	[PPP_DOWNSCALE_PT4TOPT6] = downscale_y_table_pt4topt6,
+	[PPP_DOWNSCALE_PT6TOPT8] = downscale_y_table_pt6topt8,
+	[PPP_DOWNSCALE_PT8TOPT1] = downscale_y_table_pt8topt1,
+};
+
+void ppp_load_table(const struct ppp_table *table, int len)
+{
+	int i;
+	for (i = 0; i < len; i++)
+		PPP_WRITEL(table[i].val, table[i].reg);
+}
+
+void ppp_load_up_lut(void)
+{
+	ppp_load_table(upscale_table,
+		PPP_UPSCALE_MAX);
+}
+
+void ppp_load_gaussian_lut(void)
+{
+	ppp_load_table(mdp_gaussian_blur_table,
+		PPP_BLUR_SCALE_MAX);
+}
+
+void ppp_load_x_scale_table(int idx)
+{
+	ppp_load_table(downscale_x_table[idx], 64);
+}
+
+void ppp_load_y_scale_table(int idx)
+{
+	ppp_load_table(downscale_y_table[idx], 64);
+}
+
+uint32_t ppp_bpp(uint32_t type)
+{
+	if (type > MDP_IMGTYPE_LIMIT)
+		return 0;
+	return bytes_per_pixel[type];
+}
+
+uint32_t ppp_src_config(uint32_t type)
+{
+	if (type > MDP_IMGTYPE_LIMIT)
+		return 0;
+	return src_cfg_lut[type];
+}
+
+uint32_t ppp_out_config(uint32_t type)
+{
+	if (type > MDP_IMGTYPE_LIMIT)
+		return 0;
+	return out_cfg_lut[type];
+}
+
+uint32_t ppp_pack_pattern(uint32_t type)
+{
+	if (type > MDP_IMGTYPE_LIMIT)
+		return 0;
+	return pack_patt_lut[type];
+}
+
+uint32_t ppp_dst_op_reg(uint32_t type)
+{
+	if (type > MDP_IMGTYPE_LIMIT)
+		return 0;
+	return dst_op_reg[type];
+}
+
+uint32_t ppp_src_op_reg(uint32_t type)
+{
+	if (type > MDP_IMGTYPE_LIMIT)
+		return 0;
+	return src_op_reg[type];
+}
+
+bool ppp_per_p_alpha(uint32_t type)
+{
+	if (type > MDP_IMGTYPE_LIMIT)
+		return 0;
+	return per_pixel_alpha[type];
+}
+
+bool ppp_multi_plane(uint32_t type)
+{
+	if (type > MDP_IMGTYPE_LIMIT)
+		return 0;
+	return multi_plane[type];
+}
+
+uint32_t *ppp_default_pre_lut(void)
+{
+	return default_pre_lut_val;
+}
+
+uint32_t *ppp_default_post_lut(void)
+{
+	return default_post_lut_val;
+}
+
+struct ppp_csc_table *ppp_csc_rgb2yuv(void)
+{
+	return &rgb2yuv;
+}
+
+struct ppp_csc_table *ppp_csc_table2(void)
+{
+	return &default_table2;
+}
diff --git a/drivers/video/msm/mdss/mdp3_ppp_hwio.c b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
new file mode 100644
index 0000000..309effc
--- /dev/null
+++ b/drivers/video/msm/mdss/mdp3_ppp_hwio.c
@@ -0,0 +1,1184 @@
+/* Copyright (c) 2007, 2012-2013 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/file.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include "linux/proc_fs.h"
+
+#include "mdss_fb.h"
+#include "mdp3_ppp.h"
+#include "mdp3_hwio.h"
+
+/* SHIM Q Factor */
+#define PHI_Q_FACTOR          29
+#define PQF_PLUS_5            (PHI_Q_FACTOR + 5)	/* due to 32 phases */
+#define PQF_PLUS_4            (PHI_Q_FACTOR + 4)
+#define PQF_PLUS_2            (PHI_Q_FACTOR + 2)	/* to get 4.0 */
+#define PQF_MINUS_2           (PHI_Q_FACTOR - 2)	/* to get 0.25 */
+#define PQF_PLUS_5_PLUS_2     (PQF_PLUS_5 + 2)
+#define PQF_PLUS_5_MINUS_2    (PQF_PLUS_5 - 2)
+
+static long long mdp_do_div(long long num, long long den)
+{
+	do_div(num, den);
+	return num;
+}
+
+static int mdp_calc_scale_params(uint32_t org, uint32_t dim_in,
+	uint32_t dim_out, bool is_W, int32_t *phase_init_ptr,
+	uint32_t *phase_step_ptr)
+{
+	bool rpa_on = false;
+	int init_phase = 0;
+	uint64_t numer = 0;
+	uint64_t denom = 0;
+	int64_t point5 = 1;
+	int64_t one = 1;
+	int64_t k1, k2, k3, k4;	/* linear equation coefficients */
+	uint64_t int_mask;
+	uint64_t fract_mask;
+	uint64_t Os;
+	int64_t Osprime;
+	int64_t Od;
+	int64_t Odprime;
+	int64_t Oreq;
+	uint32_t mult;
+
+	/*
+	 * The phase accumulator should really be rational for all cases in a
+	 * general purpose polyphase scaler for a tiled architecture with
+	 * non-zero * origin capability because there is no way to represent
+	 * certain scale factors in fixed point regardless of precision.
+	 * The error incurred in attempting to use fixed point is most
+	 * eggregious for SF where 1/SF is an integral multiple of 1/3.
+	 *
+	 * Set the RPA flag for this dimension.
+	 *
+	 * In order for 1/SF (dim_in/dim_out) to be an integral multiple of
+	 * 1/3, dim_out must be an integral multiple of 3.
+	 */
+	if (!(dim_out % 3)) {
+		mult = dim_out / 3;
+		rpa_on = (!(dim_in % mult));
+	}
+
+	numer = dim_out;
+	denom = dim_in;
+
+	/*
+	 * convert to U30.34 before division
+	 *
+	 * The K vectors carry 4 extra bits of precision
+	 * and are rounded.
+	 *
+	 * We initially go 5 bits over then round by adding
+	 * 1 and right shifting by 1
+	 * so final result is U31.33
+	 */
+	numer <<= PQF_PLUS_5;
+
+	/* now calculate the scale factor (aka k3) */
+	k3 = ((mdp_do_div(numer, denom) + 1) >> 1);
+
+	/* check scale factor for legal range [0.25 - 4.0] */
+	if (((k3 >> 4) < (1LL << PQF_MINUS_2)) ||
+	    ((k3 >> 4) > (1LL << PQF_PLUS_2))) {
+		return -EINVAL;
+	}
+
+	/* calculate inverse scale factor (aka k1) for phase init */
+	numer = dim_in;
+	denom = dim_out;
+	numer <<= PQF_PLUS_5;
+	k1 = ((mdp_do_div(numer, denom) + 1) >> 1);
+
+	/*
+	 * calculate initial phase and ROI overfetch
+	 */
+	/* convert point5 & one to S39.24 (will always be positive) */
+	point5 <<= (PQF_PLUS_4 - 1);
+	one <<= PQF_PLUS_4;
+	k2 = ((k1 - one) >> 1);
+	init_phase = (int)(k2 >> 4);
+	k4 = ((k3 - one) >> 1);
+	if (k3 != one) {
+		/* calculate the masks */
+		fract_mask = one - 1;
+		int_mask = ~fract_mask;
+
+		if (!rpa_on) {
+			/*
+			 * FIXED POINT IMPLEMENTATION
+			 */
+			if (org) {
+				/*
+				 * The complicated case; ROI origin != 0
+				 * init_phase needs to be adjusted
+				 * OF is also position dependent
+				 */
+
+				/* map (org - .5) into destination space */
+				Os = ((uint64_t) org << 1) - 1;
+				Od = ((k3 * Os) >> 1) + k4;
+
+				/* take the ceiling */
+				Odprime = (Od & int_mask);
+				if (Odprime != Od)
+					Odprime += one;
+
+				/* now map that back to source space */
+				Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2;
+
+				/* then floor & decrement to calc the required
+				   starting coordinate */
+				Oreq = (Osprime & int_mask) - one;
+
+				/* calculate initial phase */
+				init_phase = (int)((Osprime - Oreq) >> 4);
+			}
+		} else {
+			/*
+			 * RPA IMPLEMENTATION
+			 *
+			 * init_phase needs to be calculated in all RPA_on cases
+			 * because it's a numerator, not a fixed point value.
+			 */
+
+			/* map (org - .5) into destination space */
+			Os = ((uint64_t) org << PQF_PLUS_4) - point5;
+			Od = mdp_do_div((dim_out * (Os + point5)),
+					dim_in);
+			Od -= point5;
+
+			/* take the ceiling */
+			Odprime = (Od & int_mask);
+			if (Odprime != Od)
+				Odprime += one;
+
+			/* now map that back to source space */
+			Osprime =
+			    mdp_do_div((dim_in * (Odprime + point5)),
+				       dim_out);
+			Osprime -= point5;
+
+			/* then floor & decrement to calculate the required
+			   starting coordinate */
+			Oreq = (Osprime & int_mask) - one;
+
+			/* calculate initial phase */
+			init_phase = (int)((Osprime - Oreq) >> 4);
+		}
+	}
+
+	/* return the scale parameters */
+	*phase_init_ptr = init_phase;
+	*phase_step_ptr = (uint32_t) (k1 >> 4);
+
+	return 0;
+}
+
+static int scale_idx(int factor)
+{
+	int idx;
+
+	if (factor > 80)
+		idx = PPP_DOWNSCALE_PT8TOPT1;
+	else if (factor > 60)
+		idx = PPP_DOWNSCALE_PT6TOPT8;
+	else if (factor > 40)
+		idx = PPP_DOWNSCALE_PT4TOPT6;
+	else
+		idx = PPP_DOWNSCALE_PT2TOPT4;
+
+	return idx;
+}
+
+inline int32_t comp_conv_rgb2yuv(int32_t comp, int32_t y_high,
+		int32_t y_low, int32_t c_high, int32_t c_low)
+{
+	if (comp < 0)
+		comp = 0;
+	if (comp > 255)
+		comp = 255;
+
+	/* clamp */
+	if (comp < y_low)
+		comp = y_low;
+	if (comp > y_high)
+		comp = y_high;
+	return comp;
+}
+
+static uint32_t conv_rgb2yuv(uint32_t input_pixel,
+		uint16_t *matrix_vector,
+		uint16_t *bv,
+		uint16_t *clamp_vector)
+{
+	uint8_t input_C2, input_C0, input_C1;
+	uint32_t output;
+	int32_t comp_C2, comp_C1, comp_C0, temp;
+	int32_t temp1, temp2, temp3;
+	int32_t matrix[9];
+	int32_t bias_vector[3];
+	int32_t Y_low_limit, Y_high_limit, C_low_limit, C_high_limit;
+	int32_t i;
+
+	input_C2 = (input_pixel >> 16) & 0xFF;
+	input_C1 = (input_pixel >> 8) & 0xFF;
+	input_C0 = (input_pixel >> 0) & 0xFF;
+
+	comp_C0 = input_C0;
+	comp_C1 = input_C1;
+	comp_C2 = input_C2;
+
+	for (i = 0; i < MDP_CSC_SIZE; i++)
+		matrix[i] =
+		    ((int32_t) (((int32_t) matrix_vector[i]) << 20)) >> 20;
+
+	bias_vector[0] = (int32_t) (bv[0] & 0xFF);
+	bias_vector[1] = (int32_t) (bv[1] & 0xFF);
+	bias_vector[2] = (int32_t) (bv[2] & 0xFF);
+
+	Y_low_limit = (int32_t) clamp_vector[0];
+	Y_high_limit = (int32_t) clamp_vector[1];
+	C_low_limit = (int32_t) clamp_vector[2];
+	C_high_limit = (int32_t) clamp_vector[3];
+
+	/*
+	 * Color Conversion
+	 * reorder input colors
+	 */
+	temp = comp_C2;
+	comp_C2 = comp_C1;
+	comp_C1 = comp_C0;
+	comp_C0 = temp;
+
+	/* matrix multiplication */
+	temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2];
+	temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5];
+	temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8];
+
+	comp_C0 = temp1 + 0x100;
+	comp_C1 = temp2 + 0x100;
+	comp_C2 = temp3 + 0x100;
+
+	/* take interger part */
+	comp_C0 >>= 9;
+	comp_C1 >>= 9;
+	comp_C2 >>= 9;
+
+	/* post bias (+) */
+	comp_C0 += bias_vector[0];
+	comp_C1 += bias_vector[1];
+	comp_C2 += bias_vector[2];
+
+	/* limit pixel to 8-bit */
+	comp_C0 = comp_conv_rgb2yuv(comp_C0, Y_high_limit,
+			Y_low_limit, C_high_limit, C_low_limit);
+	comp_C1 = comp_conv_rgb2yuv(comp_C1, Y_high_limit,
+			Y_low_limit, C_high_limit, C_low_limit);
+	comp_C2 = comp_conv_rgb2yuv(comp_C2, Y_high_limit,
+			Y_low_limit, C_high_limit, C_low_limit);
+
+	output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0;
+	return output;
+}
+
+inline void y_h_even_num(struct ppp_img_desc *img)
+{
+	img->roi.y = (img->roi.y / 2) * 2;
+	img->roi.height = (img->roi.height / 2) * 2;
+}
+
+inline void x_w_even_num(struct ppp_img_desc *img)
+{
+	img->roi.x = (img->roi.x / 2) * 2;
+	img->roi.width = (img->roi.width / 2) * 2;
+}
+
+bool check_if_rgb(int color)
+{
+	bool rgb = false;
+	switch (color) {
+	case MDP_RGB_565:
+	case MDP_BGR_565:
+	case MDP_RGB_888:
+	case MDP_BGR_888:
+	case MDP_BGRA_8888:
+	case MDP_RGBA_8888:
+	case MDP_ARGB_8888:
+	case MDP_XRGB_8888:
+	case MDP_RGBX_8888:
+		rgb = true;
+	default:
+		break;
+	}
+	return rgb;
+}
+
+static uint8_t *mdp_adjust_rot_addr(struct ppp_blit_op *iBuf,
+	uint8_t *addr, uint32_t bpp, uint32_t uv)
+{
+	uint32_t dest_ystride = iBuf->dst.prop.width * bpp;
+	uint32_t h_slice = 1;
+	if (0)
+		return 0;
+
+	if (uv && ((iBuf->dst.color_fmt == MDP_Y_CBCR_H2V2) ||
+		(iBuf->dst.color_fmt == MDP_Y_CRCB_H2V2)))
+		h_slice = 2;
+
+	if (((iBuf->mdp_op & MDPOP_ROT90) == MDPOP_ROT90) ^
+		((iBuf->mdp_op & MDPOP_LR) == MDPOP_LR)) {
+		addr +=
+		    (iBuf->dst.roi.width -
+			    MIN(16, iBuf->dst.roi.width)) * bpp;
+	}
+	if ((iBuf->mdp_op & MDPOP_UD) == MDPOP_UD) {
+		if (1) {
+			addr +=
+				((iBuf->dst.roi.height -
+				MIN(16, iBuf->dst.roi.height))/h_slice) *
+				dest_ystride;
+		} else {
+			addr +=
+			(iBuf->dst.roi.width -
+				MIN(16, iBuf->dst.roi.width)) * bpp;
+		}
+	}
+
+	return addr;
+}
+
+void mdp_adjust_start_addr(struct ppp_blit_op *blit_op,
+	struct ppp_img_desc *img, int v_slice,
+	int h_slice, int layer)
+{
+	uint32_t bpp = ppp_bpp(img->color_fmt);
+	int x = img->roi.x;
+	int y = img->roi.y;
+	uint32_t width = img->prop.width;
+
+	if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
+		img->p0 += (x + y * ALIGN(width, 32)) * bpp;
+	else
+		img->p0 += (x + y * width) * bpp;
+	if (layer != 0)
+		img->p0 = mdp_adjust_rot_addr(blit_op, img->p0, bpp, 0);
+
+	if (img->p1) {
+		/*
+		 * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
+		 * we need to shift x direction same as y dir for offsite
+		 */
+		if (img->color_fmt == MDP_Y_CBCR_H2V2_ADRENO
+							&& layer == 0)
+			img->p1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
+			(((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
+									* bpp;
+		else
+			img->p1 += ((x / h_slice) * h_slice +
+			((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
+		if (layer != 0)
+			img->p1 = mdp_adjust_rot_addr(blit_op, img->p1, bpp, 1);
+	}
+}
+
+int load_ppp_lut(int tableType, uint32_t *lut)
+{
+	int i;
+	uint32_t base_addr;
+
+	base_addr = tableType ? MDP3_PPP_POST_LUT : MDP3_PPP_PRE_LUT;
+	for (i = 0; i < PPP_LUT_MAX; i++)
+		PPP_WRITEL(lut[i], base_addr + MDP3_PPP_LUTn(i));
+
+	return 0;
+}
+
+/* Configure Primary CSC Matrix */
+int load_primary_matrix(struct ppp_csc_table *csc)
+{
+	int i;
+
+	for (i = 0; i < MDP_CSC_SIZE; i++)
+		PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_PFMVn(i));
+
+	for (i = 0; i < MDP_CSC_SIZE; i++)
+		PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_PRMVn(i));
+
+	for (i = 0; i < MDP_BV_SIZE; i++)
+		PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_PBVn(i));
+
+	for (i = 0; i < MDP_LV_SIZE; i++)
+		PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_PLVn(i));
+
+	return 0;
+}
+
+/* Load Secondary CSC Matrix */
+int load_secondary_matrix(struct ppp_csc_table *csc)
+{
+	int i;
+
+	for (i = 0; i < MDP_CSC_SIZE; i++)
+		PPP_WRITEL(csc->fwd_matrix[i], MDP3_PPP_CSC_SFMVn(i));
+
+	for (i = 0; i < MDP_CSC_SIZE; i++)
+		PPP_WRITEL(csc->rev_matrix[i], MDP3_PPP_CSC_SRMVn(i));
+
+	for (i = 0; i < MDP_BV_SIZE; i++)
+		PPP_WRITEL(csc->bv[i], MDP3_PPP_CSC_SBVn(i));
+
+	for (i = 0; i < MDP_LV_SIZE; i++)
+		PPP_WRITEL(csc->lv[i], MDP3_PPP_CSC_SLVn(i));
+	return 0;
+}
+
+int load_csc_matrix(int matrix_type, struct ppp_csc_table *csc)
+{
+	if (matrix_type == CSC_PRIMARY_MATRIX)
+		return load_primary_matrix(csc);
+
+	return load_secondary_matrix(csc);
+}
+
+int config_ppp_src(struct ppp_img_desc *src)
+{
+	uint32_t val;
+
+	val = ((src->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
+		   (src->roi.width & MDP3_PPP_XY_MASK);
+	PPP_WRITEL(val, MDP3_PPP_SRC_SIZE);
+
+	PPP_WRITEL(src->p0, MDP3_PPP_SRCP0_ADDR);
+	PPP_WRITEL(src->p1, MDP3_PPP_SRCP1_ADDR);
+	PPP_WRITEL(src->p3, MDP3_PPP_SRCP3_ADDR);
+
+	val = (src->stride0 & MDP3_PPP_STRIDE_MASK) |
+			((src->stride1 & MDP3_PPP_STRIDE_MASK) <<
+			MDP3_PPP_STRIDE1_OFFSET);
+	PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE1_ADDR);
+	val = ((src->stride2 & MDP3_PPP_STRIDE_MASK) <<
+			MDP3_PPP_STRIDE1_OFFSET);
+	PPP_WRITEL(val, MDP3_PPP_SRC_YSTRIDE2_ADDR);
+
+	val = ppp_src_config(src->color_fmt);
+	val |= (src->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0;
+	val |= (src->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0;
+	PPP_WRITEL(val, MDP3_PPP_SRC_FORMAT);
+	PPP_WRITEL(ppp_pack_pattern(src->color_fmt),
+		MDP3_PPP_SRC_UNPACK_PATTERN1);
+	return 0;
+}
+
+int config_ppp_out(struct ppp_img_desc *dst)
+{
+	uint32_t val;
+	bool pseudoplanr_output = false;
+
+	switch (dst->color_fmt) {
+	case MDP_Y_CBCR_H2V2:
+	case MDP_Y_CRCB_H2V2:
+	case MDP_Y_CBCR_H2V1:
+	case MDP_Y_CRCB_H2V1:
+		pseudoplanr_output = true;
+		break;
+	default:
+		break;
+	}
+	val = ppp_out_config(dst->color_fmt);
+	if (pseudoplanr_output)
+		val |= PPP_DST_PLANE_PSEUDOPLN;
+	PPP_WRITEL(val, MDP3_PPP_OUT_FORMAT);
+	PPP_WRITEL(ppp_pack_pattern(dst->color_fmt),
+		MDP3_PPP_OUT_PACK_PATTERN1);
+
+	val = ((dst->roi.height & MDP3_PPP_XY_MASK) << MDP3_PPP_XY_OFFSET) |
+		   (dst->roi.width & MDP3_PPP_XY_MASK);
+	PPP_WRITEL(val, MDP3_PPP_OUT_SIZE);
+
+	PPP_WRITEL(dst->p0, MDP3_PPP_OUTP0_ADDR);
+	PPP_WRITEL(dst->p1, MDP3_PPP_OUTP1_ADDR);
+	PPP_WRITEL(dst->p3, MDP3_PPP_OUTP3_ADDR);
+
+	val = (dst->stride0 & MDP3_PPP_STRIDE_MASK) |
+			((dst->stride1 & MDP3_PPP_STRIDE_MASK) <<
+			MDP3_PPP_STRIDE1_OFFSET);
+	PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE1_ADDR);
+	val = ((dst->stride2 & MDP3_PPP_STRIDE_MASK) <<
+			MDP3_PPP_STRIDE1_OFFSET);
+	PPP_WRITEL(val, MDP3_PPP_OUT_YSTRIDE2_ADDR);
+	return 0;
+}
+
+int config_ppp_background(struct ppp_img_desc *bg)
+{
+	uint32_t val;
+
+	PPP_WRITEL(bg->p0, MDP3_PPP_BGP0_ADDR);
+	PPP_WRITEL(bg->p1, MDP3_PPP_BGP1_ADDR);
+	PPP_WRITEL(bg->p3, MDP3_PPP_BGP3_ADDR);
+
+	val = (bg->stride0 & MDP3_PPP_STRIDE_MASK) |
+			((bg->stride1 & MDP3_PPP_STRIDE_MASK) <<
+			MDP3_PPP_STRIDE1_OFFSET);
+	PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE1_ADDR);
+	val = ((bg->stride2 & MDP3_PPP_STRIDE_MASK) <<
+			MDP3_PPP_STRIDE1_OFFSET);
+	PPP_WRITEL(val, MDP3_PPP_BG_YSTRIDE2_ADDR);
+
+	PPP_WRITEL(ppp_src_config(bg->color_fmt),
+		MDP3_PPP_BG_FORMAT);
+	PPP_WRITEL(ppp_pack_pattern(bg->color_fmt),
+		MDP3_PPP_BG_UNPACK_PATTERN1);
+	return 0;
+}
+
+void ppp_edge_rep_luma_pixel(struct ppp_blit_op *blit_op,
+	struct ppp_edge_rep *er)
+{
+	if (blit_op->mdp_op & MDPOP_ASCALE) {
+
+		er->is_scale_enabled = 1;
+
+		if (blit_op->mdp_op & MDPOP_ROT90) {
+			er->dst_roi_width = blit_op->dst.roi.height;
+			er->dst_roi_height = blit_op->dst.roi.width;
+		} else {
+			er->dst_roi_width = blit_op->dst.roi.width;
+			er->dst_roi_height = blit_op->dst.roi.height;
+		}
+
+		/*
+		 * Find out the luma pixels needed for scaling in the
+		 * x direction (LEFT and RIGHT).  Locations of pixels are
+		 * relative to the ROI. Upper-left corner of ROI corresponds
+		 * to coordinates (0,0). Also set the number of luma pixel
+		 * to repeat.
+		 */
+		if (blit_op->src.roi.width > 3 * er->dst_roi_width) {
+			/* scale factor < 1/3 */
+			er->luma_interp_point_right =
+				(blit_op->src.roi.width - 1);
+		} else if (blit_op->src.roi.width == 3 * er->dst_roi_width) {
+			/* scale factor == 1/3 */
+			er->luma_interp_point_right =
+				(blit_op->src.roi.width - 1) + 1;
+			er->luma_repeat_right = 1;
+		} else if ((blit_op->src.roi.width > er->dst_roi_width) &&
+			   (blit_op->src.roi.width < 3 * er->dst_roi_width)) {
+			/* 1/3 < scale factor < 1 */
+			er->luma_interp_point_left = -1;
+			er->luma_interp_point_right =
+				(blit_op->src.roi.width - 1) + 1;
+			er->luma_repeat_left = 1;
+			er->luma_repeat_right = 1;
+		} else if (blit_op->src.roi.width == er->dst_roi_width) {
+			/* scale factor == 1 */
+			er->luma_interp_point_left = -1;
+			er->luma_interp_point_right =
+				(blit_op->src.roi.width - 1) + 2;
+			er->luma_repeat_left = 1;
+			er->luma_repeat_right = 2;
+		} else {
+			  /* scale factor > 1 */
+			er->luma_interp_point_left = -2;
+			er->luma_interp_point_right =
+				(blit_op->src.roi.width - 1) + 2;
+			er->luma_repeat_left = 2;
+			er->luma_repeat_right = 2;
+		}
+
+		/*
+		 * Find out the number of pixels needed for scaling in the
+		 * y direction (TOP and BOTTOM).  Locations of pixels are
+		 * relative to the ROI. Upper-left corner of ROI corresponds
+		 * to coordinates (0,0). Also set the number of luma pixel
+		 * to repeat.
+		 */
+		if (blit_op->src.roi.height > 3 * er->dst_roi_height) {
+			er->luma_interp_point_bottom =
+				(blit_op->src.roi.height - 1);
+		} else if (blit_op->src.roi.height == 3 * er->dst_roi_height) {
+			er->luma_interp_point_bottom =
+				(blit_op->src.roi.height - 1) + 1;
+			er->luma_repeat_bottom = 1;
+		} else if ((blit_op->src.roi.height > er->dst_roi_height) &&
+			   (blit_op->src.roi.height < 3 * er->dst_roi_height)) {
+			er->luma_interp_point_top = -1;
+			er->luma_interp_point_bottom =
+				(blit_op->src.roi.height - 1) + 1;
+			er->luma_repeat_top = 1;
+			er->luma_repeat_bottom = 1;
+		} else if (blit_op->src.roi.height == er->dst_roi_height) {
+			er->luma_interp_point_top = -1;
+			er->luma_interp_point_bottom =
+				(blit_op->src.roi.height - 1) + 2;
+			er->luma_repeat_top = 1;
+			er->luma_repeat_bottom = 2;
+		} else {
+			er->luma_interp_point_top = -2;
+			er->luma_interp_point_bottom =
+				(blit_op->src.roi.height - 1) + 2;
+			er->luma_repeat_top = 2;
+			er->luma_repeat_bottom = 2;
+		}
+	} else {
+		/*
+		 * Since no scaling needed, Tile Fetch does not require any
+		 * more luma pixel than what the ROI contains.
+		 */
+		er->luma_interp_point_right =
+			(int32_t) (blit_op->src.roi.width - 1);
+		er->luma_interp_point_bottom =
+			(int32_t) (blit_op->src.roi.height - 1);
+	}
+	/* After adding the ROI offsets, we have locations of
+	 * luma_interp_points relative to the image.
+	 */
+	er->luma_interp_point_left += (int32_t) (blit_op->src.roi.x);
+	er->luma_interp_point_right += (int32_t) (blit_op->src.roi.x);
+	er->luma_interp_point_top += (int32_t) (blit_op->src.roi.y);
+	er->luma_interp_point_bottom += (int32_t) (blit_op->src.roi.y);
+}
+
+void ppp_edge_rep_chroma_pixel(struct ppp_blit_op *blit_op,
+	struct ppp_edge_rep *er)
+{
+	bool chroma_edge_enable = true;
+	uint32_t is_yuv_offsite_vertical = 0;
+
+	/* find out which chroma pixels are needed for chroma upsampling. */
+	switch (blit_op->src.color_fmt) {
+	case MDP_Y_CBCR_H2V1:
+	case MDP_Y_CRCB_H2V1:
+	case MDP_YCRYCB_H2V1:
+		er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
+		er->chroma_interp_point_right =
+			(er->luma_interp_point_right + 1) >> 1;
+		er->chroma_interp_point_top = er->luma_interp_point_top;
+		er->chroma_interp_point_bottom = er->luma_interp_point_bottom;
+		break;
+
+	case MDP_Y_CBCR_H2V2:
+	case MDP_Y_CBCR_H2V2_ADRENO:
+	case MDP_Y_CRCB_H2V2:
+		er->chroma_interp_point_left = er->luma_interp_point_left >> 1;
+		er->chroma_interp_point_right =
+			(er->luma_interp_point_right + 1) >> 1;
+		er->chroma_interp_point_top =
+			(er->luma_interp_point_top - 1) >> 1;
+		er->chroma_interp_point_bottom =
+		    (er->luma_interp_point_bottom + 1) >> 1;
+		is_yuv_offsite_vertical = 1;
+		break;
+
+	default:
+		chroma_edge_enable = false;
+		er->chroma_interp_point_left = er->luma_interp_point_left;
+		er->chroma_interp_point_right = er->luma_interp_point_right;
+		er->chroma_interp_point_top = er->luma_interp_point_top;
+		er->chroma_interp_point_bottom = er->luma_interp_point_bottom;
+
+		break;
+	}
+
+	if (chroma_edge_enable) {
+		/* Defines which chroma pixels belongs to the roi */
+		switch (blit_op->src.color_fmt) {
+		case MDP_Y_CBCR_H2V1:
+		case MDP_Y_CRCB_H2V1:
+		case MDP_YCRYCB_H2V1:
+			er->chroma_bound_left = blit_op->src.roi.x / 2;
+			/* there are half as many chroma pixel as luma pixels */
+			er->chroma_bound_right =
+			    (blit_op->src.roi.width +
+				blit_op->src.roi.x - 1) / 2;
+			er->chroma_bound_top = blit_op->src.roi.y;
+			er->chroma_bound_bottom =
+			    (blit_op->src.roi.height + blit_op->src.roi.y - 1);
+			break;
+		case MDP_Y_CBCR_H2V2:
+		case MDP_Y_CBCR_H2V2_ADRENO:
+		case MDP_Y_CRCB_H2V2:
+			/*
+			 * cosite in horizontal dir, and offsite in vertical dir
+			 * width of chroma ROI is 1/2 of size of luma ROI
+			 * height of chroma ROI is 1/2 of size of luma ROI
+			 */
+			er->chroma_bound_left = blit_op->src.roi.x / 2;
+			er->chroma_bound_right =
+			    (blit_op->src.roi.width +
+				blit_op->src.roi.x - 1) / 2;
+			er->chroma_bound_top = blit_op->src.roi.y / 2;
+			er->chroma_bound_bottom =
+			    (blit_op->src.roi.height +
+				blit_op->src.roi.y - 1) / 2;
+			break;
+
+		default:
+			/*
+			 * If no valid chroma sub-sampling format specified,
+			 * assume 4:4:4 ( i.e. fully sampled).
+			 */
+			er->chroma_bound_left = blit_op->src.roi.x;
+			er->chroma_bound_right = blit_op->src.roi.width +
+				blit_op->src.roi.x - 1;
+			er->chroma_bound_top = blit_op->src.roi.y;
+			er->chroma_bound_bottom =
+			    (blit_op->src.roi.height + blit_op->src.roi.y - 1);
+			break;
+		}
+
+		/*
+		 * Knowing which chroma pixels are needed, and which chroma
+		 * pixels belong to the ROI (i.e. available for fetching ),
+		 * calculate how many chroma pixels Tile Fetch needs to
+		 * duplicate.  If any required chroma pixels falls outside
+		 * of the ROI, Tile Fetch must obtain them by replicating
+		 * pixels.
+		 */
+		if (er->chroma_bound_left > er->chroma_interp_point_left)
+			er->chroma_repeat_left =
+			    er->chroma_bound_left -
+				er->chroma_interp_point_left;
+		else
+			er->chroma_repeat_left = 0;
+
+		if (er->chroma_interp_point_right > er->chroma_bound_right)
+			er->chroma_repeat_right =
+			    er->chroma_interp_point_right -
+				er->chroma_bound_right;
+		else
+			er->chroma_repeat_right = 0;
+
+		if (er->chroma_bound_top > er->chroma_interp_point_top)
+			er->chroma_repeat_top =
+			    er->chroma_bound_top -
+				er->chroma_interp_point_top;
+		else
+			er->chroma_repeat_top = 0;
+
+		if (er->chroma_interp_point_bottom > er->chroma_bound_bottom)
+			er->chroma_repeat_bottom =
+			    er->chroma_interp_point_bottom -
+				er->chroma_bound_bottom;
+		else
+			er->chroma_repeat_bottom = 0;
+
+		if (er->is_scale_enabled && (blit_op->src.roi.height == 1)
+		    && is_yuv_offsite_vertical) {
+			er->chroma_repeat_bottom = 3;
+			er->chroma_repeat_top = 0;
+		}
+	}
+}
+
+int config_ppp_edge_rep(struct ppp_blit_op *blit_op)
+{
+	uint32_t reg = 0;
+	struct ppp_edge_rep er;
+
+	memset(&er, 0, sizeof(er));
+
+	ppp_edge_rep_luma_pixel(blit_op, &er);
+
+	/*
+	 * After adding the ROI offsets, we have locations of
+	 * chroma_interp_points relative to the image.
+	 */
+	er.chroma_interp_point_left = er.luma_interp_point_left;
+	er.chroma_interp_point_right = er.luma_interp_point_right;
+	er.chroma_interp_point_top = er.luma_interp_point_top;
+	er.chroma_interp_point_bottom = er.luma_interp_point_bottom;
+
+	ppp_edge_rep_chroma_pixel(blit_op, &er);
+	/* ensure repeats are >=0 and no larger than 3 pixels */
+	if ((er.chroma_repeat_left < 0) || (er.chroma_repeat_right < 0) ||
+	    (er.chroma_repeat_top < 0) || (er.chroma_repeat_bottom < 0))
+		return -EINVAL;
+	if ((er.chroma_repeat_left > 3) || (er.chroma_repeat_right > 3) ||
+	    (er.chroma_repeat_top > 3) || (er.chroma_repeat_bottom > 3))
+		return -EINVAL;
+	if ((er.luma_repeat_left < 0) || (er.luma_repeat_right < 0) ||
+	    (er.luma_repeat_top < 0) || (er.luma_repeat_bottom < 0))
+		return -EINVAL;
+	if ((er.luma_repeat_left > 3) || (er.luma_repeat_right > 3) ||
+	    (er.luma_repeat_top > 3) || (er.luma_repeat_bottom > 3))
+		return -EINVAL;
+
+	reg |= (er.chroma_repeat_left & 3) << MDP_LEFT_CHROMA;
+	reg |= (er.chroma_repeat_right & 3) << MDP_RIGHT_CHROMA;
+	reg |= (er.chroma_repeat_top & 3) << MDP_TOP_CHROMA;
+	reg |= (er.chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA;
+	reg |= (er.luma_repeat_left & 3) << MDP_LEFT_LUMA;
+	reg |= (er.luma_repeat_right & 3) << MDP_RIGHT_LUMA;
+	reg |= (er.luma_repeat_top & 3) << MDP_TOP_LUMA;
+	reg |= (er.luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA;
+	PPP_WRITEL(reg, MDP3_PPP_SRC_EDGE_REP);
+	return 0;
+}
+
+int config_ppp_bg_edge_rep(struct ppp_blit_op *blit_op)
+{
+	uint32_t reg = 0;
+
+	switch (blit_op->dst.color_fmt) {
+	case MDP_Y_CBCR_H2V2:
+	case MDP_Y_CRCB_H2V2:
+		if (blit_op->dst.roi.y == 0)
+			reg |= BIT(MDP_TOP_CHROMA);
+
+		if ((blit_op->dst.roi.y + blit_op->dst.roi.height) ==
+		    blit_op->dst.prop.height) {
+			reg |= BIT(MDP_BOTTOM_CHROMA);
+		}
+
+		if (((blit_op->dst.roi.x + blit_op->dst.roi.width) ==
+				blit_op->dst.prop.width) &&
+				((blit_op->dst.roi.width % 2) == 0))
+			reg |= BIT(MDP_RIGHT_CHROMA);
+		break;
+	case MDP_Y_CBCR_H2V1:
+	case MDP_Y_CRCB_H2V1:
+	case MDP_YCRYCB_H2V1:
+		if (((blit_op->dst.roi.x + blit_op->dst.roi.width) ==
+				blit_op->dst.prop.width) &&
+				((blit_op->dst.roi.width % 2) == 0))
+			reg |= BIT(MDP_RIGHT_CHROMA);
+		break;
+	default:
+		break;
+	}
+	PPP_WRITEL(reg, MDP3_PPP_BG_EDGE_REP);
+	return 0;
+}
+
+int config_ppp_lut(uint32_t *pppop_reg_ptr, int lut_c0_en,
+	int lut_c1_en, int lut_c2_en)
+{
+	if (lut_c0_en)
+		*pppop_reg_ptr |= MDP_LUT_C0_EN;
+	if (lut_c1_en)
+		*pppop_reg_ptr |= MDP_LUT_C1_EN;
+	if (lut_c2_en)
+		*pppop_reg_ptr |= MDP_LUT_C2_EN;
+	return 0;
+}
+
+int config_ppp_scale(struct ppp_blit_op *blit_op, uint32_t *pppop_reg_ptr)
+{
+	struct ppp_img_desc *src = &blit_op->src;
+	struct ppp_img_desc *dst = &blit_op->dst;
+	uint32_t dstW, dstH;
+	uint32_t x_fac, y_fac;
+	uint32_t mdp_blur = 0;
+	uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y;
+	int x_idx, y_idx;
+
+	if (blit_op->mdp_op & MDPOP_ASCALE) {
+		if (blit_op->mdp_op & MDPOP_ROT90) {
+			dstW = dst->roi.height;
+			dstH = dst->roi.width;
+		} else {
+			dstW = dst->roi.width;
+			dstH = dst->roi.height;
+		}
+		*pppop_reg_ptr |=
+			(PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
+
+		mdp_blur = blit_op->mdp_op & MDPOP_BLUR;
+
+		if ((dstW != src->roi.width) ||
+		    (dstH != src->roi.height) || mdp_blur) {
+
+				mdp_calc_scale_params(blit_op->src.roi.x,
+					blit_op->src.roi.width,
+					dstW, 1, &phase_init_x,
+					&phase_step_x);
+				mdp_calc_scale_params(blit_op->src.roi.y,
+					blit_op->src.roi.height,
+					dstH, 0, &phase_init_y,
+					&phase_step_y);
+
+			PPP_WRITEL(phase_init_x, MDP3_PPP_SCALE_PHASEX_INIT);
+			PPP_WRITEL(phase_init_y, MDP3_PPP_SCALE_PHASEY_INIT);
+			PPP_WRITEL(phase_step_x, MDP3_PPP_SCALE_PHASEX_STEP);
+			PPP_WRITEL(phase_step_y, MDP3_PPP_SCALE_PHASEY_STEP);
+
+
+			if (dstW > src->roi.width || dstW > src->roi.height)
+				ppp_load_up_lut();
+
+			if (mdp_blur)
+				ppp_load_gaussian_lut();
+
+			if (dstW <= src->roi.width) {
+				x_fac = (dstW * 100) / src->roi.width;
+				x_idx = scale_idx(x_fac);
+				ppp_load_x_scale_table(x_idx);
+			}
+			if (dstH <= src->roi.height) {
+				y_fac = (dstH * 100) / src->roi.height;
+				y_idx = scale_idx(y_fac);
+				ppp_load_y_scale_table(y_idx);
+			}
+
+		} else {
+			blit_op->mdp_op &= ~(MDPOP_ASCALE);
+		}
+	}
+	config_ppp_edge_rep(blit_op);
+	config_ppp_bg_edge_rep(blit_op);
+	return 0;
+}
+
+int config_ppp_csc(int src_color, int dst_color, uint32_t *pppop_reg_ptr)
+{
+	bool inputRGB, outputRGB;
+
+	inputRGB = check_if_rgb(src_color);
+	outputRGB = check_if_rgb(dst_color);
+
+	if ((!inputRGB) && (outputRGB))
+		*pppop_reg_ptr |= PPP_OP_CONVERT_YCBCR2RGB |
+			PPP_OP_CONVERT_ON;
+	if ((inputRGB) && (!outputRGB))
+		*pppop_reg_ptr |= PPP_OP_CONVERT_ON;
+
+	return 0;
+}
+
+int config_ppp_blend(struct ppp_blit_op *blit_op,
+			uint32_t *pppop_reg_ptr)
+{
+	struct ppp_csc_table *csc;
+	uint32_t alpha, trans_color;
+	uint32_t val = 0;
+	int c_fmt = blit_op->src.color_fmt;
+	int bg_alpha;
+
+	csc = ppp_csc_rgb2yuv();
+	alpha = blit_op->blend.const_alpha;
+	trans_color = blit_op->blend.trans_color;
+	if (blit_op->mdp_op & MDPOP_FG_PM_ALPHA) {
+		if (ppp_per_p_alpha(c_fmt)) {
+			*pppop_reg_ptr |= PPP_OP_ROT_ON |
+					  PPP_OP_BLEND_ON |
+					  PPP_OP_BLEND_CONSTANT_ALPHA;
+		} else {
+			if ((blit_op->mdp_op & MDPOP_ALPHAB)
+				&& (blit_op->blend.const_alpha == 0xff)) {
+				blit_op->mdp_op &= ~(MDPOP_ALPHAB);
+			}
+
+			if ((blit_op->mdp_op & MDPOP_ALPHAB)
+			   || (blit_op->mdp_op & MDPOP_TRANSP)) {
+
+				*pppop_reg_ptr |= PPP_OP_ROT_ON |
+					PPP_OP_BLEND_ON |
+					PPP_OP_BLEND_CONSTANT_ALPHA |
+					PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+			}
+		}
+
+		bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
+			PPP_BLEND_BG_ALPHA_REVERSE;
+
+		if ((ppp_per_p_alpha(c_fmt)) && !(blit_op->mdp_op &
+						MDPOP_LAYER_IS_FG)) {
+			bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
+		} else {
+			bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
+			bg_alpha |= blit_op->blend.const_alpha << 24;
+		}
+		PPP_WRITEL(bg_alpha, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+
+		if (blit_op->mdp_op & MDPOP_TRANSP)
+			*pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
+	} else if (ppp_per_p_alpha(c_fmt)) {
+		if (blit_op->mdp_op & MDPOP_LAYER_IS_FG)
+			*pppop_reg_ptr |= PPP_OP_ROT_ON |
+				  PPP_OP_BLEND_ON |
+				  PPP_OP_BLEND_CONSTANT_ALPHA;
+		else
+			*pppop_reg_ptr |= PPP_OP_ROT_ON |
+				  PPP_OP_BLEND_ON |
+				  PPP_OP_BLEND_SRCPIXEL_ALPHA;
+		PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+	} else {
+		if ((blit_op->mdp_op & MDPOP_ALPHAB)
+				&& (blit_op->blend.const_alpha == 0xff)) {
+			blit_op->mdp_op &=
+				~(MDPOP_ALPHAB);
+		}
+
+		if ((blit_op->mdp_op & MDPOP_ALPHAB)
+		   || (blit_op->mdp_op & MDPOP_TRANSP)) {
+			*pppop_reg_ptr |= PPP_OP_ROT_ON |
+				PPP_OP_BLEND_ON |
+				PPP_OP_BLEND_CONSTANT_ALPHA |
+				PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+		}
+
+		if (blit_op->mdp_op & MDPOP_TRANSP)
+			*pppop_reg_ptr |=
+				PPP_BLEND_CALPHA_TRNASP;
+		PPP_WRITEL(0, MDP3_PPP_BLEND_BG_ALPHA_SEL);
+	}
+
+	if (*pppop_reg_ptr & PPP_OP_BLEND_ON) {
+		blit_op->bg = blit_op->dst;
+		config_ppp_background(&blit_op->bg);
+
+		if (blit_op->dst.color_fmt == MDP_YCRYCB_H2V1) {
+			*pppop_reg_ptr |= PPP_OP_BG_CHROMA_H2V1;
+			if (blit_op->mdp_op & MDPOP_TRANSP) {
+				trans_color = conv_rgb2yuv(trans_color,
+					&csc->fwd_matrix[0],
+					&csc->bv[0],
+					&csc->lv[0]);
+			}
+		}
+	}
+	val = (alpha << MDP_BLEND_CONST_ALPHA);
+	val |= (trans_color & MDP_BLEND_TRASP_COL_MASK);
+	PPP_WRITEL(val, MDP3_PPP_BLEND_PARAM);
+	return 0;
+}
+
+int config_ppp_rotation(uint32_t mdp_op, uint32_t *pppop_reg_ptr)
+{
+	*pppop_reg_ptr |= PPP_OP_ROT_ON;
+
+	if (mdp_op & MDPOP_ROT90)
+		*pppop_reg_ptr |= PPP_OP_ROT_90;
+	if (mdp_op & MDPOP_LR)
+		*pppop_reg_ptr |= PPP_OP_FLIP_LR;
+	if (mdp_op & MDPOP_UD)
+		*pppop_reg_ptr |= PPP_OP_FLIP_UD;
+
+	return 0;
+}
+
+int config_ppp_op_mode(struct ppp_blit_op *blit_op)
+{
+	uint32_t ppp_operation_reg = 0;
+	int sv_slice, sh_slice;
+	int dv_slice, dh_slice;
+
+	sv_slice = sh_slice = dv_slice = dh_slice = 1;
+
+	ppp_operation_reg |= ppp_dst_op_reg(blit_op->dst.color_fmt);
+	switch (blit_op->dst.color_fmt) {
+	case MDP_Y_CBCR_H2V2:
+	case MDP_Y_CRCB_H2V2:
+		y_h_even_num(&blit_op->dst);
+		y_h_even_num(&blit_op->src);
+		dv_slice = 2;
+	case MDP_Y_CBCR_H2V1:
+	case MDP_Y_CRCB_H2V1:
+	case MDP_YCRYCB_H2V1:
+		x_w_even_num(&blit_op->dst);
+		x_w_even_num(&blit_op->src);
+		dh_slice = 2;
+		break;
+	default:
+		break;
+	}
+
+	ppp_operation_reg |= ppp_src_op_reg(blit_op->src.color_fmt);
+	switch (blit_op->src.color_fmt) {
+	case MDP_Y_CBCR_H2V2:
+	case MDP_Y_CBCR_H2V2_ADRENO:
+	case MDP_Y_CRCB_H2V2:
+		sh_slice = sv_slice = 2;
+		break;
+	case MDP_YCRYCB_H2V1:
+		x_w_even_num(&blit_op->dst);
+		x_w_even_num(&blit_op->src);
+	case MDP_Y_CBCR_H2V1:
+	case MDP_Y_CRCB_H2V1:
+		sh_slice = 2;
+		break;
+	default:
+		break;
+	}
+
+	config_ppp_csc(blit_op->src.color_fmt,
+		blit_op->dst.color_fmt, &ppp_operation_reg);
+
+	if (blit_op->mdp_op & MDPOP_DITHER)
+		ppp_operation_reg |= PPP_OP_DITHER_EN;
+
+	if (blit_op->mdp_op & MDPOP_ROTATION)
+		config_ppp_rotation(blit_op->mdp_op, &ppp_operation_reg);
+
+	if (blit_op->src.color_fmt == MDP_Y_CBCR_H2V2_ADRENO) {
+		blit_op->src.stride0 = ALIGN(blit_op->src.prop.width, 32) *
+			ppp_bpp(blit_op->src.color_fmt);
+		blit_op->src.stride1 = 2 * ALIGN(blit_op->src.prop.width/2, 32);
+	} else {
+		blit_op->src.stride0 = blit_op->src.prop.width *
+			ppp_bpp(blit_op->src.color_fmt);
+		blit_op->src.stride1 = blit_op->src.stride0;
+	}
+
+	blit_op->dst.stride0 = blit_op->dst.prop.width *
+		ppp_bpp(blit_op->dst.color_fmt);
+
+	if (ppp_multi_plane(blit_op->dst.color_fmt)) {
+		blit_op->dst.p1 = blit_op->dst.p0;
+		blit_op->dst.p1 += blit_op->dst.prop.width *
+			blit_op->dst.prop.height *
+			ppp_bpp(blit_op->dst.color_fmt);
+	} else {
+		blit_op->dst.p1 = NULL;
+	}
+
+	/* Jumping from Y-Plane to Chroma Plane */
+	/* first pixel addr calculation */
+	mdp_adjust_start_addr(blit_op, &blit_op->src, sv_slice, sh_slice, 0);
+	mdp_adjust_start_addr(blit_op, &blit_op->dst, dv_slice, dh_slice, 2);
+
+	config_ppp_scale(blit_op, &ppp_operation_reg);
+
+	config_ppp_blend(blit_op, &ppp_operation_reg);
+
+	config_ppp_src(&blit_op->src);
+	config_ppp_out(&blit_op->dst);
+	PPP_WRITEL(ppp_operation_reg, MDP3_PPP_OP_MODE);
+	mb();
+	return 0;
+}
+
+void ppp_enable(void)
+{
+	PPP_WRITEL(0x1000, 0x30);
+	mb();
+}
+
+int mdp3_ppp_init(void)
+{
+	load_ppp_lut(LUT_PRE_TABLE, ppp_default_pre_lut());
+	load_ppp_lut(LUT_POST_TABLE, ppp_default_post_lut());
+	load_csc_matrix(CSC_PRIMARY_MATRIX, ppp_csc_rgb2yuv());
+	load_csc_matrix(CSC_SECONDARY_MATRIX, ppp_csc_table2());
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 5d56df4..c663170 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -408,12 +408,14 @@
 	pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
 				ctrl_pdata, ctrl_pdata->ndx);
 
-	mdss_dsi_clk_disable(pdata);
-	mdss_dsi_unprepare_clocks(ctrl_pdata);
+	if (pdata->panel_info.type == MIPI_CMD_PANEL)
+		mdss_dsi_clk_ctrl(ctrl_pdata, 1);
 
 	/* disable DSI controller */
 	mdss_dsi_controller_cfg(0, pdata);
 
+	mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+
 	/* disable DSI phy */
 	mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
 	ret = mdss_dsi_panel_power_on(pdata, 0);
@@ -431,6 +433,7 @@
 {
 	int ret = 0;
 	struct mipi_panel_info *mipi;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
 	pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
 
@@ -439,20 +442,24 @@
 		return -EINVAL;
 	}
 
-	mipi  = &pdata->panel_info.mipi;
+	mipi = &pdata->panel_info.mipi;
 
-	ret = mdss_dsi_panel_power_on(pdata, 1);
-	if (ret) {
-		pr_err("%s: Panel power on failed\n", __func__);
-		return ret;
-	}
+	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+
+	pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
+				ctrl_pdata, ctrl_pdata->ndx);
+
+	WARN(ctrl_pdata->panel_state != UNKNOWN_STATE,
+			"incorrect panel state=%d\n", ctrl_pdata->panel_state);
+
 	mdss_dsi_sw_reset(pdata);
 	mdss_dsi_host_init(mipi, pdata);
 
-	pdata->panel_info.panel_power_on = 1;
-
 	mdss_dsi_op_mode_config(mipi->mode, pdata);
 
+	ctrl_pdata->panel_state = PANEL_ON;
+
 	pr_debug("%s-:End\n", __func__);
 	return ret;
 }
@@ -498,8 +505,7 @@
 	mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
 	mdss_dsi_phy_init(pdata);
 
-	mdss_dsi_prepare_clocks(ctrl_pdata);
-	mdss_dsi_clk_enable(pdata);
+	mdss_dsi_clk_ctrl(ctrl_pdata, 1);
 
 	clk_rate = pdata->panel_info.clk_rate;
 	clk_rate = min(clk_rate, pdata->panel_info.clk_max);
@@ -577,6 +583,9 @@
 		wmb();
 	}
 
+	if (pdata->panel_info.type == MIPI_CMD_PANEL)
+		mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+
 	pr_debug("%s-:\n", __func__);
 	return 0;
 }
@@ -598,12 +607,15 @@
 				panel_data);
 	mipi  = &pdata->panel_info.mipi;
 
-	ret = ctrl_pdata->on(pdata);
-	if (ret) {
-		pr_err("%s: unable to initialize the panel\n", __func__);
-		return ret;
+	if (ctrl_pdata->panel_state != PANEL_ON) {
+		ret = ctrl_pdata->on(pdata);
+		if (ret) {
+			pr_err("%s: unable to initialize the panel\n",
+							__func__);
+			return ret;
+		}
+		ctrl_pdata->panel_state = PANEL_ON;
 	}
-
 	mdss_dsi_op_mode_config(mipi->mode, pdata);
 
 	pr_debug("%s-:\n", __func__);
@@ -628,12 +640,14 @@
 
 	mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
 
-	ret = ctrl_pdata->off(pdata);
-	if (ret) {
-		pr_err("%s: Panel OFF failed\n", __func__);
-		return ret;
+	if (ctrl_pdata->panel_state == PANEL_ON) {
+		ret = ctrl_pdata->off(pdata);
+		if (ret) {
+			pr_err("%s: Panel OFF failed\n", __func__);
+			return ret;
+		}
+		ctrl_pdata->panel_state = PANEL_OFF;
 	}
-
 	pr_debug("%s-:End\n", __func__);
 	return ret;
 }
@@ -655,35 +669,38 @@
 	switch (event) {
 	case MDSS_EVENT_UNBLANK:
 		rc = mdss_dsi_on(pdata);
-		if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
+		if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE)
 			rc = mdss_dsi_unblank(pdata);
-		}
 		break;
 	case MDSS_EVENT_PANEL_ON:
-		if (ctrl_pdata->on_cmds->ctrl_state == DSI_HS_MODE)
+		if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE)
 			rc = mdss_dsi_unblank(pdata);
 		break;
 	case MDSS_EVENT_BLANK:
-		if (ctrl_pdata->off_cmds->ctrl_state == DSI_HS_MODE) {
+		if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE)
 			rc = mdss_dsi_blank(pdata);
-		}
 		break;
 	case MDSS_EVENT_PANEL_OFF:
-		if (ctrl_pdata->off_cmds->ctrl_state == DSI_LP_MODE) {
+		if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
 			rc = mdss_dsi_blank(pdata);
-		}
 		rc = mdss_dsi_off(pdata);
 		break;
 	case MDSS_EVENT_CONT_SPLASH_FINISH:
-		if (ctrl_pdata->on_cmds->ctrl_state == DSI_LP_MODE) {
+		if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
 			rc = mdss_dsi_cont_splash_on(pdata);
 		} else {
 			pr_debug("%s:event=%d, Dsi On not called: ctrl_state: %d\n",
 				 __func__, event,
-				 ctrl_pdata->on_cmds->ctrl_state);
+				 ctrl_pdata->on_cmds.link_state);
 			rc = -EINVAL;
 		}
 		break;
+	case MDSS_EVENT_PANEL_CLK_CTRL:
+		mdss_dsi_clk_req(ctrl_pdata, (int)arg);
+		break;
+	case MDSS_EVENT_DSI_CMDLIST_KOFF:
+		mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
@@ -1055,17 +1072,16 @@
 
 	ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler;
 
-	ctrl_pdata->on_cmds = panel_data->dsi_panel_on_cmds;
-	ctrl_pdata->off_cmds = panel_data->dsi_panel_off_cmds;
+	ctrl_pdata->on_cmds = panel_data->on_cmds;
+	ctrl_pdata->off_cmds = panel_data->off_cmds;
 
 	memcpy(&((ctrl_pdata->panel_data).panel_info),
 				&(panel_data->panel_info),
 				       sizeof(struct mdss_panel_info));
 
-	mdss_dsi_irq_handler_config(ctrl_pdata);
 	ctrl_pdata->panel_data.set_backlight = panel_data->bl_fnc;
 	ctrl_pdata->bklt_ctrl = panel_data->panel_info.bklt_ctrl;
-	ctrl_pdata->pwm_gpio = panel_data->panel_info.pwm_gpio;
+	ctrl_pdata->pwm_pmic_gpio = panel_data->panel_info.pwm_pmic_gpio;
 	ctrl_pdata->pwm_period = panel_data->panel_info.pwm_period;
 	ctrl_pdata->pwm_lpg_chan = panel_data->panel_info.pwm_lpg_chan;
 	ctrl_pdata->bklt_max = panel_data->panel_info.bl_max;
@@ -1073,6 +1089,7 @@
 	if (ctrl_pdata->bklt_ctrl == BL_PWM)
 		mdss_dsi_panel_pwm_cfg(ctrl_pdata);
 
+	mdss_dsi_ctrl_init(ctrl_pdata);
 	/*
 	 * register in mdp driver
 	 */
@@ -1090,13 +1107,20 @@
 
 		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
 		ctrl_pdata->panel_data.panel_info.panel_power_on = 1;
+		rc = mdss_dsi_panel_power_on(&(ctrl_pdata->panel_data), 1);
+		if (rc) {
+			pr_err("%s: Panel power on failed\n", __func__);
+			return rc;
+		}
 	}
 
+	ctrl_pdata->pclk_rate = dsi_pclk_rate;
+	ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
+	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
+			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
 
-	if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled) {
-		mdss_dsi_prepare_clocks(ctrl_pdata);
-		mdss_dsi_clk_enable(&(ctrl_pdata->panel_data));
-	}
+	if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled)
+		mdss_dsi_clk_ctrl(ctrl_pdata, 1);
 
 	rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
 	if (rc) {
@@ -1111,11 +1135,6 @@
 	ctrl_pdata->on = panel_data->on;
 	ctrl_pdata->off = panel_data->off;
 
-	ctrl_pdata->pclk_rate = dsi_pclk_rate;
-	ctrl_pdata->byte_clk_rate = panel_data->panel_info.clk_rate / 8;
-	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
-			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
-
 	if (panel_data->panel_info.pdest == DISPLAY_1) {
 		mdss_debug_register_base("dsi0",
 			ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
@@ -1126,6 +1145,7 @@
 		ctrl_pdata->ndx = 1;
 	}
 
+	ctrl_pdata->panel_state = UNKNOWN_STATE;
 	pr_debug("%s: Panal data initialized\n", __func__);
 	return 0;
 }
@@ -1155,8 +1175,6 @@
 {
 	int ret;
 
-	mdss_dsi_init();
-
 	ret = mdss_dsi_register_driver();
 	if (ret) {
 		pr_err("mdss_dsi_register_driver() failed!\n");
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 197ff7a..602ed9e 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -89,6 +89,12 @@
 	DSI_HS_MODE,
 };
 
+enum dsi_panel_state {
+	UNKNOWN_STATE,
+	PANEL_ON,
+	PANEL_OFF,
+};
+
 #define DSI_NON_BURST_SYNCH_PULSE	0
 #define DSI_NON_BURST_SYNCH_EVENT	1
 #define DSI_BURST_MODE			2
@@ -127,6 +133,10 @@
 #define DSI_CMD_TRIGGER_SW_SEOF		0x05	/* cmd dma only */
 #define DSI_CMD_TRIGGER_SW_TE		0x06
 
+#define DSI_VIDEO_TERM  BIT(16)
+#define DSI_MDP_TERM    BIT(8)
+#define DSI_CMD_TERM    BIT(0)
+
 extern struct device dsi_dev;
 extern int mdss_dsi_clk_on;
 extern u32 dsi_irq;
@@ -182,7 +192,6 @@
 #define DSI_HDR_DATA1(data)	((data) & 0x0ff)
 #define DSI_HDR_WC(wc)		((wc) & 0x0ffff)
 
-#define DSI_BUF_SIZE	1024
 #define MDSS_DSI_MRPS	0x04  /* Maximum Return Packet Size */
 
 #define MDSS_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align  */
@@ -234,35 +243,67 @@
 #define DTYPE_DCS_READ1_RESP    0x21    /* 1 parameter, short */
 #define DTYPE_DCS_READ2_RESP    0x22    /* 2 parameter, short */
 
+
+struct dsi_ctrl_hdr {
+	char dtype;	/* data type */
+	char last;	/* last in chain */
+	char vc;	/* virtual chan */
+	char ack;	/* ask ACK from peripheral */
+	char wait;	/* ms */
+	short dlen;	/* 16 bits */
+} __packed;
+
 struct dsi_cmd_desc {
-	int dtype;
-	int last;
-	int vc;
-	int ack;	/* ask ACK from peripheral */
-	int wait;
-	int dlen;
+	struct dsi_ctrl_hdr dchdr;
 	char *payload;
 };
 
+struct dsi_panel_cmds {
+	char *buf;
+	int blen;
+	struct dsi_cmd_desc *cmds;
+	int cmd_cnt;
+	int link_state;
+};
+
+#define CMD_REQ_MAX     4
+
+typedef void (*fxn)(u32 data);
+
+#define CMD_REQ_RX      0x0001
+#define CMD_REQ_COMMIT  0x0002
+#define CMD_CLK_CTRL    0x0004
+#define CMD_REQ_NO_MAX_PKT_SIZE 0x0008
+
+struct dcs_cmd_req {
+	struct dsi_cmd_desc *cmds;
+	int cmds_cnt;
+	u32 flags;
+	int rlen;       /* rx length */
+	fxn cb;
+};
+
+struct dcs_cmd_list {
+	int put;
+	int get;
+	int tot;
+	struct dcs_cmd_req list[CMD_REQ_MAX];
+};
+
 struct dsi_kickoff_action {
 	struct list_head act_entry;
 	void (*action) (void *);
 	void *data;
 };
 
-struct dsi_panel_cmds_list {
-	struct dsi_cmd_desc *buf;
-	u32 size;
-	char ctrl_state;
-};
-
 struct mdss_panel_common_pdata {
 	struct mdss_panel_info panel_info;
 	int (*on) (struct mdss_panel_data *pdata);
 	int (*off) (struct mdss_panel_data *pdata);
 	void (*bl_fnc) (struct mdss_panel_data *pdata, u32 bl_level);
-	struct dsi_panel_cmds_list *dsi_panel_on_cmds;
-	struct dsi_panel_cmds_list *dsi_panel_off_cmds;
+
+	struct dsi_panel_cmds on_cmds;
+	struct dsi_panel_cmds off_cmds;
 };
 
 struct dsi_drv_cm_data {
@@ -272,17 +313,24 @@
 	int broadcast_enable;
 };
 
+enum {
+	DSI_CTRL_0,
+	DSI_CTRL_1,
+	DSI_CTRL_MAX,
+};
+
 struct mdss_dsi_ctrl_pdata {
-	int ndx;
+	int ndx;	/* panel_num */
 	int (*on) (struct mdss_panel_data *pdata);
 	int (*off) (struct mdss_panel_data *pdata);
 	struct mdss_panel_data panel_data;
-	struct mdss_hw *mdss_hw;
 	unsigned char *ctrl_base;
 	int reg_size;
+	u32 clk_cnt;
 	struct clk *byte_clk;
 	struct clk *esc_clk;
 	struct clk *pixel_clk;
+	u8 panel_state;
 	int irq_cnt;
 	int mdss_dsi_clk_on;
 	int rst_gpio;
@@ -290,16 +338,32 @@
 	int disp_te_gpio;
 	int bklt_ctrl;	/* backlight ctrl */
 	int pwm_period;
-	int pwm_gpio;
+	int pwm_pmic_gpio;
 	int pwm_lpg_chan;
 	int bklt_max;
 	struct pwm_device *pwm_bl;
-	struct dsi_panel_cmds_list *on_cmds;
-	struct dsi_panel_cmds_list *off_cmds;
 	struct dsi_drv_cm_data shared_pdata;
 	u32 pclk_rate;
 	u32 byte_clk_rate;
 	struct dss_module_power power_data;
+	u32 dsi_irq_mask;
+	struct mdss_hw *dsi_hw;
+
+	struct dsi_panel_cmds on_cmds;
+	struct dsi_panel_cmds off_cmds;
+
+	struct dcs_cmd_list cmdlist;
+	struct completion dma_comp;
+	struct completion mdp_comp;
+	struct completion video_comp;
+	spinlock_t irq_lock;
+	spinlock_t mdp_lock;
+	int mdp_busy;
+	struct mutex mutex;
+	struct mutex cmd_mutex;
+
+	struct dsi_buf tx_buf;
+	struct dsi_buf rx_buf;
 };
 
 int dsi_panel_device_register(struct platform_device *pdev,
@@ -310,29 +374,26 @@
 void mdss_dsi_init(void);
 int mdss_dsi_buf_alloc(struct dsi_buf *, int size);
 int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm);
-int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
-		struct dsi_buf *dp, struct dsi_cmd_desc *cmds, int cnt);
+int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+		struct dsi_cmd_desc *cmds, int cnt);
 
-int mdss_dsi_cmd_dma_tx(struct dsi_buf *dp,
-				struct mdss_panel_data *pdata);
-int mdss_dsi_cmd_reg_tx(u32 data,
-				unsigned char *ctrl_base);
-int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
-			struct dsi_buf *tp, struct dsi_buf *rp,
-			struct dsi_cmd_desc *cmds, int len);
-int mdss_dsi_cmd_dma_rx(struct dsi_buf *tp, int rlen,
-				struct mdss_panel_data *pdata);
+int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+			struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags);
+
 void mdss_dsi_host_init(struct mipi_panel_info *pinfo,
 				struct mdss_panel_data *pdata);
 void mdss_dsi_op_mode_config(int mode,
 				struct mdss_panel_data *pdata);
 void mdss_dsi_cmd_mode_ctrl(int enable);
 void mdp4_dsi_cmd_trigger(void);
-void mdss_dsi_cmd_mdp_start(struct mdss_panel_data *pdata);
+void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
 void mdss_dsi_ack_err_status(unsigned char *dsi_base);
-void mdss_dsi_clk_enable(struct mdss_panel_data *pdata);
-void mdss_dsi_clk_disable(struct mdss_panel_data *pdata);
+void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl,
+				int enable);
 void mdss_dsi_controller_cfg(int enable,
 				struct mdss_panel_data *pdata);
 void mdss_dsi_sw_reset(struct mdss_panel_data *pdata);
@@ -355,4 +416,13 @@
 void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
 void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl);
 
+void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
+				struct dcs_cmd_req *cmdreq);
+struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cmdlist_kickoff(int intf);
+
 #endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 3c0dfc2..6b210af 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -25,12 +25,11 @@
 #include "mdss.h"
 #include "mdss_dsi.h"
 
-static struct completion dsi_dma_comp;
-static spinlock_t dsi_irq_lock;
-static spinlock_t dsi_mdp_lock;
-static int dsi_mdp_busy;
 static struct mdss_dsi_ctrl_pdata *left_ctrl_pdata;
 
+static struct mdss_dsi_ctrl_pdata *ctrl_list[DSI_CTRL_MAX];
+
+
 struct mdss_hw mdss_dsi0_hw = {
 	.hw_ndx = MDSS_HW_DSI0,
 	.ptr = NULL,
@@ -43,58 +42,128 @@
 	.irq_handler = mdss_dsi_isr,
 };
 
-void mdss_dsi_init(void)
+void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl)
 {
-	init_completion(&dsi_dma_comp);
-	spin_lock_init(&dsi_irq_lock);
-	spin_lock_init(&dsi_mdp_lock);
-}
-
-void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl)
-{
-	int ret;
-
 	if (ctrl->panel_data.panel_info.pdest == DISPLAY_1) {
 		mdss_dsi0_hw.ptr = (void *)(ctrl);
-		ctrl->mdss_hw = &mdss_dsi0_hw;
+		ctrl->dsi_hw = &mdss_dsi0_hw;
+		ctrl->ndx = DSI_CTRL_0;
 	} else {
 		mdss_dsi1_hw.ptr = (void *)(ctrl);
-		ctrl->mdss_hw = &mdss_dsi1_hw;
+		ctrl->dsi_hw = &mdss_dsi1_hw;
+		ctrl->ndx = DSI_CTRL_1;
 	}
 
-	ret = mdss_register_irq(ctrl->mdss_hw);
-	if (ret)
+	ctrl_list[ctrl->ndx] = ctrl;	/* keep it */
+
+	if (mdss_register_irq(ctrl->dsi_hw))
 		pr_err("%s: mdss_register_irq failed.\n", __func__);
+
+	pr_debug("%s: ndx=%d base=%p\n", __func__, ctrl->ndx, ctrl->ctrl_base);
+
+	init_completion(&ctrl->dma_comp);
+	init_completion(&ctrl->mdp_comp);
+	init_completion(&ctrl->video_comp);
+	spin_lock_init(&ctrl->irq_lock);
+	spin_lock_init(&ctrl->mdp_lock);
+	mutex_init(&ctrl->mutex);
+	mutex_init(&ctrl->cmd_mutex);
+	mdss_dsi_buf_alloc(&ctrl->tx_buf, SZ_4K);
+	mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K);
 }
 
-void mdss_dsi_irq_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable, int isr)
+/*
+ * acquire ctrl->mutex first
+ */
+void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
 {
-	unsigned long flags;
-
-	if (ctrl == NULL) {
-		pr_err("%s: Invalid ctrl\n", __func__);
-		return;
-	}
-
-	spin_lock_irqsave(&dsi_irq_lock, flags);
+	mutex_lock(&ctrl->mutex);
 	if (enable) {
-		if (ctrl->irq_cnt == 0)
-			mdss_enable_irq(ctrl->mdss_hw);
-		ctrl->irq_cnt++;
+		if (ctrl->clk_cnt == 0) {
+			mdss_dsi_prepare_clocks(ctrl);
+			mdss_dsi_clk_enable(ctrl);
+		}
+		ctrl->clk_cnt++;
 	} else {
-		if (ctrl->irq_cnt) {
-			ctrl->irq_cnt--;
-			if (ctrl->irq_cnt == 0) {
-				if (isr)
-					mdss_disable_irq_nosync(ctrl->mdss_hw);
-				else
-					mdss_disable_irq(ctrl->mdss_hw);
+		if (ctrl->clk_cnt) {
+			ctrl->clk_cnt--;
+			if (ctrl->clk_cnt == 0) {
+				mdss_dsi_clk_disable(ctrl);
+				mdss_dsi_unprepare_clocks(ctrl);
 			}
 		}
 	}
-	pr_debug("%s: ctrl=%d enable=%d cnt=%d\n", __func__,
-					ctrl->ndx, enable, ctrl->irq_cnt);
-	spin_unlock_irqrestore(&dsi_irq_lock, flags);
+	pr_debug("%s: ctrl ndx=%d enabled=%d clk_cnt=%d\n",
+			__func__, ctrl->ndx, enable, ctrl->clk_cnt);
+	mutex_unlock(&ctrl->mutex);
+}
+
+void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+{
+	if (enable == 0) {
+		/* need wait before disable */
+		mutex_lock(&ctrl->cmd_mutex);
+		mdss_dsi_cmd_mdp_busy(ctrl);
+		mutex_unlock(&ctrl->cmd_mutex);
+	}
+
+	mdss_dsi_clk_ctrl(ctrl, enable);
+}
+
+void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctrl->irq_lock, flags);
+	if (ctrl->dsi_irq_mask & term) {
+		spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+		return;
+	}
+	if (ctrl->dsi_irq_mask == 0) {
+		mdss_enable_irq(ctrl->dsi_hw);
+		pr_debug("%s: IRQ Enable, ndx=%d mask=%x term=%x\n", __func__,
+			ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+	}
+	ctrl->dsi_irq_mask |= term;
+	spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+}
+
+void mdss_dsi_disable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctrl->irq_lock, flags);
+	if (!(ctrl->dsi_irq_mask & term)) {
+		spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+		return;
+	}
+	ctrl->dsi_irq_mask &= ~term;
+	if (ctrl->dsi_irq_mask == 0) {
+		mdss_disable_irq(ctrl->dsi_hw);
+		pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__,
+			ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+	}
+	spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+}
+
+/*
+ * mdss_dsi_disale_irq_nosync() should be called
+ * from interrupt context
+ */
+void mdss_dsi_disable_irq_nosync(struct mdss_dsi_ctrl_pdata *ctrl, u32 term)
+{
+	spin_lock(&ctrl->irq_lock);
+	if (!(ctrl->dsi_irq_mask & term)) {
+		spin_unlock(&ctrl->irq_lock);
+		return;
+	}
+	ctrl->dsi_irq_mask &= ~term;
+	if (ctrl->dsi_irq_mask == 0) {
+		mdss_disable_irq_nosync(ctrl->dsi_hw);
+		pr_debug("%s: IRQ Disable, ndx=%d mask=%x term=%x\n", __func__,
+			ctrl->ndx, (int)ctrl->dsi_irq_mask, (int)term);
+	}
+	spin_unlock(&ctrl->irq_lock);
 }
 
 /*
@@ -165,18 +234,20 @@
  */
 static int mdss_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	char *bp;
 	u32 *hp;
 	int i, len;
 
+	dchdr = &cm->dchdr;
 	bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 
 	/* fill up payload */
 	if (cm->payload) {
-		len = cm->dlen;
+		len = dchdr->dlen;
 		len += 3;
 		len &= ~0x03;	/* multipled by 4 */
-		for (i = 0; i < cm->dlen; i++)
+		for (i = 0; i < dchdr->dlen; i++)
 			*bp++ = cm->payload[i];
 
 		/* append 0xff to the end */
@@ -189,11 +260,11 @@
 	/* fill up header */
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp = DSI_HDR_WC(dchdr->dlen);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_LONG_PKT;
 	*hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -206,10 +277,12 @@
  */
 static int mdss_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 	int len;
 
-	if (cm->dlen && cm->payload == 0) {
+	dchdr = &cm->dchdr;
+	if (dchdr->dlen && cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return 0;
 	}
@@ -217,12 +290,12 @@
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->last)
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 
-	len = (cm->dlen > 2) ? 2 : cm->dlen;
+	len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
 
 	if (len == 1) {
 		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1);
@@ -248,10 +321,12 @@
  */
 static int mdss_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 	int len;
 
-	if (cm->dlen && cm->payload == 0) {
+	dchdr = &cm->dchdr;
+	if (dchdr->dlen && cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return 0;
 	}
@@ -259,12 +334,12 @@
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
-	len = (cm->dlen > 2) ? 2 : cm->dlen;
+	len = (dchdr->dlen > 2) ? 2 : dchdr->dlen;
 
 	if (len == 1) {
 		*hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1);
@@ -289,10 +364,12 @@
  */
 static int mdss_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	char *bp;
 	u32 *hp;
 	int i, len;
 
+	dchdr = &cm->dchdr;
 	bp = mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 
 	/*
@@ -300,10 +377,10 @@
 	 * dcs command byte (first byte) followed by payload
 	 */
 	if (cm->payload) {
-		len = cm->dlen;
+		len = dchdr->dlen;
 		len += 3;
 		len &= ~0x03;	/* multipled by 4 */
-		for (i = 0; i < cm->dlen; i++)
+		for (i = 0; i < dchdr->dlen; i++)
 			*bp++ = cm->payload[i];
 
 		/* append 0xff to the end */
@@ -316,11 +393,11 @@
 	/* fill up header */
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp = DSI_HDR_WC(dchdr->dlen);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_LONG_PKT;
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -333,9 +410,11 @@
  */
 static int mdss_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 	int len;
 
+	dchdr = &cm->dchdr;
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return -EINVAL;
@@ -344,13 +423,13 @@
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->ack)		/* ask ACK trigger msg from peripeheral */
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->ack)		/* ask ACK trigger msg from peripeheral */
 		*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
-	len = (cm->dlen > 1) ? 1 : cm->dlen;
+	len = (dchdr->dlen > 1) ? 1 : dchdr->dlen;
 
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE);
 	*hp |= DSI_HDR_DATA1(cm->payload[0]);	/* dcs command byte */
@@ -365,9 +444,11 @@
  */
 static int mdss_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
-	if (cm->dlen < 2 || cm->payload == 0) {
+	dchdr = &cm->dchdr;
+	if (dchdr->dlen < 2 || cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return -EINVAL;
 	}
@@ -375,10 +456,10 @@
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
-	if (cm->ack)		/* ask ACK trigger msg from peripeheral */
+	*hp |= DSI_HDR_VC(dchdr->vc);
+	if (dchdr->ack)		/* ask ACK trigger msg from peripeheral */
 		*hp |= DSI_HDR_BTA;
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1);
@@ -395,8 +476,10 @@
 
 static int mdss_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
+	dchdr = &cm->dchdr;
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return -EINVAL;
@@ -405,10 +488,10 @@
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_BTA;
 	*hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DATA1(cm->payload[0]);	/* dcs command byte */
@@ -421,14 +504,16 @@
 
 static int mdss_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
+	dchdr = &cm->dchdr;
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_CM_ON);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -438,14 +523,16 @@
 
 static int mdss_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
+	dchdr = &cm->dchdr;
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -455,14 +542,16 @@
 
 static int mdss_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
+	dchdr = &cm->dchdr;
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -472,14 +561,16 @@
 
 static int mdss_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
+	dchdr = &cm->dchdr;
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -489,8 +580,10 @@
 
 static int mdss_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
+	dchdr = &cm->dchdr;
 	if (cm->payload == 0) {
 		pr_err("%s: NO payload error\n", __func__);
 		return 0;
@@ -499,9 +592,9 @@
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	*hp |= DSI_HDR_DATA1(cm->payload[0]);
@@ -514,16 +607,18 @@
 
 static int mdss_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
+	dchdr = &cm->dchdr;
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
+	*hp = DSI_HDR_WC(dchdr->dlen);
 	*hp |= DSI_HDR_LONG_PKT;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -533,16 +628,18 @@
 
 static int mdss_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	u32 *hp;
 
+	dchdr = &cm->dchdr;
 	mdss_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE);
 	hp = dp->hdr;
 	*hp = 0;
-	*hp = DSI_HDR_WC(cm->dlen);
+	*hp = DSI_HDR_WC(dchdr->dlen);
 	*hp |= DSI_HDR_LONG_PKT;
-	*hp |= DSI_HDR_VC(cm->vc);
+	*hp |= DSI_HDR_VC(dchdr->vc);
 	*hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT);
-	if (cm->last)
+	if (dchdr->last)
 		*hp |= DSI_HDR_LAST;
 
 	mdss_dsi_buf_push(dp, DSI_HOST_HDR_SIZE);
@@ -555,9 +652,12 @@
  */
 int mdss_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm)
 {
+	struct dsi_ctrl_hdr *dchdr;
 	int len = 0;
 
-	switch (cm->dtype) {
+	dchdr = &cm->dchdr;
+
+	switch (dchdr->dtype) {
 	case DTYPE_GEN_WRITE:
 	case DTYPE_GEN_WRITE1:
 	case DTYPE_GEN_WRITE2:
@@ -606,7 +706,7 @@
 		break;
 	default:
 		pr_debug("%s: dtype=%x NOT supported\n",
-					__func__, cm->dtype);
+					__func__, dchdr->dtype);
 		break;
 
 	}
@@ -820,7 +920,7 @@
 	wmb();
 }
 
-void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
+void mdss_set_tx_power_mode(int mode, struct mdss_panel_data *pdata)
 {
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	u32 data;
@@ -1034,94 +1134,84 @@
 	return 4;
 }
 
+
+static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+					struct dsi_buf *tp);
+
+static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+			struct dsi_buf *rp, int rlen);
 /*
  * mdss_dsi_cmds_tx:
- * ov_mutex need to be acquired before call this function.
+ * thread context only
  */
-int mdss_dsi_cmds_tx(struct mdss_panel_data *pdata,
-		struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt)
+int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+		struct dsi_cmd_desc *cmds, int cnt)
 {
+	struct dsi_buf *tp;
 	struct dsi_cmd_desc *cm;
-	u32 dsi_ctrl, ctrl;
+	struct dsi_ctrl_hdr *dchdr;
+	u32 dsi_ctrl, data;
 	int i, video_mode;
-	unsigned long flag;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return -EINVAL;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
-
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
-		if (pdata->panel_info.pdest == DISPLAY_1) {
+	if (ctrl->shared_pdata.broadcast_enable) {
+		if (ctrl->ndx == DSI_CTRL_0) {
 			pr_debug("%s: Broadcast mode. 1st ctrl\n",
 				 __func__);
 			return 0;
 		}
+	}
+
+	if (ctrl->shared_pdata.broadcast_enable) {
+		if ((ctrl->ndx == DSI_CTRL_1)
+		  && (left_ctrl_pdata != NULL)) {
+			dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
+								+ 0x0004);
+			video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
+			if (video_mode) {
+				data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+				MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
+						data);
+			}
+		}
+	}
 
 	/* turn on cmd mode
 	* for video mode, do not send cmds more than
 	* one pixel line, since it only transmit it
 	* during BLLP.
 	*/
-
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
-		if ((pdata->panel_info.pdest == DISPLAY_2)
-		  && (left_ctrl_pdata != NULL)) {
-			dsi_ctrl = MIPI_INP(left_ctrl_pdata->ctrl_base
-								+ 0x0004);
-			video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
-			if (video_mode) {
-				ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
-				MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0004,
-						ctrl);
-			}
-		}
-
-	dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004);
+	dsi_ctrl = MIPI_INP((ctrl->ctrl_base) + 0x0004);
 	video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */
 	if (video_mode) {
-		ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, ctrl);
+		data = dsi_ctrl | 0x04; /* CMD_MODE_EN */
+		MIPI_OUTP((ctrl->ctrl_base) + 0x0004, data);
 	}
 
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
-
-	dsi_mdp_busy = true;
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
+	tp = &ctrl->tx_buf;
 	cm = cmds;
-	mdss_dsi_buf_init(tp);
 	for (i = 0; i < cnt; i++) {
+		mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 		mdss_dsi_buf_init(tp);
 		mdss_dsi_cmd_dma_add(tp, cm);
-		mdss_dsi_cmd_dma_tx(tp, pdata);
-		if (cm->wait)
-			msleep(cm->wait);
+		mdss_dsi_cmd_dma_tx(ctrl, tp);
+		dchdr = &cm->dchdr;
+		if (dchdr->wait)
+			usleep(dchdr->wait * 1000);
 		cm++;
 	}
 
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	dsi_mdp_busy = false;
-	mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
 	if (video_mode)
-		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+		MIPI_OUTP((ctrl->ctrl_base) + 0x0004,
 					dsi_ctrl); /* restore */
 	return cnt;
 }
 
-/* MDSS_DSI_MRPS, Maximum Return Packet Size */
+/* MIPI_DSI_MRPS, Maximum Return Packet Size */
 static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */
 
-static struct dsi_cmd_desc pkt_size_cmd[] = {
-	{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0,
-		sizeof(max_pktsize), max_pktsize}
+static struct dsi_cmd_desc pkt_size_cmd = {
+	{DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, sizeof(max_pktsize)},
+	max_pktsize,
 };
 
 /*
@@ -1129,31 +1219,24 @@
  * plus DCS header, ECC and CRC for DCS long read response
  * mdss_dsi_controller only have 4x32 bits register ( 16 bytes) to
  * hold data per transaction.
- * MDSS_DSI_LEN equal to 8
+ * MIPI_DSI_LEN equal to 8
  * len should be either 4 or 8
- * any return data more than MDSS_DSI_LEN need to be break down
+ * any return data more than MIPI_DSI_LEN need to be break down
  * to multiple transactions.
  *
  * ov_mutex need to be acquired before call this function.
  */
-int mdss_dsi_cmds_rx(struct mdss_panel_data *pdata,
-			struct dsi_buf *tp, struct dsi_buf *rp,
-			struct dsi_cmd_desc *cmds, int rlen)
+
+int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+			struct dsi_cmd_desc *cmds, int rlen, u32 rx_flags)
 {
 	int cnt, len, diff, pkt_size;
-	unsigned long flag;
+	struct dsi_buf *tp, *rp;
+	int no_max_pkt_size;
 	char cmd;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return -EINVAL;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
-
-	if (pdata->panel_info.mipi.no_max_pkt_size)
+	no_max_pkt_size = rx_flags & CMD_REQ_NO_MAX_PKT_SIZE;
+	if (no_max_pkt_size)
 		rlen = ALIGN(rlen, 4); /* Only support rlen = 4*n */
 
 	len = rlen;
@@ -1178,33 +1261,33 @@
 		cnt = len + 6; /* 4 bytes header + 2 bytes crc */
 	}
 
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	mdss_dsi_irq_ctrl(ctrl_pdata, 1, 0);
-	dsi_mdp_busy = true;
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
+	tp = &ctrl->tx_buf;
+	rp = &ctrl->rx_buf;
 
-	if (!pdata->panel_info.mipi.no_max_pkt_size) {
+	if (!no_max_pkt_size) {
 		/* packet size need to be set at every read */
 		pkt_size = len;
 		max_pktsize[0] = pkt_size;
+		mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 		mdss_dsi_buf_init(tp);
-		mdss_dsi_cmd_dma_add(tp, pkt_size_cmd);
-		mdss_dsi_cmd_dma_tx(tp, pdata);
+		mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd);
+		mdss_dsi_cmd_dma_tx(ctrl, tp);
 		pr_debug("%s: Max packet size sent\n", __func__);
 	}
 
+	mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM);
 	mdss_dsi_buf_init(tp);
 	mdss_dsi_cmd_dma_add(tp, cmds);
 
 	/* transmit read comamnd to client */
-	mdss_dsi_cmd_dma_tx(tp, pdata);
+	mdss_dsi_cmd_dma_tx(ctrl, tp);
 	/*
 	 * once cmd_dma_done interrupt received,
 	 * return data from client is ready and stored
 	 * at RDBK_DATA register already
 	 */
 	mdss_dsi_buf_init(rp);
-	if (pdata->panel_info.mipi.no_max_pkt_size) {
+	if (no_max_pkt_size) {
 		/*
 		 * expect rlen = n * 4
 		 * short alignement for start addr
@@ -1212,14 +1295,9 @@
 		rp->data += 2;
 	}
 
-	mdss_dsi_cmd_dma_rx(rp, cnt, pdata);
+	mdss_dsi_cmd_dma_rx(ctrl, rp, cnt);
 
-	spin_lock_irqsave(&dsi_mdp_lock, flag);
-	dsi_mdp_busy = false;
-	mdss_dsi_irq_ctrl(ctrl_pdata, 0, 0);
-	spin_unlock_irqrestore(&dsi_mdp_lock, flag);
-
-	if (pdata->panel_info.mipi.no_max_pkt_size) {
+	if (no_max_pkt_size) {
 		/*
 		 * remove extra 2 bytes from previous
 		 * rx transaction at shift register
@@ -1257,22 +1335,16 @@
 	return rp->len;
 }
 
-int mdss_dsi_cmd_dma_tx(struct dsi_buf *tp,
-			struct mdss_panel_data *pdata)
+#define DMA_TX_TIMEOUT 200
+
+static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+					struct dsi_buf *tp)
 {
 	int len;
 	int domain = MDSS_IOMMU_DOMAIN_UNSECURE;
 	char *bp;
 	unsigned long size, addr;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return -EINVAL;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
 	bp = tp->data;
 
 	len = ALIGN(tp->len, 4);
@@ -1296,29 +1368,32 @@
 		addr = tp->dmap;
 	}
 
-	INIT_COMPLETION(dsi_dma_comp);
+	INIT_COMPLETION(ctrl->dma_comp);
 
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
-		if ((pdata->panel_info.pdest == DISPLAY_2)
+	if (ctrl->shared_pdata.broadcast_enable)
+		if ((ctrl->ndx == DSI_CTRL_1)
 		  && (left_ctrl_pdata != NULL)) {
 			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x048, addr);
 			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x04c, len);
 		}
 
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x048, addr);
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x04c, len);
+	MIPI_OUTP((ctrl->ctrl_base) + 0x048, addr);
+	MIPI_OUTP((ctrl->ctrl_base) + 0x04c, len);
 	wmb();
 
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
-		if ((pdata->panel_info.pdest == DISPLAY_2)
+	if (ctrl->shared_pdata.broadcast_enable)
+		if ((ctrl->ndx == DSI_CTRL_1)
 		  && (left_ctrl_pdata != NULL)) {
 			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x090, 0x01);
 		}
 
-	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x090, 0x01);	/* trigger */
+	MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01);	/* trigger */
 	wmb();
 
-	wait_for_completion(&dsi_dma_comp);
+	if (!wait_for_completion_timeout(&ctrl->dma_comp,
+				msecs_to_jiffies(DMA_TX_TIMEOUT))) {
+		pr_err("%s: dma timeout error\n", __func__);
+	}
 
 	if (is_mdss_iommu_attached())
 		msm_iommu_unmap_contig_buffer(addr,
@@ -1329,20 +1404,13 @@
 	return tp->len;
 }
 
-int mdss_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen,
-			struct mdss_panel_data *pdata)
+static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+			struct dsi_buf *rp, int rlen)
+
 {
 	u32 *lp, data;
 	int i, off, cnt;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 
-	if (pdata == NULL) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return -EINVAL;
-	}
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
 	lp = (u32 *)rp->data;
 	cnt = rlen;
 	cnt += 3;
@@ -1354,106 +1422,289 @@
 	off = 0x06c;	/* DSI_RDBK_DATA0 */
 	off += ((cnt - 1) * 4);
 
-
 	for (i = 0; i < cnt; i++) {
-		data = (u32)MIPI_INP((ctrl_pdata->ctrl_base) + off);
+		data = (u32)MIPI_INP((ctrl->ctrl_base) + off);
 		*lp++ = ntohl(data);	/* to network byte order */
 		pr_debug("%s: data = 0x%x and ntohl(data) = 0x%x\n",
 					 __func__, data, ntohl(data));
 		off -= 4;
 		rp->len += sizeof(*lp);
 	}
-
 	return rlen;
 }
 
-void mdss_dsi_ack_err_status(unsigned char *dsi_base)
+#define VSYNC_PERIOD 17
+
+void mdss_dsi_wait4video_done(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&ctrl->mdp_lock, flag);
+	INIT_COMPLETION(ctrl->video_comp);
+	mdss_dsi_enable_irq(ctrl, DSI_VIDEO_TERM);
+	spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+
+	wait_for_completion_timeout(&ctrl->video_comp,
+			msecs_to_jiffies(VSYNC_PERIOD * 4));
+}
+
+static void mdss_dsi_wait4video_eng_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	mdss_dsi_wait4video_done(ctrl);
+	/* delay 4 ms to skip BLLP */
+	usleep(4000);
+}
+
+void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	unsigned long flag;
+
+	spin_lock_irqsave(&ctrl->mdp_lock, flag);
+	mdss_dsi_enable_irq(ctrl, DSI_MDP_TERM);
+	ctrl->mdp_busy = true;
+	INIT_COMPLETION(ctrl->mdp_comp);
+	spin_unlock_irqrestore(&ctrl->mdp_lock, flag);
+}
+
+void mdss_dsi_cmd_mdp_busy(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	unsigned long flags;
+	int need_wait = 0;
+
+	pr_debug("%s: start pid=%d\n",
+				__func__, current->pid);
+	spin_lock_irqsave(&ctrl->mdp_lock, flags);
+	if (ctrl->mdp_busy == true)
+		need_wait++;
+	spin_unlock_irqrestore(&ctrl->mdp_lock, flags);
+
+	if (need_wait) {
+		/* wait until DMA finishes the current job */
+		pr_debug("%s: pending pid=%d\n",
+				__func__, current->pid);
+		wait_for_completion(&ctrl->mdp_comp);
+	}
+	pr_debug("%s: done pid=%d\n",
+				__func__, current->pid);
+}
+
+void mdss_dsi_cmdlist_tx(struct mdss_dsi_ctrl_pdata *ctrl,
+				struct dcs_cmd_req *req)
+{
+	int ret;
+
+	ret = mdss_dsi_cmds_tx(ctrl, req->cmds, req->cmds_cnt);
+
+	if (req->cb)
+		req->cb(ret);
+
+}
+
+void mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
+				struct dcs_cmd_req *req)
+{
+	int len;
+	u32 data, *dp;
+	struct dsi_buf *rp;
+
+	len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen, req->flags);
+	rp = &ctrl->rx_buf;
+	dp = (u32 *)rp->data;
+	data = *dp;
+
+	if (req->cb)
+		req->cb(data);
+}
+
+void mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp)
+{
+	struct dcs_cmd_req *req;
+	u32 data;
+
+	mutex_lock(&ctrl->cmd_mutex);
+	req = mdss_dsi_cmdlist_get(ctrl);
+
+	/* make sure dsi_cmd_mdp is idle */
+	mdss_dsi_cmd_mdp_busy(ctrl);
+
+	if (req == NULL)
+		goto need_lock;
+
+	pr_debug("%s:  from_mdp=%d pid=%d\n", __func__, from_mdp, current->pid);
+	mdss_dsi_clk_ctrl(ctrl, 1);
+
+	data = MIPI_INP((ctrl->ctrl_base) + 0x0004);
+	if (data & 0x02) {
+		/* video mode, make sure video engine is busy
+		 * so dcs command will be sent at start of BLLP
+		 */
+		mdss_dsi_wait4video_eng_busy(ctrl);
+	} else {
+		/* command mode */
+		if (!from_mdp) { /* cmdlist_put */
+			/* make sure dsi_cmd_mdp is idle */
+			mdss_dsi_cmd_mdp_busy(ctrl);
+		}
+	}
+
+	if (req->flags & CMD_REQ_RX)
+		mdss_dsi_cmdlist_rx(ctrl, req);
+	else
+		mdss_dsi_cmdlist_tx(ctrl, req);
+
+	mdss_dsi_clk_ctrl(ctrl, 0);
+
+need_lock:
+
+	if (from_mdp) /* from pipe_commit */
+		mdss_dsi_cmd_mdp_start(ctrl);
+
+	mutex_unlock(&ctrl->cmd_mutex);
+}
+
+/*
+ * mdss_dsi_cmd_get: ctrl->cmd_mutex acquired by caller
+ */
+struct dcs_cmd_req *mdss_dsi_cmdlist_get(struct mdss_dsi_ctrl_pdata *ctrl)
+{
+	struct dcs_cmd_list *clist;
+	struct dcs_cmd_req *req = NULL;
+
+	clist = &ctrl->cmdlist;
+	if (clist->get != clist->put) {
+		req = &clist->list[clist->get];
+		clist->get++;
+		clist->get %= CMD_REQ_MAX;
+		clist->tot--;
+		pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+		clist->tot, clist->put, clist->get);
+	}
+	return req;
+}
+
+int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl,
+				struct dcs_cmd_req *cmdreq)
+{
+	struct dcs_cmd_req *req;
+	struct dcs_cmd_list *clist;
+	int ret = 0;
+
+	mutex_lock(&ctrl->cmd_mutex);
+	clist = &ctrl->cmdlist;
+	req = &clist->list[clist->put];
+	*req = *cmdreq;
+	clist->put++;
+	clist->put %= CMD_REQ_MAX;
+	clist->tot++;
+	if (clist->put == clist->get) {
+		/* drop the oldest one */
+		pr_debug("%s: DROP, tot=%d put=%d get=%d\n", __func__,
+			clist->tot, clist->put, clist->get);
+		clist->get++;
+		clist->get %= CMD_REQ_MAX;
+		clist->tot--;
+	}
+	mutex_unlock(&ctrl->cmd_mutex);
+
+	ret++;
+	pr_debug("%s: tot=%d put=%d get=%d\n", __func__,
+		clist->tot, clist->put, clist->get);
+
+	if (req->flags & CMD_REQ_COMMIT)
+		mdss_dsi_cmdlist_commit(ctrl, 0);
+
+	return ret;
+}
+
+void mdss_dsi_ack_err_status(unsigned char *base)
 {
 	u32 status;
 
-	status = MIPI_INP(dsi_base + 0x0068);/* DSI_ACK_ERR_STATUS */
+	status = MIPI_INP(base + 0x0068);/* DSI_ACK_ERR_STATUS */
 
 	if (status) {
-		MIPI_OUTP(dsi_base + 0x0068, status);
+		MIPI_OUTP(base + 0x0068, status);
 		pr_debug("%s: status=%x\n", __func__, status);
 	}
 }
 
-void mdss_dsi_timeout_status(unsigned char *dsi_base)
+void mdss_dsi_timeout_status(unsigned char *base)
 {
 	u32 status;
 
-	status = MIPI_INP(dsi_base + 0x00c0);/* DSI_TIMEOUT_STATUS */
+	status = MIPI_INP(base + 0x00c0);/* DSI_TIMEOUT_STATUS */
 	if (status & 0x0111) {
-		MIPI_OUTP(dsi_base + 0x00c0, status);
+		MIPI_OUTP(base + 0x00c0, status);
 		pr_debug("%s: status=%x\n", __func__, status);
 	}
 }
 
-void mdss_dsi_dln0_phy_err(unsigned char *dsi_base)
+void mdss_dsi_dln0_phy_err(unsigned char *base)
 {
 	u32 status;
 
-	status = MIPI_INP(dsi_base + 0x00b4);/* DSI_DLN0_PHY_ERR */
+	status = MIPI_INP(base + 0x00b4);/* DSI_DLN0_PHY_ERR */
 
 	if (status & 0x011111) {
-		MIPI_OUTP(dsi_base + 0x00b4, status);
+		MIPI_OUTP(base + 0x00b4, status);
 		pr_debug("%s: status=%x\n", __func__, status);
 	}
 }
 
-void mdss_dsi_fifo_status(unsigned char *dsi_base)
+void mdss_dsi_fifo_status(unsigned char *base)
 {
 	u32 status;
 
-	status = MIPI_INP(dsi_base + 0x000c);/* DSI_FIFO_STATUS */
+	status = MIPI_INP(base + 0x000c);/* DSI_FIFO_STATUS */
 
 	if (status & 0x44444489) {
-		MIPI_OUTP(dsi_base + 0x000c, status);
+		MIPI_OUTP(base + 0x000c, status);
 		pr_debug("%s: status=%x\n", __func__, status);
 	}
 }
 
-void mdss_dsi_status(unsigned char *dsi_base)
+void mdss_dsi_status(unsigned char *base)
 {
 	u32 status;
 
-	status = MIPI_INP(dsi_base + 0x0008);/* DSI_STATUS */
+	status = MIPI_INP(base + 0x0008);/* DSI_STATUS */
 
 	if (status & 0x80000000) {
-		MIPI_OUTP(dsi_base + 0x0008, status);
+		MIPI_OUTP(base + 0x0008, status);
 		pr_debug("%s: status=%x\n", __func__, status);
 	}
 }
 
-void mdss_dsi_error(unsigned char *dsi_base)
+void mdss_dsi_error(struct mdss_dsi_ctrl_pdata *ctrl)
 {
+	unsigned char *base;
+
+	base = ctrl->ctrl_base;
+
 	/* DSI_ERR_INT_MASK0 */
-	mdss_dsi_ack_err_status(dsi_base);	/* mask0, 0x01f */
-	mdss_dsi_timeout_status(dsi_base);	/* mask0, 0x0e0 */
-	mdss_dsi_fifo_status(dsi_base);		/* mask0, 0x133d00 */
-	mdss_dsi_status(dsi_base);		/* mask0, 0xc0100 */
-	mdss_dsi_dln0_phy_err(dsi_base);	/* mask0, 0x3e00000 */
+	mdss_dsi_ack_err_status(base);	/* mask0, 0x01f */
+	mdss_dsi_timeout_status(base);	/* mask0, 0x0e0 */
+	mdss_dsi_fifo_status(base);		/* mask0, 0x133d00 */
+	mdss_dsi_status(base);		/* mask0, 0xc0100 */
+	mdss_dsi_dln0_phy_err(base);	/* mask0, 0x3e00000 */
 }
 
 
 irqreturn_t mdss_dsi_isr(int irq, void *ptr)
 {
 	u32 isr;
-	unsigned char *dsi_base;
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata =
+	struct mdss_dsi_ctrl_pdata *ctrl =
 			(struct mdss_dsi_ctrl_pdata *)ptr;
 
-	dsi_base = ctrl_pdata->ctrl_base;
-	if (!dsi_base)
+	if (!ctrl->ctrl_base)
 		pr_err("%s:%d DSI base adr no Initialized",
 				       __func__, __LINE__);
 
-	isr = MIPI_INP(dsi_base + 0x0110);/* DSI_INTR_CTRL */
-	MIPI_OUTP(dsi_base + 0x0110, isr);
+	isr = MIPI_INP(ctrl->ctrl_base + 0x0110);/* DSI_INTR_CTRL */
+	MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr);
 
-	if (ctrl_pdata->shared_pdata.broadcast_enable)
-		if ((ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_2)
+	if (ctrl->shared_pdata.broadcast_enable)
+		if ((ctrl->panel_data.panel_info.pdest == DISPLAY_2)
 		    && (left_ctrl_pdata != NULL)) {
 			u32 isr0;
 			isr0 = MIPI_INP(left_ctrl_pdata->ctrl_base
@@ -1461,24 +1712,38 @@
 			MIPI_OUTP(left_ctrl_pdata->ctrl_base + 0x0110, isr0);
 		}
 
-	pr_debug("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+	pr_debug("%s: isr=%x", __func__, isr);
 
-	if (isr & DSI_INTR_ERROR)
-		mdss_dsi_error(dsi_base);
-
-	if (isr & DSI_INTR_VIDEO_DONE) {
-		/*
-		* do something  here
-		*/
+	if (isr & DSI_INTR_ERROR) {
+		pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR);
+		spin_lock(&ctrl->mdp_lock);
+		ctrl->mdp_busy = false;
+		mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
+		complete(&ctrl->mdp_comp);
+		mdss_dsi_error(ctrl);
+		spin_unlock(&ctrl->mdp_lock);
 	}
 
-	if (isr & DSI_INTR_CMD_DMA_DONE)
-		complete(&dsi_dma_comp);
+	if (isr & DSI_INTR_VIDEO_DONE) {
+		spin_lock(&ctrl->mdp_lock);
+		mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM);
+		complete(&ctrl->video_comp);
+		spin_unlock(&ctrl->mdp_lock);
+	}
+
+	if (isr & DSI_INTR_CMD_DMA_DONE) {
+		spin_lock(&ctrl->mdp_lock);
+		mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM);
+		complete(&ctrl->dma_comp);
+		spin_unlock(&ctrl->mdp_lock);
+	}
 
 	if (isr & DSI_INTR_CMD_MDP_DONE) {
-		spin_lock(&dsi_mdp_lock);
-		dsi_mdp_busy = false;
-		spin_unlock(&dsi_mdp_lock);
+		spin_lock(&ctrl->mdp_lock);
+		ctrl->mdp_busy = false;
+		mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
+		complete(&ctrl->mdp_comp);
+		spin_unlock(&ctrl->mdp_lock);
 	}
 
 	return IRQ_HANDLED;
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index c56cd41..6b0f68e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -26,9 +26,6 @@
 
 #define DT_CMD_HDR 6
 
-static struct dsi_buf dsi_panel_tx_buf;
-static struct dsi_buf dsi_panel_rx_buf;
-
 DEFINE_LED_TRIGGER(bl_led_trigger);
 
 static struct mdss_dsi_phy_ctrl phy_params;
@@ -37,16 +34,18 @@
 {
 	int ret;
 
-	if (!gpio_is_valid(ctrl->pwm_gpio)) {
-		pr_err("%s: pwm_gpio=%d Invalid\n", __func__,
-				ctrl->pwm_gpio);
+	if (!gpio_is_valid(ctrl->pwm_pmic_gpio)) {
+		pr_err("%s: pwm_pmic_gpio=%d Invalid\n", __func__,
+				ctrl->pwm_pmic_gpio);
+		ctrl->pwm_pmic_gpio = -1;
 		return;
 	}
 
-	ret = gpio_request(ctrl->pwm_gpio, "disp_pwm");
+	ret = gpio_request(ctrl->pwm_pmic_gpio, "disp_pwm");
 	if (ret) {
-		pr_err("%s: pwm_gpio=%d request failed\n", __func__,
-				ctrl->pwm_gpio);
+		pr_err("%s: pwm_pmic_gpio=%d request failed\n", __func__,
+				ctrl->pwm_pmic_gpio);
+		ctrl->pwm_pmic_gpio = -1;
 		return;
 	}
 
@@ -54,8 +53,8 @@
 	if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) {
 		pr_err("%s: lpg_chan=%d pwm request failed", __func__,
 				ctrl->pwm_lpg_chan);
-		gpio_free(ctrl->pwm_gpio);
-		ctrl->pwm_gpio = -1;
+		gpio_free(ctrl->pwm_pmic_gpio);
+		ctrl->pwm_pmic_gpio = -1;
 	}
 }
 
@@ -74,7 +73,7 @@
 
 	pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n",
 			__func__, ctrl->bklt_ctrl, ctrl->pwm_period,
-				ctrl->pwm_gpio, ctrl->pwm_lpg_chan);
+				ctrl->pwm_pmic_gpio, ctrl->pwm_lpg_chan);
 
 	pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__,
 					ctrl->ndx, level, duty);
@@ -90,6 +89,71 @@
 		pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret);
 }
 
+static char dcs_cmd[2] = {0x54, 0x00}; /* DTYPE_DCS_READ */
+static struct dsi_cmd_desc dcs_read_cmd = {
+	{DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(dcs_cmd)},
+	dcs_cmd
+};
+
+u32 mdss_dsi_dcs_read(struct mdss_dsi_ctrl_pdata *ctrl,
+			char cmd0, char cmd1)
+{
+	struct dcs_cmd_req cmdreq;
+
+	dcs_cmd[0] = cmd0;
+	dcs_cmd[1] = cmd1;
+	memset(&cmdreq, 0, sizeof(cmdreq));
+	cmdreq.cmds = &dcs_read_cmd;
+	cmdreq.cmds_cnt = 1;
+	cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT;
+	cmdreq.rlen = 1;
+	cmdreq.cb = NULL; /* call back */
+	mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+	/*
+	 * blocked here, until call back called
+	 */
+
+	return 0;
+}
+
+static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
+			struct dsi_panel_cmds *pcmds)
+{
+	struct dcs_cmd_req cmdreq;
+
+	memset(&cmdreq, 0, sizeof(cmdreq));
+	cmdreq.cmds = pcmds->cmds;
+	cmdreq.cmds_cnt = pcmds->cmd_cnt;
+	cmdreq.flags = CMD_REQ_COMMIT;
+	cmdreq.rlen = 0;
+	cmdreq.cb = NULL;
+
+	mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
+
+static char led_pwm1[2] = {0x51, 0x0};	/* DTYPE_DCS_WRITE1 */
+static struct dsi_cmd_desc backlight_cmd = {
+	{DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1)},
+	led_pwm1
+};
+
+static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level)
+{
+	struct dcs_cmd_req cmdreq;
+
+	pr_debug("%s: level=%d\n", __func__, level);
+
+	led_pwm1[1] = (unsigned char)level;
+
+	memset(&cmdreq, 0, sizeof(cmdreq));
+	cmdreq.cmds = &backlight_cmd;
+	cmdreq.cmds_cnt = 1;
+	cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL;
+	cmdreq.rlen = 0;
+	cmdreq.cb = NULL;
+
+	mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+}
 
 void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
 {
@@ -152,6 +216,9 @@
 	case BL_PWM:
 		mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level);
 		break;
+	case BL_DCS_CMD:
+		mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level);
+		break;
 	default:
 		pr_err("%s: Unknown bl_ctrl configuration\n",
 			__func__);
@@ -159,14 +226,6 @@
 	}
 }
 
-static char set_tear_on[2] = {0x35, 0x00};
-static struct dsi_cmd_desc dsi_tear_on_cmd = {
-	DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on};
-
-static char set_tear_off[2] = {0x34, 0x00};
-static struct dsi_cmd_desc dsi_tear_off_cmd = {
-	DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off};
-
 static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
 {
 	struct mipi_panel_info *mipi;
@@ -183,14 +242,10 @@
 
 	pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
 
-	if (ctrl->on_cmds->size)
-		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
-				 ctrl->on_cmds->buf,
-				 ctrl->on_cmds->size);
+	if (ctrl->on_cmds.cmd_cnt)
+		mdss_dsi_panel_cmds_send(ctrl, &ctrl->on_cmds);
 
-	mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
-			&dsi_tear_on_cmd, 1);
-
+	pr_debug("%s:-\n", __func__);
 	return 0;
 }
 
@@ -211,17 +266,95 @@
 
 	mipi  = &pdata->panel_info.mipi;
 
-	mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
-			&dsi_tear_off_cmd, 1);
+	if (ctrl->off_cmds.cmd_cnt)
+		mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds);
 
-	if (ctrl->off_cmds->size)
-		mdss_dsi_cmds_tx(pdata, &dsi_panel_tx_buf,
-				 ctrl->off_cmds->buf,
-				 ctrl->off_cmds->size);
+	pr_debug("%s:-\n", __func__);
+	return 0;
+}
+
+
+static int mdss_dsi_parse_dcs_cmds(struct device_node *np,
+		struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key)
+{
+	const char *data;
+	int blen = 0, len;
+	char *buf, *bp;
+	struct dsi_ctrl_hdr *dchdr;
+	int i, cnt;
+
+	data = of_get_property(np, cmd_key, &blen);
+	if (!data) {
+		pr_err("%s: failed, key=%s\n", __func__, cmd_key);
+		return -ENOMEM;
+	}
+
+	buf = kzalloc(sizeof(char) * blen, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	memcpy(buf, data, blen);
+
+	/* scan dcs commands */
+	bp = buf;
+	len = blen;
+	cnt = 0;
+	while (len > sizeof(*dchdr)) {
+		dchdr = (struct dsi_ctrl_hdr *)bp;
+		dchdr->dlen = ntohs(dchdr->dlen);
+		if (dchdr->dlen > len) {
+			pr_err("%s: dtsi cmd=%x error, len=%d",
+				__func__, dchdr->dtype, dchdr->dlen);
+			return -ENOMEM;
+		}
+		bp += sizeof(*dchdr);
+		len -= sizeof(*dchdr);
+		bp += dchdr->dlen;
+		len -= dchdr->dlen;
+		cnt++;
+	}
+
+	if (len != 0) {
+		pr_err("%s: dcs_cmd=%x len=%d error!",
+				__func__, buf[0], blen);
+		kfree(buf);
+		return -ENOMEM;
+	}
+
+	pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc),
+						GFP_KERNEL);
+	if (!pcmds->cmds)
+		return -ENOMEM;
+
+	pcmds->cmd_cnt = cnt;
+	pcmds->buf = buf;
+	pcmds->blen = blen;
+
+	bp = buf;
+	len = blen;
+	for (i = 0; i < cnt; i++) {
+		dchdr = (struct dsi_ctrl_hdr *)bp;
+		len -= sizeof(*dchdr);
+		bp += sizeof(*dchdr);
+		pcmds->cmds[i].dchdr = *dchdr;
+		pcmds->cmds[i].payload = bp;
+		bp += dchdr->dlen;
+		len -= dchdr->dlen;
+	}
+
+	pcmds->link_state = DSI_LP_MODE; /* default */
+
+	data = of_get_property(np, link_key, NULL);
+	if (!strncmp(data, "DSI_HS_MODE", 11))
+		pcmds->link_state = DSI_HS_MODE;
+
+	pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
+		pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
 
 	return 0;
 }
 
+
 static int mdss_panel_parse_dt(struct platform_device *pdev,
 			       struct mdss_panel_common_pdata *panel_data)
 {
@@ -229,12 +362,8 @@
 	u32 res[6], tmp;
 	u32 fbc_res[7];
 	int rc, i, len;
-	int cmd_plen, data_offset;
 	const char *data;
 	static const char *bl_ctrl_type, *pdest;
-	static const char *on_cmds_state, *off_cmds_state;
-	char *on_cmds = NULL, *off_cmds = NULL;
-	int num_of_on_cmds = 0, num_of_off_cmds = 0;
 	bool fbc_enabled = false;
 
 	rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2);
@@ -301,15 +430,15 @@
 	} else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) {
 		panel_data->panel_info.bklt_ctrl = BL_PWM;
 
-		rc = of_property_read_u32(np, "qcom,dsi-pwm-period", &tmp);
+		rc = of_property_read_u32(np, "qcom,pwm-period", &tmp);
 		if (rc) {
-			pr_err("%s:%d, Error, dsi pwm_period\n",
+			pr_err("%s:%d, Error, panel pwm_period\n",
 						__func__, __LINE__);
 			return -EINVAL;
 		}
 		panel_data->panel_info.pwm_period = tmp;
 
-		rc = of_property_read_u32(np, "qcom,dsi-lpg-channel", &tmp);
+		rc = of_property_read_u32(np, "qcom,pwm-lpg-channel", &tmp);
 		if (rc) {
 			pr_err("%s:%d, Error, dsi lpg channel\n",
 						__func__, __LINE__);
@@ -317,8 +446,10 @@
 		}
 		panel_data->panel_info.pwm_lpg_chan = tmp;
 
-		tmp = of_get_named_gpio(np, "qcom,dsi-pwm-gpio", 0);
-		panel_data->panel_info.pwm_gpio =  tmp;
+		tmp = of_get_named_gpio(np, "qcom,pwm-pmic-gpio", 0);
+		panel_data->panel_info.pwm_pmic_gpio =  tmp;
+	} else if (!strncmp(bl_ctrl_type, "bl_ctrl_dcs", 11)) {
+		panel_data->panel_info.bklt_ctrl = BL_DCS_CMD;
 	} else {
 		pr_debug("%s: Unknown backlight control\n", __func__);
 		panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL;
@@ -529,171 +660,15 @@
 			panel_data->panel_info.bpp;
 	}
 
-	data = of_get_property(np, "qcom,panel-on-cmds", &len);
-	if (!data) {
-		pr_err("%s:%d, Unable to read ON cmds", __func__, __LINE__);
-		goto error;
-	}
+	mdss_dsi_parse_dcs_cmds(np, &panel_data->on_cmds,
+		"qcom,panel-on-cmds", "qcom,on-cmds-dsi-state");
 
-	on_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
-	if (!on_cmds)
-		return -ENOMEM;
-
-	memcpy(on_cmds, data, len);
-
-	data_offset = 0;
-	cmd_plen = 0;
-	while ((len - data_offset) >= DT_CMD_HDR) {
-		data_offset += (DT_CMD_HDR - 1);
-		cmd_plen = on_cmds[data_offset++];
-		data_offset += cmd_plen;
-		num_of_on_cmds++;
-	}
-	if (!num_of_on_cmds) {
-		pr_err("%s:%d, No ON cmds specified", __func__, __LINE__);
-		goto error;
-	}
-
-	panel_data->dsi_panel_on_cmds =
-		kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
-	if (!panel_data->dsi_panel_on_cmds)
-		return -ENOMEM;
-
-	(panel_data->dsi_panel_on_cmds)->buf =
-		kzalloc((num_of_on_cmds * sizeof(struct dsi_cmd_desc)),
-						GFP_KERNEL);
-	if (!(panel_data->dsi_panel_on_cmds)->buf)
-		return -ENOMEM;
-
-	data_offset = 0;
-	for (i = 0; i < num_of_on_cmds; i++) {
-		panel_data->dsi_panel_on_cmds->buf[i].dtype =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].last =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].vc =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].ack =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].wait =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].dlen =
-						on_cmds[data_offset++];
-		panel_data->dsi_panel_on_cmds->buf[i].payload =
-						&on_cmds[data_offset];
-		data_offset += (panel_data->dsi_panel_on_cmds->buf[i].dlen);
-	}
-
-	if (data_offset != len) {
-		pr_err("%s:%d, Incorrect ON command entries",
-						__func__, __LINE__);
-		goto error;
-	}
-
-	(panel_data->dsi_panel_on_cmds)->size = num_of_on_cmds;
-
-	on_cmds_state = of_get_property(pdev->dev.of_node,
-				"qcom,on-cmds-dsi-state", NULL);
-	if (!strncmp(on_cmds_state, "DSI_LP_MODE", 11)) {
-		(panel_data->dsi_panel_on_cmds)->ctrl_state =
-						DSI_LP_MODE;
-	} else if (!strncmp(on_cmds_state, "DSI_HS_MODE", 11)) {
-		(panel_data->dsi_panel_on_cmds)->ctrl_state =
-						DSI_HS_MODE;
-	} else {
-		pr_debug("%s: ON cmds state not specified. Set Default\n",
-							__func__);
-		(panel_data->dsi_panel_on_cmds)->ctrl_state =
-						DSI_LP_MODE;
-	}
-
-	data = of_get_property(np, "qcom,panel-off-cmds", &len);
-	if (!data) {
-		pr_err("%s:%d, Unable to read OFF cmds", __func__, __LINE__);
-		goto error;
-	}
-
-	off_cmds = kzalloc(sizeof(char) * len, GFP_KERNEL);
-	if (!off_cmds)
-		return -ENOMEM;
-
-	memcpy(off_cmds, data, len);
-
-	data_offset = 0;
-	cmd_plen = 0;
-	while ((len - data_offset) >= DT_CMD_HDR) {
-		data_offset += (DT_CMD_HDR - 1);
-		cmd_plen = off_cmds[data_offset++];
-		data_offset += cmd_plen;
-		num_of_off_cmds++;
-	}
-	if (!num_of_off_cmds) {
-		pr_err("%s:%d, No OFF cmds specified", __func__, __LINE__);
-		goto error;
-	}
-
-	panel_data->dsi_panel_off_cmds =
-		kzalloc(sizeof(struct dsi_panel_cmds_list), GFP_KERNEL);
-	if (!panel_data->dsi_panel_off_cmds)
-		return -ENOMEM;
-
-	(panel_data->dsi_panel_off_cmds)->buf = kzalloc(num_of_off_cmds
-				* sizeof(struct dsi_cmd_desc),
-					GFP_KERNEL);
-	if (!(panel_data->dsi_panel_off_cmds)->buf)
-		return -ENOMEM;
-
-	data_offset = 0;
-	for (i = 0; i < num_of_off_cmds; i++) {
-		panel_data->dsi_panel_off_cmds->buf[i].dtype =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].last =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].vc =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].ack =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].wait =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].dlen =
-						off_cmds[data_offset++];
-		panel_data->dsi_panel_off_cmds->buf[i].payload =
-						&off_cmds[data_offset];
-		data_offset += (panel_data->dsi_panel_off_cmds->buf[i].dlen);
-	}
-
-	if (data_offset != len) {
-		pr_err("%s:%d, Incorrect OFF command entries",
-						__func__, __LINE__);
-		goto error;
-	}
-
-	(panel_data->dsi_panel_off_cmds)->size = num_of_off_cmds;
-
-	off_cmds_state = of_get_property(pdev->dev.of_node,
-				"qcom,off-cmds-dsi-state", NULL);
-	if (!strncmp(off_cmds_state, "DSI_LP_MODE", 11)) {
-		(panel_data->dsi_panel_off_cmds)->ctrl_state =
-						DSI_LP_MODE;
-	} else if (!strncmp(off_cmds_state, "DSI_HS_MODE", 11)) {
-		(panel_data->dsi_panel_off_cmds)->ctrl_state =
-						DSI_HS_MODE;
-	} else {
-		pr_debug("%s: ON cmds state not specified. Set Default\n",
-							__func__);
-		(panel_data->dsi_panel_off_cmds)->ctrl_state =
-						DSI_LP_MODE;
-	}
+	mdss_dsi_parse_dcs_cmds(np, &panel_data->off_cmds,
+		"qcom,panel-off-cmds", "qcom,off-cmds-dsi-state");
 
 	return 0;
-error:
-	kfree((panel_data->dsi_panel_on_cmds)->buf);
-	kfree((panel_data->dsi_panel_off_cmds)->buf);
-	kfree(panel_data->dsi_panel_on_cmds);
-	kfree(panel_data->dsi_panel_off_cmds);
-	kfree(on_cmds);
-	kfree(off_cmds);
 
+error:
 	return -EINVAL;
 }
 
@@ -744,9 +719,6 @@
 
 static int __init mdss_dsi_panel_init(void)
 {
-	mdss_dsi_buf_alloc(&dsi_panel_tx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
-	mdss_dsi_buf_alloc(&dsi_panel_rx_buf, ALIGN(DSI_BUF_SIZE, SZ_4K));
-
 	return platform_driver_register(&this_driver);
 }
 module_init(mdss_dsi_panel_init);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
index f726e79..1f0efd3 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_hdcp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -287,7 +287,7 @@
 	timeout_count = 100;
 	keys_state = (link0_status >> 28) & 0x7;
 	while ((keys_state != HDCP_KEYS_STATE_VALID) &&
-		timeout_count--) {
+		--timeout_count) {
 		link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
 		keys_state = (link0_status >> 28) & 0x7;
 		DEV_DBG("%s: %s: Keys not ready(%d). s=%d\n, l0=%0x08x",
@@ -320,7 +320,7 @@
 				link0_status);
 			msleep(20);
 		}
-	} while (!an_ready && timeout_count--);
+	} while (!an_ready && --timeout_count);
 
 	if (!timeout_count) {
 		rc = -ETIMEDOUT;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 12552bc..ab91320 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -130,9 +130,9 @@
 	{0x18,	0x18,	0x28,	0x28,	0x28,	0x28,	0x28,	0x28,	0x28,
 	 0x28,	0x28,	0x28,	0x28,	0x18,	0x28,	0x18,	0x28,	0x28,
 	 0x28,	0x28}, /*01*/
-	{0x00,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,	0x04,
-	 0x04,	0x04,	0x04,	0x04,	0x88,	0x00,	0x04,	0x04,	0x04,
-	 0x04,	0x04}, /*02*/
+	{0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,	0x00,
+	 0x00,	0x00}, /*02*/
 	{0x02,	0x06,	0x11,	0x15,	0x04,	0x13,	0x10,	0x05,	0x1F,
 	 0x14,	0x20,	0x22,	0x21,	0x01,	0x03,	0x11,	0x00,	0x00,
 	 0x00,	0x00}, /*03*/
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index eb2bd21..afbbe55 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -14,11 +14,12 @@
 #include <linux/kernel.h>
 #include "mdss_panel.h"
 #include "mdss_mdp.h"
+#include "mdss_dsi.h"
 
 #define VSYNC_EXPIRE_TICK 4
 
 #define START_THRESHOLD 4
-#define CONTINUE_TRESHOLD 4
+#define CONTINUE_THRESHOLD 4
 
 #define MAX_SESSIONS 2
 
@@ -26,11 +27,12 @@
 #define KOFF_TIMEOUT msecs_to_jiffies(84)
 
 struct mdss_mdp_cmd_ctx {
+	struct mdss_mdp_ctl *ctl;
 	u32 pp_num;
 	u8 ref_cnt;
+	struct completion vsync_comp;
 	struct completion pp_comp;
 	struct completion stop_comp;
-	atomic_t vsync_ref;
 	mdp_vsync_handler_t send_vsync;
 	int panel_on;
 	int koff_cnt;
@@ -46,6 +48,7 @@
 	u8 tear_check;
 	u16 height;	/* panel height */
 	u16 vporch;	/* vertical porches */
+	u16 start_threshold;
 	u32 vclk_line;	/* vsync clock per line */
 };
 
@@ -83,7 +86,7 @@
 						ctx->height);
 
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_SYNC_THRESH,
-			   (CONTINUE_TRESHOLD << 16) | (START_THRESHOLD));
+		   (CONTINUE_THRESHOLD << 16) | (ctx->start_threshold));
 
 	mdss_mdp_pingpong_write(mixer, MDSS_MDP_REG_PP_TEAR_CHECK_EN, enable);
 	return 0;
@@ -118,13 +121,16 @@
 				    pinfo->lcdc.v_front_porch +
 				    pinfo->lcdc.v_pulse_width;
 
+		ctx->start_threshold = START_THRESHOLD;
+
 		total_lines = ctx->height + ctx->vporch;
 		total_lines *= pinfo->mipi.frame_rate;
 		ctx->vclk_line = mdp_vsync_clk_speed_hz / total_lines;
 
-		pr_debug("%s: fr=%d tline=%d vcnt=%d vrate=%d\n",
+		pr_debug("%s: fr=%d tline=%d vcnt=%d thold=%d vrate=%d\n",
 			__func__, pinfo->mipi.frame_rate, total_lines,
-				ctx->vclk_line, mdp_vsync_clk_speed_hz);
+				ctx->vclk_line, ctx->start_threshold,
+				mdp_vsync_clk_speed_hz);
 	} else {
 		enable = 0;
 	}
@@ -151,6 +157,8 @@
 		return;
 	}
 
+	complete_all(&ctx->vsync_comp);
+
 	pr_debug("%s: num=%d ctx=%d expire=%d koff=%d\n", __func__, ctl->num,
 			ctx->pp_num, ctx->expire, ctx->koff_cnt);
 
@@ -226,6 +234,9 @@
 		mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
 						ctx->pp_num);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		/* disable dsi clock */
+		mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+							(void *)0);
 		complete(&ctx->stop_comp);
 		pr_debug("%s: SET_CLK_OFF, pid=%d\n", __func__, current->pid);
 	} else {
@@ -249,11 +260,12 @@
 
 	enable = (handler->vsync_handler != NULL);
 
+	mutex_lock(&ctx->clk_mtx);
+
 	pr_debug("%s: ctx=%p ctx=%d enabled=%d %d clk_enabled=%d clk_ctrl=%d\n",
 			__func__, ctx, ctx->pp_num, ctx->vsync_enabled, enable,
 					ctx->clk_enabled, ctx->clk_control);
 
-	mutex_lock(&ctx->clk_mtx);
 	if (ctx->vsync_enabled == enable) {
 		mutex_unlock(&ctx->clk_mtx);
 		return 0;
@@ -266,6 +278,8 @@
 		ctx->send_vsync = handler->vsync_handler;
 		spin_unlock_irqrestore(&ctx->clk_lock, flags);
 		if (ctx->clk_enabled == 0) {
+			mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+							(void *)1);
 			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 			mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
 							ctx->pp_num);
@@ -294,10 +308,11 @@
 		return;
 	}
 
+	mutex_lock(&ctx->clk_mtx);
+
 	pr_debug("%s: ctx=%p num=%d clk_enabled=%d\n", __func__,
 				ctx, ctx->pp_num, ctx->clk_enabled);
 
-	mutex_lock(&ctx->clk_mtx);
 	spin_lock_irqsave(&ctx->clk_lock, flags);
 	ctx->koff_cnt++;
 	ctx->clk_control = 0;
@@ -309,6 +324,8 @@
 	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
 	if (set_clk_on) {
+		mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL,
+							(void *)1);
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 		ctx->vsync_enabled = 1;
 		mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
@@ -331,16 +348,18 @@
 
 	pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
 
-	rc = wait_for_completion_interruptible_timeout(&ctx->pp_comp,
+	rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
 			KOFF_TIMEOUT);
 	WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n", rc, ctl->num);
 
-	return rc;
+	return 0;
 }
 
 int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
+	unsigned long flags;
+	int need_wait = 0;
 	int rc;
 
 	ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
@@ -349,10 +368,21 @@
 		return -ENODEV;
 	}
 
-	pr_debug("%s: kickoff intf_num=%d ctx=%p\n", __func__,
-					ctl->intf_num, ctx);
+	spin_lock_irqsave(&ctx->clk_lock, flags);
+	if (ctx->koff_cnt > 0)
+		need_wait = 1;
+	spin_unlock_irqrestore(&ctx->clk_lock, flags);
 
-	mdss_mdp_cmd_chk_clock(ctx);
+	pr_debug("%s: need_wait=%d  intf_num=%d ctx=%p\n",
+			__func__, need_wait, ctl->intf_num, ctx);
+
+	if (need_wait) {
+		rc = wait_for_completion_interruptible_timeout(
+				&ctx->pp_comp, KOFF_TIMEOUT);
+
+		WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n",
+						rc, ctl->num);
+	}
 
 	if (ctx->panel_on == 0) {
 		rc = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UNBLANK, NULL);
@@ -364,10 +394,19 @@
 		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
 	}
 
+	mdss_mdp_cmd_chk_clock(ctx);
+
+	/*
+	 * tx dcs command if had any
+	 */
+	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
+
+	INIT_COMPLETION(ctx->vsync_comp);
 	INIT_COMPLETION(ctx->pp_comp);
 	mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num);
 
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+	mb();
 
 	return 0;
 }
@@ -454,10 +493,11 @@
 		return -ENODEV;
 	}
 
+	ctx->ctl = ctl;
 	ctx->pp_num = mixer->num;
+	init_completion(&ctx->vsync_comp);
 	init_completion(&ctx->pp_comp);
 	init_completion(&ctx->stop_comp);
-	atomic_set(&ctx->vsync_ref, 0);
 	spin_lock_init(&ctx->clk_lock);
 	mutex_init(&ctx->clk_mtx);
 	INIT_WORK(&ctx->clk_work, clk_ctrl_work);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 9e8cfa7..f138420 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -81,6 +81,10 @@
  * @MDSS_EVENT_FB_REGISTERED:	Called after fb dev driver has been registered,
  *				panel driver gets ptr to struct fb_info which
  *				holds fb dev information.
+ * @MDSS_EVENT_PANEL_CLK_CTRL:	panel clock control
+				 - 0 clock disable
+				 - 1 clock enable
+ * @MDSS_EVENT_DSI_CMDLIST_KOFF: kickoff sending dcs command from command list
  */
 enum mdss_intf_events {
 	MDSS_EVENT_RESET = 1,
@@ -94,6 +98,8 @@
 	MDSS_EVENT_CHECK_PARAMS,
 	MDSS_EVENT_CONT_SPLASH_FINISH,
 	MDSS_EVENT_FB_REGISTERED,
+	MDSS_EVENT_PANEL_CLK_CTRL,
+	MDSS_EVENT_DSI_CMDLIST_KOFF,
 };
 
 struct lcd_panel_info {
@@ -222,7 +228,7 @@
 	u32 out_format;
 	u32 vic; /* video identification code */
 	int bklt_ctrl;	/* backlight ctrl */
-	int pwm_gpio;
+	int pwm_pmic_gpio;
 	int pwm_lpg_chan;
 	int pwm_period;
 
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 5564ceb..12bc5e0 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -170,13 +170,10 @@
 	clk_unprepare(ctrl_pdata->byte_clk);
 }
 
-void mdss_dsi_clk_enable(struct mdss_panel_data *pdata)
+void mdss_dsi_clk_enable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
 	u32 esc_clk_rate = 19200000;
 
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
 	if (!ctrl_pdata) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return;
@@ -206,12 +203,8 @@
 	ctrl_pdata->mdss_dsi_clk_on = 1;
 }
 
-void mdss_dsi_clk_disable(struct mdss_panel_data *pdata)
+void mdss_dsi_clk_disable(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
 {
-	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
-	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
-				panel_data);
 	if (!ctrl_pdata) {
 		pr_err("%s: Invalid input data\n", __func__);
 		return;
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index aa1eba5..ce9e5b9 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -195,7 +195,7 @@
 	/* write pointer offset in bytes */
 	unsigned int write_offset;
 
-	/* non-zero if data error occured */
+	/* non-zero if data error occurred */
 	int error;
 };
 
@@ -237,7 +237,10 @@
 	 * (dmx_sct_filter_params) and no sections were
 	 * received for the given time.
 	 */
-	DMX_EVENT_SECTION_TIMEOUT = 0x00000400
+	DMX_EVENT_SECTION_TIMEOUT = 0x00000400,
+
+	/* Scrambling bits change between clear and scrambled */
+	DMX_EVENT_SCRAMBLING_STATUS_CHANGE = 0x00000800
 };
 
 enum dmx_oob_cmd {
@@ -256,7 +259,7 @@
 /* Discontinuity indicator was set */
 #define DMX_FILTER_DISCONTINUITY_INDICATOR	0x02
 
-/* PES legnth in PES header is not correct */
+/* PES length in PES header is not correct */
 #define DMX_FILTER_PES_LENGTH_ERROR		0x04
 
 
@@ -412,7 +415,7 @@
 	/*
 	 * The PID the index entry belongs to.
 	 * In case of recording filter, multiple PIDs may exist in the same
-	 * filter through DMX_ADD_PID ioctl and each can be indexed seperatly.
+	 * filter through DMX_ADD_PID ioctl and each can be indexed separately.
 	 */
 	__u16 pid;
 
@@ -423,7 +426,7 @@
 	__u64 match_tsp_num;
 
 	/*
-	 * The TS packet number in the recorded data preceeding
+	 * The TS packet number in the recorded data preceding
 	 * match_tsp_num and has PUSI set.
 	 */
 	__u64 last_pusi_tsp_num;
@@ -432,6 +435,23 @@
 	__u64 stc;
 };
 
+/* Scrambling information associated with DMX_EVENT_SCRAMBLING_STATUS_CHANGE */
+struct dmx_scrambling_status_event_info {
+	/*
+	 * The PID which its scrambling bit status changed.
+	 * In case of recording filter, multiple PIDs may exist in the same
+	 * filter through DMX_ADD_PID ioctl, each may have
+	 * different scrambling bits status.
+	 */
+	__u16 pid;
+
+	/* old value of scrambling bits */
+	__u8 old_value;
+
+	/* new value of scrambling bits */
+	__u8 new_value;
+};
+
 /*
  * Filter's event returned through DMX_GET_EVENT.
  * poll with POLLPRI would block until events are available.
@@ -447,6 +467,7 @@
 		struct dmx_es_data_event_info es_data;
 		struct dmx_marker_event_info marker;
 		struct dmx_index_event_info index;
+		struct dmx_scrambling_status_event_info scrambling_status;
 	} params;
 };
 
@@ -754,6 +775,19 @@
 	__u32 identifier;
 };
 
+struct dmx_scrambling_bits {
+	/*
+	 * The PID to return its scrambling bit value.
+	 * In case of recording filter, multiple PIDs may exist in the same
+	 * filter through DMX_ADD_PID ioctl, each may have different
+	 * scrambling bits status.
+	 */
+	__u16 pid;
+
+	/* Current value of scrambling bits: 0, 1, 2 or 3 */
+	__u8 value;
+};
+
 #define DMX_START                _IO('o', 41)
 #define DMX_STOP                 _IO('o', 42)
 #define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
@@ -784,5 +818,6 @@
 #define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params)
 #define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion)
 #define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion)
+#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits)
 
 #endif /*_DVBDMX_H_*/
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 61e9cb1..e4df414 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -716,7 +716,7 @@
 	} data;
 };
 
-#define MDP_MAX_FENCE_FD	10
+#define MDP_MAX_FENCE_FD	32
 #define MDP_BUF_SYNC_FLAG_WAIT	1
 
 struct mdp_buf_sync {
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index f551e75..6d7d178 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -3069,4 +3069,32 @@
 	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =	1<<3,
 };
 
+/**
+ * enum nl80211_connect_failed_reason - connection request failed reasons
+ * @NL80211_CONN_FAIL_MAX_CLIENTS: Maximum number of clients that can be
+ *  handled by the AP is reached.
+ * @NL80211_CONN_FAIL_BLOCKED_CLIENT: Connection request is rejected due to ACL.
+ */
+enum nl80211_connect_failed_reason {
+	NL80211_CONN_FAIL_MAX_CLIENTS,
+	NL80211_CONN_FAIL_BLOCKED_CLIENT,
+};
+
+/**
+ * enum nl80211_acl_policy - access control policy
+ *
+ * Access control policy is applied on a MAC list set by
+ * %NL80211_CMD_START_AP and %NL80211_CMD_SET_MAC_ACL, to
+ * be used with %NL80211_ATTR_ACL_POLICY.
+ *
+ * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
+ *   listed in ACL, i.e. allow all the stations which are not listed
+ *  in ACL to authenticate.
+ * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow the stations which are listed
+ *    in ACL, i.e. deny all the stations which are not listed in ACL.
+ */
+enum nl80211_acl_policy {
+	NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED,
+	NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
+};
 #endif /* __LINUX_NL80211_H */
diff --git a/include/linux/of_coresight.h b/include/linux/of_coresight.h
index 0943dda..eb20e80 100644
--- a/include/linux/of_coresight.h
+++ b/include/linux/of_coresight.h
@@ -13,7 +13,7 @@
 #ifndef __LINUX_OF_CORESIGHT_H
 #define __LINUX_OF_CORESIGHT_H
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_OF_CORESIGHT
 extern struct coresight_platform_data *of_get_coresight_platform_data(
 				struct device *dev, struct device_node *node);
 extern struct coresight_cti_data *of_get_coresight_cti_data(
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 67889bf..952bcb1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2726,6 +2726,8 @@
 
 #endif /* CONFIG_SMP */
 
+extern struct atomic_notifier_head migration_notifier_head;
+
 extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask);
 extern long sched_getaffinity(pid_t pid, struct cpumask *mask);
 
diff --git a/include/media/msm_media_info.h b/include/media/msm_media_info.h
index 993a4ab..65831db 100644
--- a/include/media/msm_media_info.h
+++ b/include/media/msm_media_info.h
@@ -7,6 +7,7 @@
 
 enum color_fmts {
 	COLOR_FMT_NV12,
+	COLOR_FMT_NV21,
 };
 
 static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
@@ -16,6 +17,7 @@
 		goto invalid_input;
 
 	switch (color_fmt) {
+	case COLOR_FMT_NV21:
 	case COLOR_FMT_NV12:
 		alignment = 128;
 		stride = MSM_MEDIA_ALIGN(width, alignment);
@@ -34,6 +36,7 @@
 		goto invalid_input;
 
 	switch (color_fmt) {
+	case COLOR_FMT_NV21:
 	case COLOR_FMT_NV12:
 		alignment = 128;
 		stride = MSM_MEDIA_ALIGN(width, alignment);
@@ -52,6 +55,7 @@
 		goto invalid_input;
 
 	switch (color_fmt) {
+	case COLOR_FMT_NV21:
 	case COLOR_FMT_NV12:
 		alignment = 32;
 		sclines = MSM_MEDIA_ALIGN(height, alignment);
@@ -70,6 +74,7 @@
 		goto invalid_input;
 
 	switch (color_fmt) {
+	case COLOR_FMT_NV21:
 	case COLOR_FMT_NV12:
 		alignment = 16;
 		sclines = MSM_MEDIA_ALIGN(((height + 1) >> 1), alignment);
@@ -96,6 +101,7 @@
 	y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
 	uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
 	switch (color_fmt) {
+	case COLOR_FMT_NV21:
 	case COLOR_FMT_NV12:
 		uv_alignment = 4096;
 		y_plane = y_stride * y_sclines;
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index c185096..aead2d2 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -18,6 +18,11 @@
 	MSM_CPP_REALTIME_FRAME,
 };
 
+enum msm_vpe_frame_type {
+	MSM_VPE_OFFLINE_FRAME,
+	MSM_VPE_REALTIME_FRAME,
+};
+
 struct msm_cpp_frame_strip_info {
 	int scale_v_en;
 	int scale_h_en;
@@ -117,6 +122,57 @@
 	uint32_t cpp_hw_caps;
 };
 
+struct msm_vpe_frame_strip_info {
+	uint32_t src_w;
+	uint32_t src_h;
+	uint32_t dst_w;
+	uint32_t dst_h;
+	uint32_t src_x;
+	uint32_t src_y;
+	uint32_t phase_step_x;
+	uint32_t phase_step_y;
+	uint32_t phase_init_x;
+	uint32_t phase_init_y;
+};
+
+struct msm_vpe_buffer_info_t {
+	int fd;
+	uint32_t index;
+	uint32_t offset;
+	uint8_t native_buff;
+	uint8_t processed_divert;
+};
+
+struct msm_vpe_stream_buff_info_t {
+	uint32_t identity;
+	uint32_t num_buffs;
+	struct msm_vpe_buffer_info_t *buffer_info;
+};
+
+struct msm_vpe_frame_info_t {
+	int32_t frame_id;
+	struct timeval timestamp;
+	uint32_t inst_id;
+	uint32_t identity;
+	uint32_t client_id;
+	enum msm_vpe_frame_type frame_type;
+	struct msm_vpe_frame_strip_info strip_info;
+	int src_fd;
+	int dst_fd;
+	struct ion_handle *src_ion_handle;
+	struct ion_handle *dest_ion_handle;
+	unsigned long src_phyaddr;
+	unsigned long dest_phyaddr;
+	unsigned long src_chroma_plane_offset;
+	unsigned long dest_chroma_plane_offset;
+	struct timeval in_time, out_time;
+	void *cookie;
+
+	struct msm_vpe_buffer_info_t input_buffer_info;
+	struct msm_vpe_buffer_info_t output_buffer_info;
+};
+
+
 #define VIDIOC_MSM_CPP_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_v4l2_ioctl_t)
 
@@ -141,7 +197,27 @@
 #define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t)
 
+
+#define VIDIOC_MSM_VPE_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_TRANSACTION_SETUP \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_GET_EVENTPAYLOAD \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_GET_INST_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_ENQUEUE_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_camera_v4l2_ioctl_t)
+
+#define VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_camera_v4l2_ioctl_t)
+
 #define V4L2_EVENT_CPP_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 0)
+#define V4L2_EVENT_VPE_FRAME_DONE  (V4L2_EVENT_PRIVATE_START + 1)
 
 struct msm_camera_v4l2_ioctl_t {
 	uint32_t id;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index dc29eb9..fb2b57a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -416,6 +416,26 @@
 	size_t probe_resp_len;
 };
 
+struct mac_address {
+	u8 addr[ETH_ALEN];
+};
+
+/**
+ * struct cfg80211_acl_data - Access control list data
+ *
+ * @acl_policy: ACL policy to be applied on the station's
+ *	entry specified by mac_addr
+ * @n_acl_entries: Number of MAC address entries passed
+ * @mac_addrs: List of MAC addresses of stations to be used for ACL
+ */
+struct cfg80211_acl_data {
+	enum nl80211_acl_policy acl_policy;
+	int n_acl_entries;
+
+	/* Keep it last */
+	struct mac_address mac_addrs[];
+};
+
 /**
  * struct cfg80211_ap_settings - AP configuration
  *
@@ -432,6 +452,8 @@
  * @privacy: the BSS uses privacy
  * @auth_type: Authentication type (algorithm)
  * @inactivity_timeout: time in seconds to determine station's inactivity.
+ * @acl: ACL configuration used by the drivers which has support for
+ *	MAC address based access control
  */
 struct cfg80211_ap_settings {
 	struct cfg80211_beacon_data beacon;
@@ -444,6 +466,7 @@
 	bool privacy;
 	enum nl80211_auth_type auth_type;
 	int inactivity_timeout;
+	const struct cfg80211_acl_data *acl;
 };
 
 /**
@@ -1559,6 +1582,13 @@
  *	later passes to cfg80211_probe_status().
  *
  * @set_noack_map: Set the NoAck Map for the TIDs.
+ * @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
+ *	Parameters include ACL policy, an array of MAC address of stations
+ *	and the number of MAC addresses. If there is already a list in driver
+ *	this new list replaces the existing one. Driver has to clear its ACL
+ *	when number of MAC addresses entries is passed as 0. Drivers which
+ *	advertise the support for MAC based ACL have to implement this callback.
+ *
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1757,6 +1787,9 @@
 	struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
 	int	(*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
 				 struct cfg80211_update_ft_ies_params *ftie);
+
+	int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
+			   const struct cfg80211_acl_data *params);
 };
 
 /*
@@ -1924,10 +1957,6 @@
 	bool beacon_int_infra_match;
 };
 
-struct mac_address {
-	u8 addr[ETH_ALEN];
-};
-
 struct ieee80211_txrx_stypes {
 	u16 tx, rx;
 };
@@ -2068,6 +2097,9 @@
  * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
  * @ht_capa_mod_mask:  Specify what ht_cap values can be over-ridden.
  *	If null, then none can be over-ridden.
+ *
+ * @max_acl_mac_addrs: Maximum number of MAC addresses that the device
+ *	supports for ACL.
  */
 struct wiphy {
 	/* assign these fields before you register the wiphy */
@@ -2089,6 +2121,8 @@
 	/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
 	u16 interface_modes;
 
+	u16 max_acl_mac_addrs;
+
 	u32 flags, features;
 
 	u32 ap_sme_capa;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 862e172..1a07d2e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -87,6 +87,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/sched.h>
 
+ATOMIC_NOTIFIER_HEAD(migration_notifier_head);
+
 void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period)
 {
 	unsigned long delta;
@@ -1589,15 +1591,17 @@
 try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
 {
 	unsigned long flags;
-	int cpu, success = 0;
+	int cpu, src_cpu, success = 0;
 
 	smp_wmb();
 	raw_spin_lock_irqsave(&p->pi_lock, flags);
+	src_cpu = task_cpu(p);
+	cpu = src_cpu;
+
 	if (!(p->state & state))
 		goto out;
 
 	success = 1; /* we're going to change ->state */
-	cpu = task_cpu(p);
 
 	if (p->on_rq && ttwu_remote(p, wake_flags))
 		goto stat;
@@ -1634,7 +1638,7 @@
 		p->sched_class->task_waking(p);
 
 	cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags);
-	if (task_cpu(p) != cpu) {
+	if (src_cpu != cpu) {
 		wake_flags |= WF_MIGRATED;
 		set_task_cpu(p, cpu);
 	}
@@ -1646,6 +1650,9 @@
 out:
 	raw_spin_unlock_irqrestore(&p->pi_lock, flags);
 
+	if (src_cpu != cpu && task_notify_on_migrate(p))
+		atomic_notifier_call_chain(&migration_notifier_head,
+					   cpu, (void *)src_cpu);
 	return success;
 }
 
@@ -5068,6 +5075,7 @@
 static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu)
 {
 	struct rq *rq_dest, *rq_src;
+	bool moved = false;
 	int ret = 0;
 
 	if (unlikely(!cpu_active(dest_cpu)))
@@ -5094,12 +5102,16 @@
 		set_task_cpu(p, dest_cpu);
 		enqueue_task(rq_dest, p, 0);
 		check_preempt_curr(rq_dest, p, 0);
+		moved = true;
 	}
 done:
 	ret = 1;
 fail:
 	double_rq_unlock(rq_src, rq_dest);
 	raw_spin_unlock(&p->pi_lock);
+	if (moved && task_notify_on_migrate(p))
+		atomic_notifier_call_chain(&migration_notifier_head,
+					   dest_cpu, (void *)src_cpu);
 	return ret;
 }
 
@@ -7731,6 +7743,24 @@
 	sched_move_task(task);
 }
 
+static u64 cpu_notify_on_migrate_read_u64(struct cgroup *cgrp,
+					  struct cftype *cft)
+{
+	struct task_group *tg = cgroup_tg(cgrp);
+
+	return tg->notify_on_migrate;
+}
+
+static int cpu_notify_on_migrate_write_u64(struct cgroup *cgrp,
+					   struct cftype *cft, u64 notify)
+{
+	struct task_group *tg = cgroup_tg(cgrp);
+
+	tg->notify_on_migrate = (notify > 0);
+
+	return 0;
+}
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
 				u64 shareval)
@@ -8002,6 +8032,11 @@
 #endif /* CONFIG_RT_GROUP_SCHED */
 
 static struct cftype cpu_files[] = {
+	{
+		.name = "notify_on_migrate",
+		.read_u64 = cpu_notify_on_migrate_read_u64,
+		.write_u64 = cpu_notify_on_migrate_write_u64,
+	},
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	{
 		.name = "shares",
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 7e31770..103730d 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2126,11 +2126,11 @@
 static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
 {
 	struct sched_entity *se = &p->se;
-	struct cfs_rq *cfs_rq = &rq->cfs;
+	struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
 	WARN_ON(task_rq(p) != rq);
 
-	if (cfs_rq->h_nr_running > 1) {
+	if (rq->cfs.h_nr_running > 1) {
 		u64 slice = sched_slice(cfs_rq, se);
 		u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
 		s64 delta = slice - ran;
@@ -3101,6 +3101,8 @@
 	unsigned int		loop_max;
 };
 
+static DEFINE_PER_CPU(bool, dbs_boost_needed);
+
 /*
  * move_task - move a task from one runqueue to another runqueue.
  * Both runqueues must be locked.
@@ -3111,6 +3113,8 @@
 	set_task_cpu(p, env->dst_cpu);
 	activate_task(env->dst_rq, p, 0);
 	check_preempt_curr(env->dst_rq, p, 0);
+	if (task_notify_on_migrate(p))
+		per_cpu(dbs_boost_needed, env->dst_cpu) = true;
 }
 
 /*
@@ -4541,9 +4545,15 @@
 			 */
 			sd->nr_balance_failed = sd->cache_nice_tries+1;
 		}
-	} else
+	} else {
 		sd->nr_balance_failed = 0;
-
+		if (per_cpu(dbs_boost_needed, this_cpu)) {
+			per_cpu(dbs_boost_needed, this_cpu) = false;
+			atomic_notifier_call_chain(&migration_notifier_head,
+						   this_cpu,
+						   (void *)cpu_of(busiest));
+		}
+	}
 	if (likely(!active_balance)) {
 		/* We were unbalanced, so reset the balancing interval */
 		sd->balance_interval = sd->min_interval;
@@ -4698,6 +4708,12 @@
 out_unlock:
 	busiest_rq->active_balance = 0;
 	raw_spin_unlock_irq(&busiest_rq->lock);
+	if (per_cpu(dbs_boost_needed, target_cpu)) {
+		per_cpu(dbs_boost_needed, target_cpu) = false;
+		atomic_notifier_call_chain(&migration_notifier_head,
+					   target_cpu,
+					   (void *)cpu_of(busiest_rq));
+	}
 	return 0;
 }
 
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 8f32475..f8317df 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1604,6 +1604,7 @@
 	struct task_struct *next_task;
 	struct rq *lowest_rq;
 	int ret = 0;
+	bool moved = false;
 
 	if (!rq->rt.overloaded)
 		return 0;
@@ -1673,6 +1674,7 @@
 
 	deactivate_task(rq, next_task, 0);
 	set_task_cpu(next_task, lowest_rq->cpu);
+	moved = true;
 	activate_task(lowest_rq, next_task, 0);
 	ret = 1;
 
@@ -1683,6 +1685,11 @@
 out:
 	put_task_struct(next_task);
 
+	if (moved && task_notify_on_migrate(next_task))
+		atomic_notifier_call_chain(&migration_notifier_head,
+					   cpu_of(lowest_rq),
+					   (void *)cpu_of(rq));
+
 	return ret;
 }
 
@@ -1696,8 +1703,10 @@
 static int pull_rt_task(struct rq *this_rq)
 {
 	int this_cpu = this_rq->cpu, ret = 0, cpu;
-	struct task_struct *p;
+	struct task_struct *p = NULL;
 	struct rq *src_rq;
+	bool moved = false;
+	int src_cpu = 0;
 
 	if (likely(!rt_overloaded(this_rq)))
 		return 0;
@@ -1758,6 +1767,10 @@
 			deactivate_task(src_rq, p, 0);
 			set_task_cpu(p, this_cpu);
 			activate_task(this_rq, p, 0);
+
+			moved = true;
+			src_cpu = cpu_of(src_rq);
+
 			/*
 			 * We continue with the search, just in
 			 * case there's an even higher prio task
@@ -1769,6 +1782,11 @@
 		double_unlock_balance(this_rq, src_rq);
 	}
 
+	if (moved && task_notify_on_migrate(p))
+		atomic_notifier_call_chain(&migration_notifier_head,
+					   this_cpu,
+					   (void *)src_cpu);
+
 	return ret;
 }
 
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 451bd4f..5370bcb 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -104,6 +104,8 @@
 struct task_group {
 	struct cgroup_subsys_state css;
 
+	bool notify_on_migrate;
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	/* schedulable entities of this group on each cpu */
 	struct sched_entity **se;
@@ -554,6 +556,11 @@
 	return autogroup_task_group(p, tg);
 }
 
+static inline bool task_notify_on_migrate(struct task_struct *p)
+{
+	return task_group(p)->notify_on_migrate;
+}
+
 /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
 static inline void set_task_rq(struct task_struct *p, unsigned int cpu)
 {
@@ -579,7 +586,10 @@
 {
 	return NULL;
 }
-
+static inline bool task_notify_on_migrate(struct task_struct *p)
+{
+	return false;
+}
 #endif /* CONFIG_CGROUP_SCHED */
 
 static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index ccdfed8..674c1fa 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -505,6 +505,11 @@
 			   ETH_ALEN)))
 		return -EINVAL;
 
+	if (WARN_ON(wiphy->max_acl_mac_addrs &&
+		    (!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME) ||
+		     !rdev->ops->set_mac_acl)))
+		return -EINVAL;
+
 	if (wiphy->addresses)
 		memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e1fa62e..6ed6d3e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -210,6 +210,8 @@
 	[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
 	[NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
 	[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
+	[NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
+	[NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
 	[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
 	[NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
 	[NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
@@ -1066,6 +1068,11 @@
 			sizeof(*dev->wiphy.ht_capa_mod_mask),
 			dev->wiphy.ht_capa_mod_mask);
 
+	if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
+	    dev->wiphy.max_acl_mac_addrs)
+		NLA_PUT_U32(msg, NL80211_ATTR_MAC_ACL_MAX,
+			    dev->wiphy.max_acl_mac_addrs);
+
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -2105,6 +2112,97 @@
 	return err;
 }
 
+/* This function returns an error or the number of nested attributes */
+static int validate_acl_mac_addrs(struct nlattr *nl_attr)
+{
+	struct nlattr *attr;
+	int n_entries = 0, tmp;
+
+	nla_for_each_nested(attr, nl_attr, tmp) {
+		if (nla_len(attr) != ETH_ALEN)
+			return -EINVAL;
+
+		n_entries++;
+	}
+
+	return n_entries;
+}
+
+/*
+ * This function parses ACL information and allocates memory for ACL data.
+ * On successful return, the calling function is responsible to free the
+ * ACL buffer returned by this function.
+ */
+static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
+						struct genl_info *info)
+{
+	enum nl80211_acl_policy acl_policy;
+	struct nlattr *attr;
+	struct cfg80211_acl_data *acl;
+	int i = 0, n_entries, tmp;
+
+	if (!wiphy->max_acl_mac_addrs)
+		return ERR_PTR(-EOPNOTSUPP);
+
+	if (!info->attrs[NL80211_ATTR_ACL_POLICY])
+		return ERR_PTR(-EINVAL);
+
+	acl_policy = nla_get_u32(info->attrs[NL80211_ATTR_ACL_POLICY]);
+	if (acl_policy != NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
+	    acl_policy != NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
+		return ERR_PTR(-EINVAL);
+
+	if (!info->attrs[NL80211_ATTR_MAC_ADDRS])
+		return ERR_PTR(-EINVAL);
+
+	n_entries = validate_acl_mac_addrs(info->attrs[NL80211_ATTR_MAC_ADDRS]);
+	if (n_entries < 0)
+		return ERR_PTR(n_entries);
+
+	if (n_entries > wiphy->max_acl_mac_addrs)
+		return ERR_PTR(-ENOTSUPP);
+
+	acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
+		      GFP_KERNEL);
+	if (!acl)
+		return ERR_PTR(-ENOMEM);
+
+	nla_for_each_nested(attr, info->attrs[NL80211_ATTR_MAC_ADDRS], tmp) {
+		memcpy(acl->mac_addrs[i].addr, nla_data(attr), ETH_ALEN);
+		i++;
+	}
+
+	acl->n_acl_entries = n_entries;
+	acl->acl_policy = acl_policy;
+
+	return acl;
+}
+
+static int nl80211_set_mac_acl(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct cfg80211_acl_data *acl;
+	int err;
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+	    dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+		return -EOPNOTSUPP;
+
+	if (!dev->ieee80211_ptr->beacon_interval)
+		return -EINVAL;
+
+	acl = parse_acl_data(&rdev->wiphy, info);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+
+	err = rdev->ops->set_mac_acl(&rdev->wiphy, dev, acl);
+
+	kfree(acl);
+
+	return err;
+}
+
 static int nl80211_parse_beacon(struct genl_info *info,
 				struct cfg80211_beacon_data *bcn)
 {
@@ -2251,9 +2349,18 @@
 			info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
 	}
 
+	if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
+		params.acl = parse_acl_data(&rdev->wiphy, info);
+		if (IS_ERR(params.acl))
+			return PTR_ERR(params.acl);
+	}
+
 	err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
 	if (!err)
 		wdev->beacon_interval = params.beacon_interval;
+
+	kfree(params.acl);
+
 	return err;
 }
 
@@ -7063,6 +7170,14 @@
 				  NL80211_FLAG_NEED_RTNL,
 	},
 	{
+		.cmd = NL80211_CMD_SET_MAC_ACL,
+		.doit = nl80211_set_mac_acl,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
 		.cmd = NL80211_CMD_UPDATE_FT_IES,
 		.doit = nl80211_update_ft_ies,
 		.policy = nl80211_policy,
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 29703b9..bda43a5 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -2703,7 +2703,7 @@
 	}
 
 	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
-	msleep(250);
+	msleep(20);
 	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 	pr_debug("%s: leave\n", __func__);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index a37b4eb..cc22fd4 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -134,6 +134,14 @@
 	WCD9XXX_HPHR_DAC_OFF_ACK
 };
 
+enum wcd9xxx_current_v_idx {
+	WCD9XXX_CURRENT_V_INS_H,
+	WCD9XXX_CURRENT_V_INS_HU,
+	WCD9XXX_CURRENT_V_B1_H,
+	WCD9XXX_CURRENT_V_B1_HU,
+	WCD9XXX_CURRENT_V_BR_H,
+};
+
 static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
 {
 	return mbhc->polling_active;
@@ -266,6 +274,7 @@
 	int cfilt_k_val;
 	bool override;
 	struct snd_soc_codec *codec;
+	struct mbhc_internal_cal_data *d = &mbhc->mbhc_data;
 
 	codec = mbhc->codec;
 
@@ -278,7 +287,7 @@
 		if (!override)
 			wcd9xxx_turn_onoff_override(codec, true);
 		/* Adjust threshold if Mic Bias voltage changes */
-		if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+		if (d->micb_mv != VDDIO_MICBIAS_MV) {
 			cfilt_k_val = wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
 							      VDDIO_MICBIAS_MV);
 			usleep_range(10000, 10000);
@@ -286,11 +295,28 @@
 					mbhc->mbhc_bias_regs.cfilt_val,
 					0xFC, (cfilt_k_val << 2));
 			usleep_range(10000, 10000);
+			/* Threshods for insertion/removal */
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
-				      mbhc->mbhc_data.adj_v_ins_hu & 0xFF);
+				      d->v_ins_hu[MBHC_V_IDX_VDDIO] & 0xFF);
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
-				      (mbhc->mbhc_data.adj_v_ins_hu >> 8) &
+				      (d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
 				      0xFF);
+			/* Threshods for button press */
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+				      d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+				      (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
+				      0xFF);
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+				      d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+				      (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
+				      0xFF);
+			/* Threshods for button release */
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+				      d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+				      (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
 			pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
 				 __func__);
 		}
@@ -312,18 +338,36 @@
 		    restartpolling)
 			wcd9xxx_pause_hs_polling(mbhc);
 		/* Reprogram thresholds */
-		if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+		if (d->micb_mv != VDDIO_MICBIAS_MV) {
 			cfilt_k_val =
 			    wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
-						     mbhc->mbhc_data.micb_mv);
+						     d->micb_mv);
 			snd_soc_update_bits(codec,
 					mbhc->mbhc_bias_regs.cfilt_val,
 					0xFC, (cfilt_k_val << 2));
 			usleep_range(10000, 10000);
+			/* Revert threshods for insertion/removal */
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
-					mbhc->mbhc_data.v_ins_hu & 0xFF);
+					d->v_ins_hu[MBHC_V_IDX_CFILT] & 0xFF);
 			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
-					(mbhc->mbhc_data.v_ins_hu >> 8) & 0xFF);
+					(d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
+					0xFF);
+			/* Revert threshods for button press */
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
+				      d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
+				      (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
+				      0xFF);
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
+				      d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
+				      (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
+				      0xFF);
+			/* Revert threshods for button release */
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
+				      d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
+			snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
+				      (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
 			pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
 					__func__);
 		}
@@ -347,17 +391,37 @@
 	return __wcd9xxx_switch_micbias(mbhc, vddio_switch, true, true);
 }
 
-static s16 wcd9xxx_get_current_v_ins(struct wcd9xxx_mbhc *mbhc, bool hu)
+static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
+				 const enum wcd9xxx_current_v_idx idx)
 {
-	s16 v_ins;
+	enum mbhc_v_index vidx;
+	s16 ret = -EINVAL;
+
 	if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
 	    mbhc->mbhc_micbias_switched)
-		v_ins = hu ? (s16)mbhc->mbhc_data.adj_v_ins_hu :
-			(s16)mbhc->mbhc_data.adj_v_ins_h;
+		vidx = MBHC_V_IDX_VDDIO;
 	else
-		v_ins = hu ? (s16)mbhc->mbhc_data.v_ins_hu :
-			(s16)mbhc->mbhc_data.v_ins_h;
-	return v_ins;
+		vidx = MBHC_V_IDX_CFILT;
+
+	switch (idx) {
+	case WCD9XXX_CURRENT_V_INS_H:
+		ret = (s16)mbhc->mbhc_data.v_ins_h[vidx];
+		break;
+	case WCD9XXX_CURRENT_V_INS_HU:
+		ret = (s16)mbhc->mbhc_data.v_ins_hu[vidx];
+		break;
+	case WCD9XXX_CURRENT_V_B1_H:
+		ret = (s16)mbhc->mbhc_data.v_b1_h[vidx];
+		break;
+	case WCD9XXX_CURRENT_V_B1_HU:
+		ret = (s16)mbhc->mbhc_data.v_b1_hu[vidx];
+		break;
+	case WCD9XXX_CURRENT_V_BR_H:
+		ret = (s16)mbhc->mbhc_data.v_brh[vidx];
+		break;
+	}
+
+	return ret;
 }
 
 void *wcd9xxx_mbhc_cal_btn_det_mp(
@@ -389,27 +453,25 @@
 static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
 {
 	struct snd_soc_codec *codec = mbhc->codec;
-	const s16 v_ins_hu = wcd9xxx_get_current_v_ins(mbhc, true);
+	const s16 v_ins_hu = wcd9xxx_get_current_v(mbhc,
+						   WCD9XXX_CURRENT_V_INS_HU);
+	const s16 v_b1_hu = wcd9xxx_get_current_v(mbhc,
+						  WCD9XXX_CURRENT_V_B1_HU);
+	const s16 v_b1_h = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
+	const s16 v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
 
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
 		      (v_ins_hu >> 8) & 0xFF);
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
-		      mbhc->mbhc_data.v_b1_hu & 0xFF);
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
-		      (mbhc->mbhc_data.v_b1_hu >> 8) & 0xFF);
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
-		      mbhc->mbhc_data.v_b1_h & 0xFF);
+		      (v_b1_hu >> 8) & 0xFF);
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
-		      (mbhc->mbhc_data.v_b1_h >> 8) & 0xFF);
-
-	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
-		      mbhc->mbhc_data.v_brh & 0xFF);
+		      (v_b1_h >> 8) & 0xFF);
+	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
-		      (mbhc->mbhc_data.v_brh >> 8) & 0xFF);
-
+		      (v_brh >> 8) & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
 		      mbhc->mbhc_data.v_brl & 0xFF);
 	snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
@@ -813,6 +875,19 @@
 	WCD9XXX_BCL_LOCK(mbhc->resmgr);
 }
 
+static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
+{
+	int r;
+	int vddio_k, mb_k;
+	vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
+	mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
+	if (tovddio)
+		r = v * vddio_k / mb_k;
+	else
+		r = v * mb_k / vddio_k;
+	return r;
+}
+
 static s16 wcd9xxx_get_current_v_hs_max(struct wcd9xxx_mbhc *mbhc)
 {
 	s16 v_hs_max;
@@ -821,7 +896,7 @@
 	plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
 	if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
 	    mbhc->mbhc_micbias_switched)
-		v_hs_max = mbhc->mbhc_data.adj_v_hs_max;
+		v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
 	else
 		v_hs_max = plug_type->v_hs_max;
 	return v_hs_max;
@@ -1032,19 +1107,6 @@
 	mbhc->mbhc_state = MBHC_STATE_NONE;
 }
 
-static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
-{
-	int r;
-	int vddio_k, mb_k;
-	vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
-	mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
-	if (tovddio)
-		r = v * vddio_k / mb_k;
-	else
-		r = v * mb_k / vddio_k;
-	return r;
-}
-
 /* called under codec_resource_lock acquisition */
 static void wcd9xxx_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
 {
@@ -1680,7 +1742,8 @@
 		bias_value = wcd9xxx_codec_sta_dce(mbhc, 1,  true);
 		pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
 			 wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value), min_us);
-		if (bias_value < wcd9xxx_get_current_v_ins(mbhc, false)) {
+		if (bias_value <
+		    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
 			pr_debug("%s: checking false removal\n", __func__);
 			msleep(500);
 			removed = !wcd9xxx_hs_remove_settle(mbhc);
@@ -1942,7 +2005,8 @@
 static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc)
 {
 	struct snd_soc_codec *codec;
-	s16 btn_mv = 0, btn_delta_mv;
+	s16 adj_v_hs_max;
+	s16 btn_mv = 0, btn_mv_sta[MBHC_V_IDX_NUM], btn_mv_dce[MBHC_V_IDX_NUM];
 	struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
 	struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
 	u16 *btn_high;
@@ -1953,23 +2017,21 @@
 	btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
 	plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
 
-	mbhc->mbhc_data.v_ins_hu =
+	mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
 	    wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max);
-	mbhc->mbhc_data.v_ins_h =
+	mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
 	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max);
 
 	mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
 	mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
 
 	if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
-		mbhc->mbhc_data.adj_v_hs_max =
-		    scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
-		mbhc->mbhc_data.adj_v_ins_hu =
-		    wcd9xxx_codec_v_sta_dce(mbhc, STA,
-					    mbhc->mbhc_data.adj_v_hs_max);
-		mbhc->mbhc_data.adj_v_ins_h =
-		    wcd9xxx_codec_v_sta_dce(mbhc, DCE,
-					    mbhc->mbhc_data.adj_v_hs_max);
+		adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
+						  true);
+		mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
+		    wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max);
+		mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
+		    wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max);
 		mbhc->mbhc_data.v_inval_ins_low =
 		    scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
 				       false);
@@ -1983,17 +2045,27 @@
 	for (i = 0; i < btn_det->num_btn; i++)
 		btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
 
-	mbhc->mbhc_data.v_b1_h = wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv);
-	btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
-	mbhc->mbhc_data.v_b1_hu =
-	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_delta_mv);
+	btn_mv_sta[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_sta;
+	btn_mv_dce[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_cic;
+	btn_mv_sta[MBHC_V_IDX_VDDIO] =
+	    scale_v_micb_vddio(mbhc, btn_mv_sta[MBHC_V_IDX_CFILT], true);
+	btn_mv_dce[MBHC_V_IDX_VDDIO] =
+	    scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
 
-	btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
+	mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT]);
+	mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
+	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT]);
+	mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
+	    wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO]);
+	mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
+	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO]);
 
-	mbhc->mbhc_data.v_b1_huc =
-	    wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_delta_mv);
+	mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
+	    mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
+	mbhc->mbhc_data.v_brh[MBHC_V_IDX_VDDIO] =
+	    mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO];
 
-	mbhc->mbhc_data.v_brh = mbhc->mbhc_data.v_b1_h;
 	mbhc->mbhc_data.v_brl = BUTTON_MIN;
 
 	mbhc->mbhc_data.v_no_mic =
@@ -2278,12 +2350,17 @@
 static int wcd9xxx_is_fake_press(struct wcd9xxx_mbhc *mbhc)
 {
 	int i;
+	s16 mb_v;
 	int r = 0;
 	const int dces = NUM_DCE_PLUG_DETECT;
-	s16 mb_v, v_ins_hu, v_ins_h;
-
-	v_ins_hu = wcd9xxx_get_current_v_ins(mbhc, true);
-	v_ins_h = wcd9xxx_get_current_v_ins(mbhc, false);
+	const s16 v_ins_hu =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
+	const s16 v_ins_h =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
+	const s16 v_b1_hu =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
+	const s16 v_b1_h =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
 
 	for (i = 0; i < dces; i++) {
 		usleep_range(10000, 10000);
@@ -2291,8 +2368,7 @@
 			mb_v = wcd9xxx_codec_sta_dce(mbhc, 0, true);
 			pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
 				 wcd9xxx_codec_sta_dce_v(mbhc, 0, mb_v));
-			if (mb_v < (s16)mbhc->mbhc_data.v_b1_hu ||
-			    mb_v > v_ins_hu) {
+			if (mb_v < v_b1_hu || mb_v > v_ins_hu) {
 				r = 1;
 				break;
 			}
@@ -2300,8 +2376,7 @@
 			mb_v = wcd9xxx_codec_sta_dce(mbhc, 1, true);
 			pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
 				 wcd9xxx_codec_sta_dce_v(mbhc, 1, mb_v));
-			if (mb_v < (s16)mbhc->mbhc_data.v_b1_h ||
-			    mb_v > v_ins_h) {
+			if (mb_v < v_b1_h || mb_v > v_ins_h) {
 				r = 1;
 				break;
 			}
@@ -2995,8 +3070,16 @@
 	int n = 0;
 	struct wcd9xxx_mbhc *mbhc = file->private_data;
 	const struct mbhc_internal_cal_data *p = &mbhc->mbhc_data;
-	const s16 v_ins_hu_cur = wcd9xxx_get_current_v_ins(mbhc, true);
-	const s16 v_ins_h_cur = wcd9xxx_get_current_v_ins(mbhc, false);
+	const s16 v_ins_hu =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
+	const s16 v_ins_h =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
+	const s16 v_b1_hu =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
+	const s16 v_b1_h =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
+	const s16 v_br_h =
+	    wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
 
 	n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n",  p->dce_z,
 		      wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
@@ -3006,35 +3089,19 @@
 		       p->sta_z, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_z));
 	n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
 		       p->sta_mb, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_mb));
-	n += scnprintf(buffer + n, size - n, "t_dce = %x\n",  p->t_dce);
-	n += scnprintf(buffer + n, size - n, "t_sta = %x\n",  p->t_sta);
-	n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
-		       p->micb_mv);
-	n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
-		       p->v_ins_hu,
-		       wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_ins_hu),
-		       p->v_ins_hu == v_ins_hu_cur ? "*" : "");
-	n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
-		       p->v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_ins_h),
-		       p->v_ins_h == v_ins_h_cur ? "*" : "");
-	n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
-		       p->adj_v_ins_hu,
-		       wcd9xxx_codec_sta_dce_v(mbhc, 0, p->adj_v_ins_hu),
-		       p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
-	n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
-		       p->adj_v_ins_h,
-		       wcd9xxx_codec_sta_dce_v(mbhc, 1, p->adj_v_ins_h),
-		       p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
+	n += scnprintf(buffer + n, size - n, "t_dce = %d\n",  p->t_dce);
+	n += scnprintf(buffer + n, size - n, "t_sta = %d\n",  p->t_sta);
+	n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n", p->micb_mv);
+	n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)\n",
+		       v_ins_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_ins_hu));
+	n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)\n",
+		       v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_ins_h));
 	n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
-		       p->v_b1_hu,
-		       wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_b1_hu));
+		       v_b1_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_b1_hu));
 	n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
-		       p->v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_b1_h));
-	n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
-		       p->v_b1_huc,
-		       wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_b1_huc));
+		       v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_b1_h));
 	n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
-		       p->v_brh, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->v_brh));
+		       v_br_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_br_h));
 	n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n",  p->v_brl,
 		       wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_brl));
 	n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 300e34e..4f8f3cf 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -28,6 +28,12 @@
 	u8 cfilt_sel;
 };
 
+enum mbhc_v_index {
+	MBHC_V_IDX_CFILT,
+	MBHC_V_IDX_VDDIO,
+	MBHC_V_IDX_NUM,
+};
+
 /* Data used by MBHC */
 struct mbhc_internal_cal_data {
 	u16 dce_z;
@@ -38,17 +44,13 @@
 	u32 t_dce;
 	u32 t_sta;
 	u32 micb_mv;
-	u16 v_ins_hu;
-	u16 v_ins_h;
-	u16 v_b1_hu;
-	u16 v_b1_h;
-	u16 v_b1_huc;
-	u16 v_brh;
+	u16 v_ins_hu[MBHC_V_IDX_NUM];
+	u16 v_ins_h[MBHC_V_IDX_NUM];
+	u16 v_b1_hu[MBHC_V_IDX_NUM];
+	u16 v_b1_h[MBHC_V_IDX_NUM];
+	u16 v_brh[MBHC_V_IDX_NUM];
 	u16 v_brl;
 	u16 v_no_mic;
-	s16 adj_v_hs_max;
-	u16 adj_v_ins_hu;
-	u16 adj_v_ins_h;
 	s16 v_inval_ins_low;
 	s16 v_inval_ins_high;
 };
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 2c3c6df..95122b2 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1464,8 +1464,8 @@
 		ret = voc_set_ext_ec_ref(msm_route_ext_ec_ref, false);
 		break;
 	}
-	snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
 	mutex_unlock(&routing_lock);
+	snd_soc_dapm_mux_update_power(widget, kcontrol, 1, mux, e);
 	return ret;
 }
 
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 26e6ae6..6d0fcea 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -505,6 +505,9 @@
 	voc_set_tty_mode(voc_get_session_id(VOICE_SESSION_NAME), tty_mode);
 
 	voc_set_tty_mode(voc_get_session_id(VOICE2_SESSION_NAME), tty_mode);
+
+	voc_set_tty_mode(voc_get_session_id(VOLTE_SESSION_NAME), tty_mode);
+
 	return 0;
 }
 static int msm_voice_widevoice_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 08d7277..bedaba0 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -243,7 +243,7 @@
 	struct ocmem_buf *buf = NULL;
 	struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_segptr;
 
-	pr_debug("%s\n", __func__);
+	pr_debug("%s, %p\n", __func__, &audio_ocmem_lcl);
 	atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
 	if (audio_ocmem_lcl.lp_memseg_ptr == NULL) {
 		/* Retrieve low power segments */
@@ -329,6 +329,7 @@
 	if (ret) {
 		pr_err("%s: ocmem_map failed\n", __func__);
 		atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
+		goto fail_cmd1;
 	}
 
 	wait_event_interruptible(audio_ocmem_lcl.audio_wait,
@@ -372,7 +373,7 @@
 				pr_err("%s: ocmem_unmap failed, state[%d]\n",
 				__func__,
 				atomic_read(&audio_ocmem_lcl.audio_state));
-				goto fail_cmd;
+				goto fail_cmd1;
 			}
 
 			wait_event_interruptible(audio_ocmem_lcl.audio_wait,
@@ -384,7 +385,7 @@
 				pr_err("%s: ocmem_shrink failed, state[%d]\n",
 				__func__,
 				atomic_read(&audio_ocmem_lcl.audio_state));
-				goto fail_cmd;
+				goto fail_cmd1;
 			}
 			atomic_set(&audio_ocmem_lcl.audio_cond, 1);
 			clear_bit_pos(audio_ocmem_lcl.audio_state,
@@ -405,7 +406,7 @@
 				pr_err("%s: ocmem_map failed, state[%d]\n",
 				__func__,
 				atomic_read(&audio_ocmem_lcl.audio_state));
-				goto fail_cmd;
+				goto fail_cmd1;
 			}
 			wait_event_interruptible(audio_ocmem_lcl.audio_wait,
 				(atomic_read(&audio_ocmem_lcl.audio_state) &
@@ -428,7 +429,7 @@
 					pr_err("%s: ocmem_unmap failed, state[0x%x]\n",
 					__func__,
 				atomic_read(&audio_ocmem_lcl.audio_state));
-					goto fail_cmd;
+					goto fail_cmd1;
 				}
 				wait_event_interruptible(
 				audio_ocmem_lcl.audio_wait,
@@ -446,14 +447,16 @@
 					pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
 						__func__,
 				atomic_read(&audio_ocmem_lcl.audio_state));
-					goto fail_cmd;
+					goto fail_cmd1;
 				}
 				clear_bit_pos(audio_ocmem_lcl.audio_state,
 						OCMEM_STATE_SHRINK);
 
 			}
 
-			pr_debug("%s: calling ocmem free\n", __func__);
+			pr_debug("%s: calling ocmem free, state:0x%x\n",
+				__func__,
+				atomic_read(&audio_ocmem_lcl.audio_state));
 			ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
 			if (ret == -EAGAIN) {
 				pr_debug("%s: received EAGAIN\n", __func__);
@@ -466,7 +469,7 @@
 						pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
 							__func__,
 				atomic_read(&audio_ocmem_lcl.audio_state));
-							goto fail_cmd;
+							goto fail_cmd1;
 					}
 					pr_debug("calling free after EAGAIN");
 					ret = ocmem_free(OCMEM_LP_AUDIO,
@@ -474,19 +477,19 @@
 					if (ret) {
 						pr_err("%s: ocmem_free failed\n",
 								__func__);
-						goto fail_cmd;
+						goto fail_cmd2;
 					}
 				} else {
 					pr_debug("%s: shrink callback already processed\n",
 								__func__);
-					goto fail_cmd;
+					goto fail_cmd1;
 				}
 			} else if (ret) {
 				pr_err("%s: ocmem_free failed, state[0x%x], ret:%d\n",
 					__func__,
 				atomic_read(&audio_ocmem_lcl.audio_state),
 				ret);
-				goto fail_cmd;
+				goto fail_cmd2;
 			}
 			pr_debug("%s: ocmem_free success\n", __func__);
 		/* Fall through */
@@ -508,6 +511,14 @@
 		mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 	}
 	ret = 0;
+	goto fail_cmd;
+
+fail_cmd1:
+	ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+	if (ret)
+		pr_err("%s: ocmem_free failed\n", __func__);
+fail_cmd2:
+	mutex_unlock(&audio_ocmem_lcl.state_process_lock);
 fail_cmd:
 	pr_debug("%s: exit\n", __func__);
 	audio_ocmem_lcl.audio_ocmem_running = false;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index c2fd2d7..ac26d0c 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -3363,6 +3363,7 @@
 	u32 lbuf_addr_lsw;
 	u32 liomode;
 	u32 io_compressed;
+	int dir = 0;
 
 	if (!ac || ac->apr == NULL) {
 		pr_err("%s: APR handle NULL\n", __func__);
@@ -3380,15 +3381,21 @@
 	read.seq_id = param->uid;
 	liomode = (NT_MODE | ASYNC_IO_MODE);
 	io_compressed = (ASYNC_IO_MODE | COMPRESSED_IO);
-	if (ac->io_mode == liomode)
+	if (ac->io_mode == liomode) {
 		lbuf_addr_lsw = (read.buf_addr_lsw - 32);
-	else if (ac->io_mode == io_compressed)
+		/*legacy wma driver case*/
+		dir = IN;
+	} else if (ac->io_mode == io_compressed) {
 		lbuf_addr_lsw = (read.buf_addr_lsw - 64);
-	else
+		dir = OUT;
+	} else {
 		lbuf_addr_lsw = read.buf_addr_lsw;
+		dir = OUT;
+	}
 
-	list_for_each_safe(ptr, next, &ac->port[OUT].mem_map_handle) {
-		buf_node = list_entry(ptr, struct asm_buffer_node, list);
+	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
+		buf_node = list_entry(ptr, struct asm_buffer_node,
+			list);
 			if (buf_node->buf_addr_lsw == lbuf_addr_lsw) {
 				read.mem_map_handle = buf_node->mmap_hdl;
 				break;
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index 42cbcd1..5fec0c1 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -29,7 +29,7 @@
 	struct apr_svc *core_handle_q;
 	wait_queue_head_t bus_bw_req_wait;
 	u32 bus_bw_resp_received;
-	struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_ocm_payload;
+	struct avcs_cmd_rsp_get_low_power_segments_info_t lp_ocm_payload;
 };
 
 static struct q6core_str q6core_lcl;
@@ -74,19 +74,19 @@
 		pr_info("%s: cmd = AVCS_CMDRSP_GET_LOW_POWER_SEGMENTS_INFO num_segments = 0x%x\n",
 					__func__, payload1[0]);
 		nseg = payload1[0];
-		q6core_lcl.lp_ocm_payload->num_segments = nseg;
-		q6core_lcl.lp_ocm_payload->bandwidth = payload1[1];
+		q6core_lcl.lp_ocm_payload.num_segments = nseg;
+		q6core_lcl.lp_ocm_payload.bandwidth = payload1[1];
 		for (i = 0, j = 2; i < nseg; i++) {
-			q6core_lcl.lp_ocm_payload->mem_segment[i].type =
+			q6core_lcl.lp_ocm_payload.mem_segment[i].type =
 					(payload1[j] & 0xffff);
-			q6core_lcl.lp_ocm_payload->mem_segment[i].category =
+			q6core_lcl.lp_ocm_payload.mem_segment[i].category =
 					((payload1[j++] >> 16) & 0xffff);
-			q6core_lcl.lp_ocm_payload->mem_segment[i].size =
+			q6core_lcl.lp_ocm_payload.mem_segment[i].size =
 					payload1[j++];
-			q6core_lcl.lp_ocm_payload->
+			q6core_lcl.lp_ocm_payload.
 				mem_segment[i].start_address_lsw =
 				payload1[j++];
-			q6core_lcl.lp_ocm_payload->
+			q6core_lcl.lp_ocm_payload.
 				mem_segment[i].start_address_msw =
 				payload1[j++];
 		}
@@ -152,7 +152,6 @@
 		struct avcs_cmd_rsp_get_low_power_segments_info_t **lp_memseg)
 {
 	struct avcs_cmd_get_low_power_segments_info lp_ocm_cmd;
-	u8 *cptr = NULL;
 	int ret = 0;
 
 	pr_debug("%s: ", __func__);
@@ -163,16 +162,6 @@
 		return -ENODEV;
 	}
 
-	cptr = kzalloc(
-		sizeof(struct avcs_cmd_rsp_get_low_power_segments_info_t),
-		GFP_KERNEL);
-	if (!cptr) {
-		pr_err("%s: Failed to allocate memory for low power segment struct\n",
-				__func__);
-		return -ENOMEM;
-	}
-	q6core_lcl.lp_ocm_payload =
-		(struct avcs_cmd_rsp_get_low_power_segments_info_t *) cptr;
 
 	lp_ocm_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
@@ -201,7 +190,7 @@
 		goto fail_cmd;
 	}
 
-	*lp_memseg = q6core_lcl.lp_ocm_payload;
+	*lp_memseg = &q6core_lcl.lp_ocm_payload;
 	return 0;
 
 fail_cmd:
@@ -215,14 +204,6 @@
 	q6core_lcl.bus_bw_resp_received = 0;
 
 	q6core_lcl.core_handle_q = NULL;
-	q6core_lcl.lp_ocm_payload = kzalloc(
-	sizeof(struct avcs_cmd_rsp_get_low_power_segments_info_t), GFP_KERNEL);
-
-	if (!q6core_lcl.lp_ocm_payload) {
-		pr_err("%s: Failed to allocate memory for low power segment struct\n",
-				__func__);
-		return -ENOMEM;
-	}
 
 	return 0;
 }
@@ -230,7 +211,7 @@
 
 static void __exit core_exit(void)
 {
-	kfree(q6core_lcl.lp_ocm_payload);
+
 }
 module_exit(core_exit);
 MODULE_DESCRIPTION("ADSP core driver");