Merge "arm/dt: msm8226: Change mount angle of OV9724"
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/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/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/configs/mpq8092_defconfig b/arch/arm/configs/mpq8092_defconfig
index 28ca32f..713691d 100644
--- a/arch/arm/configs/mpq8092_defconfig
+++ b/arch/arm/configs/mpq8092_defconfig
@@ -299,6 +299,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
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/Makefile b/arch/arm/mach-msm/Makefile
index 321040e..400f859 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
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-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 5173c12..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 (phys_addr_t) 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/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_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..30168b8 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"
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..9a5883f 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"
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..1945651 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);
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..c00f96f
--- /dev/null
+++ b/arch/arm/mach-msm/smem.c
@@ -0,0 +1,363 @@
+/* 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;
+
+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;
+
+	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) {
+		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);
+
+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..89b2b7b
--- /dev/null
+++ b/arch/arm/mach-msm/smem_private.h
@@ -0,0 +1,68 @@
+/* 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;
+
+#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);
+#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/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/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_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/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..b3b3b5e 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -437,6 +437,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 +463,7 @@
 	*result = *result * temp_var;
 
 	*result = div64_s64(*result, 1000000);
+	pr_debug("%lld compensated into %lld\n", old, *result);
 
 	return 0;
 }
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/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_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 756cb41..94041ea 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);
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/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 e03edd7..20cb08d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2541,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/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/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/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/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_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/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_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/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/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/kernel/sched/fair.c b/kernel/sched/fair.c
index 7e31770..a1bd252 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;
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/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");