Merge "ARM: dts: msm: Remove bus active-only property from TSPP"
diff --git a/Documentation/devicetree/bindings/arm/msm/smem.txt b/Documentation/devicetree/bindings/arm/msm/smem.txt
index a38984c..b6dcdc1 100644
--- a/Documentation/devicetree/bindings/arm/msm/smem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/smem.txt
@@ -10,6 +10,10 @@
 	     "aux-mem1", "aux-mem2", "aux-mem3", ... - optional strings to
 			identify any auxiliary shared memory regions
 
+Optional properties:
+-mpu-enabled : boolean value indicating that Memory Protection Unit based
+	security is enabled on the "smem" shared memory region
+
 [Second level nodes]
 
 qcom,smd
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 9ad8abe..9b30b39 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -63,6 +63,10 @@
 Optional properties:
 - qcom,mdss-dsi-panel-name:		A string used as a descriptive name of the panel
 - qcom,cont-splash-enabled:		Boolean used to enable continuous splash mode.
+					If this property is specified, it is required to
+					to specify the memory reserved for the splash
+					screen using the qcom,memblock-reserve binding
+					for the framebuffer device attached to the panel.
 - qcom,mdss-dsi-panel-broadcast-mode:	Boolean used to enable broadcast mode.
 - qcom,mdss-dsi-fbc-enable:		Boolean used to enable frame buffer compression mode.
 - qcom,mdss-dsi-fbc-bpp:		Compressed bpp supported by the panel.
@@ -116,6 +120,12 @@
 					0xff = default value.
 - qcom,mdss-dsi-border-color:		Defines the border color value if border is present.
 					0 = default value.
+- qcom,mdss-dsi-pan-enable-dynamic-fps:	Boolean used to enable change in frame rate dynamically.
+- qcom,mdss-dsi-pan-fps-update:		A string that specifies when to change the frame rate.
+					"dfps_suspend_resume_mode"= FPS change request is
+						implemented during suspend/resume.
+					"dfps_immediate_clk_mode" = FPS change request is
+						implemented immediately using DSI clocks.
 - qcom,mdss-dsi-bl-pmic-control-type:	A string that specifies the implementation of backlight
 					control for this panel.
 					"bl_ctrl_pwm" = Backlight controlled by PWM gpio.
@@ -232,7 +242,8 @@
 					in dsi controller.
 					"high" = Set GPIO to HIGH
 					"low" = Set GPIO to LOW
-
+- qcom,partial-update-enabled:		Boolean used to enable partial
+					panel update for command mode panels.
 
 Note, if a given optional qcom,* binding is not present, then the driver will configure
 the default values specified.
@@ -315,11 +326,14 @@
 		qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00];
 		qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+		qcom,mdss-dsi-pan-enable-dynamic-fps;
+		qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
 		qcom,mdss-dsi-bl-pmic-bank-select = <0>;
 		qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>;
 		qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>;
 		qcom,mdss-pan-physical-width-dimension = <60>;
 		qcom,mdss-pan-physical-height-dimension = <140>;
 		qcom,mdss-dsi-panel-mode-gpio-state = "low";
+		qcom,partial-update-enabled;
 	};
 };
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
index 829cce2..5a70b6b 100644
--- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt
@@ -163,6 +163,11 @@
 			 enabled if framebuffer size is less than max mixer
 			 width; 2) the defaut even split is enabled if frambuffer
 			 size is greater than max mixer width.
+- qcom,memblock-reserve: Specifies the memory location and the size reserved
+			 for the framebuffer used to display the splash screen.
+			 This property is required whenever the continuous splash
+			 screen feature is enabled for the corresponding
+			 framebuffer device.
 
 Example:
 	mdss_mdp: qcom,mdss_mdp@fd900000 {
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 58fc698..aa37edc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1854,6 +1854,11 @@
 
 config DONT_MAP_HOLE_AFTER_MEMBANK0
 	def_bool n
+	depends on ENABLE_VMALLOC_SAVING=n
+
+config ENABLE_VMALLOC_SAVING
+	def_bool n
+	depends on DONT_MAP_HOLE_AFTER_MEMBANK0=n
 
 config HOLES_IN_ZONE
 	def_bool n
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 0b98db7..021ddef 100644
--- a/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-toshiba-720p-video.dtsi
@@ -90,6 +90,7 @@
 		qcom,mdss-dsi-dma-trigger = <0x04>;
 		qcom,mdss-dsi-mdp-trigger = <0x0>;
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
-
+		qcom,mdss-dsi-pan-enable-dynamic-fps;
+		qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index d377bf0..3ebe225 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -104,7 +104,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,headset-jack-type-NO;
+		qcom,headset-jack-type-NC;
 	};
 
 	sound-9302 {
@@ -122,7 +122,7 @@
 
 		qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
 		qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
-		qcom,headset-jack-type-NO;
+		qcom,headset-jack-type-NC;
 	};
 };
 
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index 2ec7b6c..c7a4eee 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -49,6 +49,7 @@
 			compatible = "qcom,mdss-fb";
 			qcom,memory-reservation-type = "EBI1";
 			qcom,memory-reservation-size = <0x800000>;
+			qcom,memblock-reserve = <0x03200000 0xFA0000>;
 		};
 
 		mdss_fb1: qcom,mdss_fb_wfd {
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index cbafe80..d12f8c9 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -46,6 +46,29 @@
 		qcom,cdc-us-euro-gpios;
 	};
 
+    sound-9302 {
+          qcom,model = "msm8226-tapan9302-skuf-snd-card";
+
+          qcom,audio-routing =
+              "RX_BIAS", "MCLK",
+              "LDO_H", "MCLK",
+              "SPK_OUT", "MCLK",
+              "SPK_OUT", "EXT_VDD_SPKR",
+              "Lineout_1 amp", "LINEOUT1",
+              "Lineout_2 amp", "LINEOUT2",
+              "AMIC1", "MIC BIAS1 External",
+              "MIC BIAS1 External", "Handset Mic",
+              "AMIC2", "MIC BIAS2 External",
+              "MIC BIAS2 External", "Headset Mic",
+              "AMIC3", "MIC BIAS1 External",
+              "MIC BIAS1 External", "Handset Mic";
+
+          qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+          qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
+          qcom,cdc-vdd-spkr-gpios;
+          qcom,cdc-us-euro-gpios;
+      };
+
 	tp_power: regulator-tp {
 		compatible = "regulator-fixed";
 		regulator-name = "tp_power";
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index 77037be..9a750ae 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -46,6 +46,29 @@
 		qcom,cdc-us-euro-gpios;
 	};
 
+    sound-9302 {
+          qcom,model = "msm8226-tapan9302-skuf-snd-card";
+
+          qcom,audio-routing =
+              "RX_BIAS", "MCLK",
+              "LDO_H", "MCLK",
+              "SPK_OUT", "MCLK",
+              "SPK_OUT", "EXT_VDD_SPKR",
+              "Lineout_1 amp", "LINEOUT1",
+              "Lineout_2 amp", "LINEOUT2",
+              "AMIC1", "MIC BIAS1 External",
+              "MIC BIAS1 External", "Handset Mic",
+              "AMIC2", "MIC BIAS2 External",
+              "MIC BIAS2 External", "Headset Mic",
+              "AMIC3", "MIC BIAS1 External",
+              "MIC BIAS1 External", "Handset Mic";
+
+          qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+          qcom,cdc-lineout-spkr-gpios = <&pm8226_gpios 2 0>;
+          qcom,cdc-vdd-spkr-gpios;
+          qcom,cdc-us-euro-gpios;
+        };
+
 	tp_power: regulator-tp {
 		compatible = "regulator-fixed";
 		regulator-name = "tp_power";
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index 4e0ee32..452cc2f 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -76,21 +76,6 @@
 				];
 			};
 		};
-
-		synaptics@20 {
-			compatible = "synaptics,rmi4";
-			reg = <0x20>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <1 0x2008>;
-			vdd-supply = <&pm8110_l19>;
-			vcc_i2c-supply = <&pm8110_l14>;
-			synaptics,reset-gpio = <&msmgpio 0 0x00>;
-			synaptics,irq-gpio = <&msmgpio 1 0x2008>;
-			synaptics,button-map = <139 102 158>;
-			synaptics,i2c-pull-up;
-			synaptics,power-down;
-			synaptics,disable-gpios;
-		};
 	};
 
 	gen-vkeys {
diff --git a/arch/arm/boot/dts/msm8610-mdss.dtsi b/arch/arm/boot/dts/msm8610-mdss.dtsi
index f37a42b..de74e52 100644
--- a/arch/arm/boot/dts/msm8610-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8610-mdss.dtsi
@@ -20,6 +20,7 @@
 		mdss_fb0: qcom,mdss_fb_primary {
 			cell-index = <0>;
 			compatible = "qcom,mdss-fb";
+			qcom,memblock-reserve = <0x3200000 0x800000>;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 82f5aea..1cc3e61 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -76,21 +76,6 @@
 				];
 			};
 		};
-
-		synaptics@20 {
-			compatible = "synaptics,rmi4";
-			reg = <0x20>;
-			interrupt-parent = <&msmgpio>;
-			interrupts = <1 0x2008>;
-			vdd-supply = <&pm8110_l19>;
-			vcc_i2c-supply = <&pm8110_l14>;
-			synaptics,reset-gpio = <&msmgpio 0 0x00>;
-			synaptics,irq-gpio = <&msmgpio 1 0x2008>;
-			synaptics,button-map = <139 102 158>;
-			synaptics,i2c-pull-up;
-			synaptics,power-down;
-			synaptics,disable-gpios;
-		};
 	};
 
 	i2c@f9925000 {
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 24b5860..7181db2 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -64,6 +64,7 @@
 			compatible = "qcom,mdss-fb";
 			qcom,memory-reservation-type = "EBI1";
 			qcom,memory-reservation-size = <0x800000>;
+			qcom,memblock-reserve = <0x03200000 0x01E00000>;
 		};
 
 		mdss_fb1: qcom,mdss_fb_external {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index fd40cc6..3057e6e 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -77,7 +77,7 @@
 
 		adsp_mem: adsp_region {
 			linux,contiguous-region;
-			reg = <0 0x2F00000>;
+			reg = <0 0x3F00000>;
 			label = "adsp_mem";
 		};
 
@@ -220,7 +220,7 @@
 	qcom,vidc {
 		compatible = "qcom,msm-vidc";
 		qcom,hfi = "q6";
-		qcom,max-hw-load = <108000>; /* 720p @ 30 */
+		qcom,max-hw-load = <243000>; /* 1080p @ 30 */
 	};
 
 	qcom,wfd {
@@ -629,10 +629,10 @@
 			"MSM_TSIF1_PHYS",
 			"MSM_TSPP_PHYS",
 			"MSM_TSPP_BAM_PHYS";
-		interrupts = <0 153 0>, /* TSIF_TSPP_IRQ */
-			<0 151 0>, /* TSIF0_IRQ */
-			<0 152 0>, /* TSIF1_IRQ */
-			<0 154 0>; /* TSIF_BAM_IRQ */
+		interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */
+			<0 119 0>, /* TSIF0_IRQ */
+			<0 120 0>, /* TSIF1_IRQ */
+			<0 122 0>; /* TSIF_BAM_IRQ */
 		interrupt-names = "TSIF_TSPP_IRQ",
 			"TSIF0_IRQ",
 			"TSIF1_IRQ",
@@ -1560,7 +1560,8 @@
 
         memory_hole: qcom,msm-mem-hole {
                 compatible = "qcom,msm-mem-hole";
-                qcom,memblock-remove = <0x5d00000 0xa200000>; /* Address and Size of Hole */
+                qcom,memblock-remove = <0x5d00000 0x7d00000
+					0xfa00000 0x500000>; /* Address and Size of Hole */
         };
 
 	uart7: uart@f995d000 { /*BLSP #2, UART #7 */
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
index 237c9f9..e1d7605 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dts
@@ -126,7 +126,7 @@
 
 &sdhc_1 {
 	reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
-	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 400000000>;
+	qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 200000000 384000000>;
 	qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
 
 	qcom,pad-pull-on = <0x0 0x3 0x3 0x1>; /* no-pull, pull-up, pull-up, pull-down */
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index d11634b..f8369a9 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -82,6 +82,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index b03e4cd..816b020 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -83,6 +83,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 6683409..329fcec 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -94,6 +94,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -168,6 +169,7 @@
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
 CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_HELPER=y
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 60217b3..812faf6 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -100,6 +100,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_COMPACTION=y
+CONFIG_ENABLE_VMALLOC_SAVING=y
 CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_USE_OF=y
@@ -174,6 +175,7 @@
 CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
 CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
 CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
 CONFIG_NETFILTER_XT_MATCH_HELPER=y
 CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
diff --git a/arch/arm/mach-msm/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 65e22ae..da3cfba 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -49,7 +49,7 @@
 	[2] =  BW_MBPS(400), /* At least 50 MHz on bus. */
 	[3] =  BW_MBPS(800), /* At least 100 MHz on bus. */
 	[4] = BW_MBPS(1600), /* At least 200 MHz on bus. */
-	[5] = BW_MBPS(2128), /* At least 266 MHz on bus. */
+	[5] = BW_MBPS(2664), /* At least 333 MHz on bus. */
 };
 
 static struct msm_bus_scale_pdata bus_client_pdata = {
@@ -63,7 +63,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 0, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -74,7 +74,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -85,7 +85,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
@@ -99,7 +99,7 @@
 	{ 1,  300000, PLL0,    4, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  384000, ACPUPLL, 5, 2,   CPR_CORNER_SVS,    0, 4 },
 	{ 1,  600000, PLL0,    4, 0,   CPR_CORNER_NORMAL, 0, 6 },
-	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 7 },
+	{ 1,  787200, ACPUPLL, 5, 0,   CPR_CORNER_NORMAL, 0, 6 },
 	{ 1,  998400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1094400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
 	{ 1, 1190400, ACPUPLL, 5, 0,   CPR_CORNER_TURBO,  0, 7 },
diff --git a/arch/arm/mach-msm/acpuclock-8974.c b/arch/arm/mach-msm/acpuclock-8974.c
index 6d848d2..8410019 100644
--- a/arch/arm/mach-msm/acpuclock-8974.c
+++ b/arch/arm/mach-msm/acpuclock-8974.c
@@ -899,38 +899,460 @@
 	{ 0, { 0 } }
 };
 
-static struct acpu_level acpu_freq_tbl_pro_pvs0[] __initdata = {
-	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000, 999 },
-	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000, 999 },
-	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 999 },
-	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  805000, 999 },
-	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  815000, 999 },
-	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  825000, 999 },
-	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  835000, 999 },
-	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  845000, 999 },
-	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  855000, 999 },
-	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  865000, 999 },
-	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  875000, 999 },
-	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  890000, 999 },
-	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  900000, 999 },
-	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  915000, 999 },
-	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  925000, 999 },
-	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  940000, 999 },
-	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  950000, 999 },
-	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  965000, 999 },
-	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  980000, 999 },
-	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  995000, 999 },
-	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18), 1010000, 999 },
-	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1025000, 999 },
-	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1040000, 999 },
-	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1055000, 999 },
-	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1070000, 999 },
-	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1085000, 999 },
-	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1100000, 999 },
-	/* higher frequencies aren't available for bring up */
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  780000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  790000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  810000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  820000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  830000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  840000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  850000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  865000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  875000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  890000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  900000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  915000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  925000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  940000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  955000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  970000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  985000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18), 1000000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19), 1015000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1030000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1045000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1060000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1075000, 691 },
 	{ 0, { 0 } }
 };
 
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  785000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  795000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  805000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  815000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  825000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  835000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  850000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  860000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  870000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  885000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  895000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  905000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  920000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  935000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  950000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  965000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  980000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  995000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19), 1005000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1020000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1035000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1050000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72 },
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83 },
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101 },
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120 },
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  760000, 139 },
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  770000, 159 },
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  780000, 180 },
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  790000, 200 },
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 221 },
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  810000, 242 },
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  820000, 264 },
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  830000, 287 },
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  840000, 308 },
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  850000, 333 },
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  865000, 356 },
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  875000, 380 },
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  885000, 404 },
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  900000, 430 },
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  915000, 456 },
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  930000, 482 },
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  945000, 510 },
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  955000, 538 },
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  970000, 565 },
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 596 },
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  995000, 627 },
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1010000, 659 },
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1025000, 691 },
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  755000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  765000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  785000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  795000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  850000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  860000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  910000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  925000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  935000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  970000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  985000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1000000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  755000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  765000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  785000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  795000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  895000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  905000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  915000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  935000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  950000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  960000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  975000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  735000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  745000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  755000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  765000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  785000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  795000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  805000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  815000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  825000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  835000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  845000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  855000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  875000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  885000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  905000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  915000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  930000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  950000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p3g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  72},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  83},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 101},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 120},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 139},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 159},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  735000, 180},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  745000, 200},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  755000, 221},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  765000, 242},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 264},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  785000, 287},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  795000, 308},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  805000, 333},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  815000, 356},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  825000, 380},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  835000, 404},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  845000, 430},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 456},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  860000, 482},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  870000, 510},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 538},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  890000, 565},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  895000, 596},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  905000, 627},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 659},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  925000, 691},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs0[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  805000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  815000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  825000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  835000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  845000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  855000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  870000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  885000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  900000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  915000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  930000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  945000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  960000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  980000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19), 1000000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19), 1020000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1040000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1060000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1080000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1100000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs1[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  800000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  800000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  800000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  800000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  800000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  800000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  800000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  800000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  800000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  800000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  800000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  805000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  815000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  825000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  835000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  845000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  855000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  870000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  885000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  900000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  915000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  930000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  945000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  960000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  975000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  995000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19), 1015000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1035000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1055000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1075000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs2[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  780000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  790000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  800000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  810000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  820000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  830000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  840000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  850000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  865000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  880000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  895000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  910000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  925000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  940000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  955000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  970000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  990000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19), 1010000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1030000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1050000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs3[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  775000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  775000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  775000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  775000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  775000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  775000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  775000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  775000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  775000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  775000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  775000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  780000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  790000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  800000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  810000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  820000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  830000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  840000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  850000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  865000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  880000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  895000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  910000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  925000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  940000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  955000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  970000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  985000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19), 1005000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1025000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs4[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  760000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  770000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  780000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  790000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  800000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  810000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  820000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  830000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  840000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  850000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  865000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  880000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  895000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  910000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  925000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  940000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  955000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  970000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  985000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19), 1000000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs5[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  750000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  750000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  750000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  750000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  750000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  750000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  750000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  750000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  750000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  750000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  750000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  760000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  770000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  780000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  790000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  800000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  810000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  820000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  830000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  840000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  850000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  860000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  870000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  885000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  900000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  915000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  930000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  945000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  960000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  975000, 800},
+	{ 0, { 0 } }
+};
+
+static struct acpu_level acpu_ftbl_pro_2p5g_pvs6[] __initdata = {
+	{ 1, {  300000, PLL_0, 0,   0 },  L2(0),  725000,  76},
+	{ 0, {  345600, HFPLL, 2,  36 },  L2(1),  725000,  87},
+	{ 1, {  422400, HFPLL, 2,  44 },  L2(2),  725000, 106},
+	{ 0, {  499200, HFPLL, 2,  52 },  L2(2),  725000, 125},
+	{ 0, {  576000, HFPLL, 1,  30 },  L2(3),  725000, 145},
+	{ 1, {  652800, HFPLL, 1,  34 },  L2(3),  725000, 164},
+	{ 1, {  729600, HFPLL, 1,  38 },  L2(4),  725000, 183},
+	{ 0, {  806400, HFPLL, 1,  42 },  L2(4),  725000, 202},
+	{ 1, {  883200, HFPLL, 1,  46 },  L2(4),  725000, 222},
+	{ 1, {  960000, HFPLL, 1,  50 },  L2(9),  725000, 241},
+	{ 1, { 1036800, HFPLL, 1,  54 }, L2(10),  735000, 261},
+	{ 0, { 1113600, HFPLL, 1,  58 }, L2(10),  745000, 282},
+	{ 1, { 1190400, HFPLL, 1,  62 }, L2(10),  755000, 305},
+	{ 1, { 1267200, HFPLL, 1,  66 }, L2(13),  765000, 327},
+	{ 0, { 1344000, HFPLL, 1,  70 }, L2(14),  775000, 350},
+	{ 0, { 1420800, HFPLL, 1,  74 }, L2(15),  785000, 373},
+	{ 1, { 1497600, HFPLL, 1,  78 }, L2(16),  795000, 398},
+	{ 1, { 1574400, HFPLL, 1,  82 }, L2(17),  805000, 424},
+	{ 0, { 1651200, HFPLL, 1,  86 }, L2(17),  815000, 449},
+	{ 1, { 1728000, HFPLL, 1,  90 }, L2(18),  825000, 476},
+	{ 0, { 1804800, HFPLL, 1,  94 }, L2(18),  835000, 503},
+	{ 0, { 1881600, HFPLL, 1,  98 }, L2(18),  845000, 530},
+	{ 1, { 1958400, HFPLL, 1, 102 }, L2(19),  855000, 559},
+	{ 0, { 2035200, HFPLL, 1, 106 }, L2(19),  865000, 590},
+	{ 0, { 2112000, HFPLL, 1, 110 }, L2(19),  875000, 621},
+	{ 0, { 2188800, HFPLL, 1, 114 }, L2(19),  890000, 654},
+	{ 1, { 2265600, HFPLL, 1, 118 }, L2(19),  905000, 686},
+	{ 0, { 2342400, HFPLL, 1, 122 }, L2(19),  920000, 723},
+	{ 0, { 2419200, HFPLL, 1, 126 }, L2(19),  935000, 761},
+	{ 1, { 2496000, HFPLL, 1, 130 }, L2(19),  950000, 800},
+	{ 0, { 0 } }
+};
 
 static struct pvs_table pvs_v1[NUM_SPEED_BINS][NUM_PVS] __initdata = {
 	/* 8974v1 1.7GHz Parts */
@@ -974,45 +1396,45 @@
 };
 
 static struct pvs_table pvs_pro[NUM_SPEED_BINS][NUM_PVS] __initdata = {
-	/* Not used by 8974Pro */
-	[0][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[0][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.0 GHz is not used on 8974Pro */
+	[0][0] = { acpu_freq_tbl_2g_pvs0, sizeof(acpu_freq_tbl_2g_pvs0) },
+	[0][1] = { acpu_freq_tbl_2g_pvs1, sizeof(acpu_freq_tbl_2g_pvs1) },
+	[0][2] = { acpu_freq_tbl_2g_pvs2, sizeof(acpu_freq_tbl_2g_pvs2) },
+	[0][3] = { acpu_freq_tbl_2g_pvs3, sizeof(acpu_freq_tbl_2g_pvs3) },
+	[0][4] = { acpu_freq_tbl_2g_pvs4, sizeof(acpu_freq_tbl_2g_pvs4) },
+	[0][5] = { acpu_freq_tbl_2g_pvs5, sizeof(acpu_freq_tbl_2g_pvs5) },
+	[0][6] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
+	[0][7] = { acpu_freq_tbl_2g_pvs6, sizeof(acpu_freq_tbl_2g_pvs6) },
 
-	/* 8974Pro AB Bringup */
-	[1][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[1][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AB 2.3GHz */
+	[1][0] = { acpu_ftbl_pro_2p3g_pvs0, sizeof(acpu_ftbl_pro_2p3g_pvs0) },
+	[1][1] = { acpu_ftbl_pro_2p3g_pvs1, sizeof(acpu_ftbl_pro_2p3g_pvs1) },
+	[1][2] = { acpu_ftbl_pro_2p3g_pvs2, sizeof(acpu_ftbl_pro_2p3g_pvs2) },
+	[1][3] = { acpu_ftbl_pro_2p3g_pvs3, sizeof(acpu_ftbl_pro_2p3g_pvs3) },
+	[1][4] = { acpu_ftbl_pro_2p3g_pvs4, sizeof(acpu_ftbl_pro_2p3g_pvs4) },
+	[1][5] = { acpu_ftbl_pro_2p3g_pvs5, sizeof(acpu_ftbl_pro_2p3g_pvs5) },
+	[1][6] = { acpu_ftbl_pro_2p3g_pvs6, sizeof(acpu_ftbl_pro_2p3g_pvs6) },
+	[1][7] = { acpu_ftbl_pro_2p3g_pvs6, sizeof(acpu_ftbl_pro_2p3g_pvs6) },
 
-	/* Not used by 8974Pro */
-	[2][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[2][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 2.2GHz is not used on 8974Pro */
+	[2][0] = { acpu_freq_tbl_2p2g_pvs0, sizeof(acpu_freq_tbl_2p2g_pvs0) },
+	[2][1] = { acpu_freq_tbl_2p2g_pvs1, sizeof(acpu_freq_tbl_2p2g_pvs1) },
+	[2][2] = { acpu_freq_tbl_2p2g_pvs2, sizeof(acpu_freq_tbl_2p2g_pvs2) },
+	[2][3] = { acpu_freq_tbl_2p2g_pvs3, sizeof(acpu_freq_tbl_2p2g_pvs3) },
+	[2][4] = { acpu_freq_tbl_2p2g_pvs4, sizeof(acpu_freq_tbl_2p2g_pvs4) },
+	[2][5] = { acpu_freq_tbl_2p2g_pvs5, sizeof(acpu_freq_tbl_2p2g_pvs5) },
+	[2][6] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
+	[2][7] = { acpu_freq_tbl_2p2g_pvs6, sizeof(acpu_freq_tbl_2p2g_pvs6) },
 
-	/* 8974Pro Bringup */
-	[3][0] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][1] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][2] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][3] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][4] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][5] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][6] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
-	[3][7] = { acpu_freq_tbl_pro_pvs0, sizeof(acpu_freq_tbl_pro_pvs0) },
+	/* 8974Pro AC 2.5GHz */
+	[3][0] = { acpu_ftbl_pro_2p5g_pvs0, sizeof(acpu_ftbl_pro_2p5g_pvs0) },
+	[3][1] = { acpu_ftbl_pro_2p5g_pvs1, sizeof(acpu_ftbl_pro_2p5g_pvs1) },
+	[3][2] = { acpu_ftbl_pro_2p5g_pvs2, sizeof(acpu_ftbl_pro_2p5g_pvs2) },
+	[3][3] = { acpu_ftbl_pro_2p5g_pvs3, sizeof(acpu_ftbl_pro_2p5g_pvs3) },
+	[3][4] = { acpu_ftbl_pro_2p5g_pvs4, sizeof(acpu_ftbl_pro_2p5g_pvs4) },
+	[3][5] = { acpu_ftbl_pro_2p5g_pvs5, sizeof(acpu_ftbl_pro_2p5g_pvs5) },
+	[3][6] = { acpu_ftbl_pro_2p5g_pvs6, sizeof(acpu_ftbl_pro_2p5g_pvs6) },
+	[3][7] = { acpu_ftbl_pro_2p5g_pvs6, sizeof(acpu_ftbl_pro_2p5g_pvs6) },
 };
 
 static struct msm_bus_scale_pdata bus_scale_data __initdata = {
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index e9ad86f..87794c4 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -23,6 +23,11 @@
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_i2c_config = {
 	.func = GPIOMUX_FUNC_3,
@@ -247,25 +252,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
@@ -288,25 +297,29 @@
 	{
 		.gpio      = 86,		/* BLSP1 QUP4 SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 87,		/* BLSP1 QUP4 SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 89,		/* BLSP1 QUP4 SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 88,		/* BLSP1 QUP4 SPI_CS */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 };
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 31bcced..c35a607 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -143,6 +143,11 @@
 	.drv = GPIOMUX_DRV_12MA,
 	.pull = GPIOMUX_PULL_NONE,
 };
+static struct gpiomux_setting gpio_spi_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
 
 static struct gpiomux_setting gpio_spi_cs1_config = {
 	.func = GPIOMUX_FUNC_GPIO,
@@ -564,31 +569,36 @@
 	{
 		.gpio      = 0,		/* BLSP1 QUP SPI_DATA_MOSI */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 1,		/* BLSP1 QUP SPI_DATA_MISO */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 3,		/* BLSP1 QUP SPI_CLK */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 9,		/* BLSP1 QUP SPI_CS2A_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs2_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs2_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 	{
 		.gpio      = 8,		/* BLSP1 QUP SPI_CS1_N */
 		.settings = {
-			[GPIOMUX_SUSPENDED] = &gpio_spi_cs1_config,
+			[GPIOMUX_ACTIVE] = &gpio_spi_cs1_config,
+			[GPIOMUX_SUSPENDED] = &gpio_spi_susp_config,
 		},
 	},
 #endif
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 654dbd3..0e3310c 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -777,7 +777,7 @@
 	.base = &virt_bases[GCC_BASE],
 	.c = {
 		.parent = &cxo_clk_src.c,
-		.rate = 800000000,
+		.rate = 768000000,
 		.dbg_name = "gpll4_clk_src",
 		.ops = &clk_ops_pll_vote,
 		CLK_INIT(gpll4_clk_src.c),
@@ -1553,7 +1553,7 @@
 	F( 50000000,  gpll0,  12,   0,   0),
 	F(100000000,  gpll0,   6,   0,   0),
 	F(200000000,  gpll0,   3,   0,   0),
-	F(400000000,  gpll4,   2,   0,   0),
+	F(384000000,  gpll4,   2,   0,   0),
 	F_END
 };
 
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 3bb4c57..cf2df18 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -1398,7 +1398,8 @@
 {
 	int rc = 0;
 
-	if (vco_cached_rate != 0) {
+	if ((vco_cached_rate != 0)
+	    && (vco_cached_rate == c->rate)) {
 		rc = vco_set_rate(c, vco_cached_rate);
 		if (rc) {
 			pr_err("%s: vco_set_rate failed. rc=%d\n",
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index 59e0e2a..6ddf340 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -1274,10 +1274,6 @@
 			     quot[CPR_CORNER_NORMAL])
 					<= CPR_FUSE_MIN_QUOT_DIFF)
 				valid_fuse = false;
-			else if ((quot[CPR_CORNER_NORMAL] -
-				  quot[CPR_CORNER_SVS])
-					<= CPR_FUSE_MIN_QUOT_DIFF)
-				valid_fuse = false;
 		} else {
 			valid_fuse = false;
 		}
diff --git a/arch/arm/mach-msm/include/mach/msm_smem.h b/arch/arm/mach-msm/include/mach/msm_smem.h
index 5556db9..19f9c0e 100644
--- a/arch/arm/mach-msm/include/mach/msm_smem.h
+++ b/arch/arm/mach-msm/include/mach/msm_smem.h
@@ -26,6 +26,18 @@
 	NUM_SMEM_SUBSYSTEMS,
 };
 
+/*
+ * Flag options for the XXX_to_proc() API
+ *
+ * SMEM_ITEM_CACHED_FLAG - Indicates this operation should use cachable smem
+ *
+ * SMEM_ANY_HOST_FLAG - Indicates this operation should not apply to smem items
+ *                      which are limited to a specific host pairing.  Will
+ *                      cause this operation to ignore the to_proc parameter.
+ */
+#define SMEM_ITEM_CACHED_FLAG 1
+#define SMEM_ANY_HOST_FLAG 2
+
 #define SMEM_NUM_SMD_STREAM_CHANNELS        64
 
 enum {
@@ -145,6 +157,15 @@
 void *smem_get_entry(unsigned id, unsigned *size);
 void *smem_find(unsigned id, unsigned size);
 
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags);
+void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags);
+void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags);
+void *smem_get_entry_to_proc(unsigned id, unsigned *size, unsigned to_proc,
+								unsigned flags);
+
 /**
  * smem_get_entry_no_rlock - Get existing item without using remote spinlock
  *
@@ -193,6 +214,26 @@
 {
 	return NULL;
 }
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	return NULL;
+}
+static void *smem_get_entry_to_proc(unsigned id, unsigned *size,
+					unsigned to_proc, unsigned flags)
+{
+	return NULL;
+}
 void *smem_get_entry_no_rlock(unsigned id, unsigned *size_out)
 {
 	return NULL;
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index a8fed52..e2ff0f4 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -160,6 +160,10 @@
 		msg_id = ((struct qmi_header *)pend_txn->enc_data)->msg_id;
 		kfree(pend_txn->enc_data);
 		if (ret < 0) {
+			pr_err("%s: Sending transaction %d from port %d failed",
+				__func__, pend_txn->txn_id,
+				((struct msm_ipc_port *)handle->src_port)->
+							this_port.port_id);
 			if (pend_txn->type == QMI_ASYNC_TXN) {
 				pend_txn->resp_cb(pend_txn->handle,
 						msg_id, pend_txn->resp,
@@ -171,10 +175,6 @@
 				pend_txn->send_stat = ret;
 				wake_up(&pend_txn->wait_q);
 			}
-			pr_err("%s: Sending transaction %d from port %d failed",
-				__func__, pend_txn->txn_id,
-				((struct msm_ipc_port *)handle->src_port)->
-							this_port.port_id);
 		} else {
 			list_del(&pend_txn->list);
 			list_add_tail(&pend_txn->list, &handle->txn_list);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index b5ccc31..a13100b 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -887,7 +887,7 @@
 static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	int result = 0;
-	int size = vma->vm_end - vma->vm_start;
+	uint32_t size = vma->vm_end - vma->vm_start;
 
 	pr_debug("%s\n", __func__);
 
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index d34bdf2..110ab87 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -57,7 +57,7 @@
 
 #define SMD_VERSION 0x00020000
 #define SMSM_SNAPSHOT_CNT 64
-#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
+#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4 + sizeof(uint64_t))
 #define RSPIN_INIT_WAIT_MS 1000
 #define SMD_FIFO_FULL_RESERVE 4
 
@@ -144,49 +144,65 @@
 	SMSM_APPS_DEM_I = 3,
 };
 
-int msm_smd_debug_mask = MSM_SMx_POWER_INFO | MSM_SMD_INFO;
+int msm_smd_debug_mask = MSM_SMD_POWER_INFO | MSM_SMD_INFO |
+							MSM_SMSM_POWER_INFO;
 module_param_named(debug_mask, msm_smd_debug_mask,
 		   int, S_IRUGO | S_IWUSR | S_IWGRP);
 void *smd_log_ctx;
+void *smsm_log_ctx;
 #define NUM_LOG_PAGES 4
 
-#define IPC_LOG(level, x...) do { \
+#define IPC_LOG_SMD(level, x...) do { \
 	if (smd_log_ctx) \
 		ipc_log_string(smd_log_ctx, x); \
 	else \
 		printk(level x); \
 	} while (0)
 
+#define IPC_LOG_SMSM(level, x...) do { \
+	if (smsm_log_ctx) \
+		ipc_log_string(smsm_log_ctx, x); \
+	else \
+		printk(level x); \
+	} while (0)
+
 #if defined(CONFIG_MSM_SMD_DEBUG)
 #define SMD_DBG(x...) do {				\
 		if (msm_smd_debug_mask & MSM_SMD_DEBUG) \
-			IPC_LOG(KERN_DEBUG, x);		\
+			IPC_LOG_SMD(KERN_DEBUG, x);	\
 	} while (0)
 
 #define SMSM_DBG(x...) do {					\
 		if (msm_smd_debug_mask & MSM_SMSM_DEBUG)	\
-			IPC_LOG(KERN_DEBUG, x);		\
+			IPC_LOG_SMSM(KERN_DEBUG, x);		\
 	} while (0)
 
 #define SMD_INFO(x...) do {			 	\
 		if (msm_smd_debug_mask & MSM_SMD_INFO)	\
-			IPC_LOG(KERN_INFO, x);		\
+			IPC_LOG_SMD(KERN_INFO, x);	\
 	} while (0)
 
 #define SMSM_INFO(x...) do {				\
 		if (msm_smd_debug_mask & MSM_SMSM_INFO) \
-			IPC_LOG(KERN_INFO, x);		\
+			IPC_LOG_SMSM(KERN_INFO, x);	\
 	} while (0)
-#define SMx_POWER_INFO(x...) do {				\
-		if (msm_smd_debug_mask & MSM_SMx_POWER_INFO) \
-			IPC_LOG(KERN_INFO, x);		\
+
+#define SMD_POWER_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMD_POWER_INFO)	\
+			IPC_LOG_SMD(KERN_INFO, x);		\
+	} while (0)
+
+#define SMSM_POWER_INFO(x...) do {				\
+		if (msm_smd_debug_mask & MSM_SMSM_POWER_INFO)	\
+			IPC_LOG_SMSM(KERN_INFO, x);		\
 	} while (0)
 #else
 #define SMD_DBG(x...) do { } while (0)
 #define SMSM_DBG(x...) do { } while (0)
 #define SMD_INFO(x...) do { } while (0)
 #define SMSM_INFO(x...) do { } while (0)
-#define SMx_POWER_INFO(x...) do { } while (0)
+#define SMD_POWER_INFO(x...) do { } while (0)
+#define SMSM_POWER_INFO(x...) do { } while (0)
 #endif
 
 /**
@@ -200,8 +216,6 @@
 #define OVERFLOW_ADD_UNSIGNED(type, a, b) \
 	(((type)~0 - (a)) < (b) ? true : false)
 
-static unsigned last_heap_free = 0xffffffff;
-
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr);
 #ifndef INT_ADSP_A11_SMSM
@@ -223,6 +237,8 @@
 static int smd_stream_write_avail(struct smd_channel *ch);
 static int smd_stream_read_avail(struct smd_channel *ch);
 
+static bool pid_is_on_edge(uint32_t edge_num, unsigned pid);
+
 static inline void smd_write_intr(unsigned int val,
 				const void __iomem *addr)
 {
@@ -237,9 +253,9 @@
 	(void) subsys;
 
 	if (!ch)
-		SMx_POWER_INFO("Apps->%s\n", subsys);
+		SMD_POWER_INFO("Apps->%s\n", subsys);
 	else
-		SMx_POWER_INFO(
+		SMD_POWER_INFO(
 			"Apps->%s ch%d '%s': tx%d/rx%d %dr/%dw : %dr/%dw\n",
 			subsys, ch->n, ch->name,
 			ch->fifo_size -
@@ -322,7 +338,7 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_MODEM].smsm;
 
-	SMx_POWER_INFO("SMSM Apps->%s", "MODEM");
+	SMSM_POWER_INFO("SMSM Apps->%s", "MODEM");
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_MODEM].smsm_out_config_count;
@@ -336,7 +352,7 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_Q6].smsm;
 
-	SMx_POWER_INFO("SMSM Apps->%s", "ADSP");
+	SMSM_POWER_INFO("SMSM Apps->%s", "ADSP");
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_Q6].smsm_out_config_count;
@@ -350,7 +366,7 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_DSPS].smsm;
 
-	SMx_POWER_INFO("SMSM Apps->%s", "DSPS");
+	SMSM_POWER_INFO("SMSM Apps->%s", "DSPS");
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_DSPS].smsm_out_config_count;
@@ -364,7 +380,7 @@
 	static const struct interrupt_config_item *intr
 		= &private_intr_config[SMD_WCNSS].smsm;
 
-	SMx_POWER_INFO("SMSM Apps->%s", "WCNSS");
+	SMSM_POWER_INFO("SMSM Apps->%s", "WCNSS");
 
 	if (intr->out_base) {
 		++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
@@ -447,13 +463,15 @@
 	char *x;
 	int size;
 
-	x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
+	x = smem_find_to_proc(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG, 0,
+							SMEM_ANY_HOST_FLAG);
 	if (x != 0) {
 		x[SZ_DIAG_ERR_MSG - 1] = 0;
 		SMD_INFO("smem: DIAG '%s'\n", x);
 	}
 
-	x = smem_get_entry(SMEM_ERR_CRASH_LOG, &size);
+	x = smem_get_entry_to_proc(SMEM_ERR_CRASH_LOG, &size, 0,
+							SMEM_ANY_HOST_FLAG);
 	if (x != 0) {
 		x[size - 1] = 0;
 		pr_err("smem: CRASH LOG\n'%s'\n", x);
@@ -560,15 +578,17 @@
 static LIST_HEAD(smd_ch_closed_list);
 static LIST_HEAD(smd_ch_closing_list);
 static LIST_HEAD(smd_ch_to_close_list);
-static LIST_HEAD(smd_ch_list_modem);
-static LIST_HEAD(smd_ch_list_dsp);
-static LIST_HEAD(smd_ch_list_dsps);
-static LIST_HEAD(smd_ch_list_wcnss);
-static LIST_HEAD(smd_ch_list_rpm);
 
-/* 2 total supported tables of channels */
-static unsigned char smd_ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS * 2];
-static struct work_struct probe_work;
+struct remote_proc_info {
+	unsigned remote_pid;
+	unsigned free_space;
+	struct work_struct probe_work;
+	struct list_head ch_list;
+	/* 2 total supported tables of channels */
+	unsigned char ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS * 2];
+};
+
+static struct remote_proc_info remote_info[NUM_SMD_SUBSYSTEMS];
 
 static void finalize_channel_close_fn(struct work_struct *work);
 static DECLARE_WORK(finalize_channel_close_work, finalize_channel_close_fn);
@@ -576,7 +596,8 @@
 
 #define PRI_ALLOC_TBL 1
 #define SEC_ALLOC_TBL 2
-static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id);
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id,
+				struct remote_proc_info *r_info);
 
 static bool smd_edge_inited(int edge)
 {
@@ -594,19 +615,23 @@
  *
  * @shared: pointer to the table array in SMEM
  * @smd_ch_allocated: pointer to an array indicating already allocated channels
- * table_id: identifier for this channel allocation table
+ * @table_id: identifier for this channel allocation table
+ * @num_entries: number of entries in this allocation table
+ * @r_info: pointer to the info structure of the remote proc we care about
  *
  * The smd_probe_lock must be locked by the calling function.  Shared and
  * smd_ch_allocated are assumed to be valid pointers.
  */
 static void scan_alloc_table(struct smd_alloc_elm *shared,
 				char *smd_ch_allocated,
-				int table_id)
+				int table_id,
+				unsigned num_entries,
+				struct remote_proc_info *r_info)
 {
 	unsigned n;
 	uint32_t type;
 
-	for (n = 0; n < SMEM_NUM_SMD_STREAM_CHANNELS; n++) {
+	for (n = 0; n < num_entries; n++) {
 		if (smd_ch_allocated[n])
 			continue;
 
@@ -615,8 +640,8 @@
 		 * involved
 		 */
 		type = SMD_CHANNEL_TYPE(shared[n].type);
-		if (type >= ARRAY_SIZE(edge_to_pids) ||
-				edge_to_pids[type].local_pid != SMD_APPS)
+		if (!pid_is_on_edge(type, SMD_APPS) ||
+				!pid_is_on_edge(type, r_info->remote_pid))
 			continue;
 		if (!shared[n].ref_count)
 			continue;
@@ -625,17 +650,17 @@
 
 		if (!smd_initialized && !smd_edge_inited(type)) {
 			SMD_INFO(
-				"Probe skipping tbl %d, ch %d, edge not inited\n",
-				table_id, n);
+				"Probe skipping proc %d, tbl %d, ch %d, edge not inited\n",
+				r_info->remote_pid, table_id, n);
 			continue;
 		}
 
-		if (!smd_alloc_channel(&shared[n], table_id))
+		if (!smd_alloc_channel(&shared[n], table_id, r_info))
 			smd_ch_allocated[n] = 1;
 		else
 			SMD_INFO(
-				"Probe skipping tbl %d, ch %d, not allocated\n",
-				table_id, n);
+				"Probe skipping proc %d, tbl %d, ch %d, not allocated\n",
+				r_info->remote_pid, table_id, n);
 	}
 }
 
@@ -650,9 +675,13 @@
 static void smd_channel_probe_worker(struct work_struct *work)
 {
 	struct smd_alloc_elm *shared;
+	struct remote_proc_info *r_info;
+	unsigned tbl_size;
 
-	shared = smem_find(ID_CH_ALLOC_TBL,
-				sizeof(*shared) * SMEM_NUM_SMD_STREAM_CHANNELS);
+	r_info = container_of(work, struct remote_proc_info, probe_work);
+
+	shared = smem_get_entry_to_proc(ID_CH_ALLOC_TBL, &tbl_size,
+							r_info->remote_pid, 0);
 
 	if (!shared) {
 		pr_err("%s: allocation table not initialized\n", __func__);
@@ -661,71 +690,50 @@
 
 	mutex_lock(&smd_probe_lock);
 
-	scan_alloc_table(shared, smd_ch_allocated, PRI_ALLOC_TBL);
+	scan_alloc_table(shared, r_info->ch_allocated, PRI_ALLOC_TBL,
+						tbl_size / sizeof(*shared),
+						r_info);
 
-	shared = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
-			sizeof(*shared) * SMEM_NUM_SMD_STREAM_CHANNELS);
+	shared = smem_get_entry_to_proc(SMEM_CHANNEL_ALLOC_TBL_2, &tbl_size,
+							r_info->remote_pid, 0);
 	if (shared)
 		scan_alloc_table(shared,
-			&(smd_ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS]),
-			SEC_ALLOC_TBL);
+			&(r_info->ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS]),
+			SEC_ALLOC_TBL,
+			tbl_size / sizeof(*shared),
+			r_info);
 
 	mutex_unlock(&smd_probe_lock);
 }
 
 /**
- * Lookup processor ID and determine if it belongs to the proved edge
- * type.
+ * get_remote_ch() - gathers remote channel info
  *
  * @shared2:   Pointer to v2 shared channel structure
  * @type:      Edge type
  * @pid:       Processor ID of processor on edge
- * @local_ch:  Channel that belongs to processor @pid
- * @remote_ch: Other side of edge contained @pid
+ * @remote_ch:  Channel that belongs to processor @pid
  * @is_word_access_ch: Bool, is this a word aligned access channel
  *
- * Returns 0 for not on edge, 1 for found on edge
+ * @returns:		0 on success, error code on failure
  */
-static int pid_is_on_edge(void *shared2,
+static int get_remote_ch(void *shared2,
 		uint32_t type, uint32_t pid,
-		void **local_ch,
 		void **remote_ch,
 		int is_word_access_ch
 		)
 {
-	int ret = 0;
-	struct edge_to_pid *edge;
-	void *ch0;
-	void *ch1;
+	if (!remote_ch || !shared2 || !pid_is_on_edge(type, pid) ||
+				!pid_is_on_edge(type, SMD_APPS))
+		return -EINVAL;
 
-	*local_ch = 0;
-	*remote_ch = 0;
+	if (is_word_access_ch)
+		*remote_ch =
+			&((struct smd_shared_v2_word_access *)(shared2))->ch1;
+	else
+		*remote_ch = &((struct smd_shared_v2 *)(shared2))->ch1;
 
-	if (!shared2 || (type >= ARRAY_SIZE(edge_to_pids)))
-		return 0;
-
-	if (is_word_access_ch) {
-		ch0 = &((struct smd_shared_v2_word_access *)(shared2))->ch0;
-		ch1 = &((struct smd_shared_v2_word_access *)(shared2))->ch1;
-	} else {
-		ch0 = &((struct smd_shared_v2 *)(shared2))->ch0;
-		ch1 = &((struct smd_shared_v2 *)(shared2))->ch1;
-	}
-
-	edge = &edge_to_pids[type];
-	if (edge->local_pid != edge->remote_pid) {
-		if (pid == edge->local_pid) {
-			*local_ch = ch0;
-			*remote_ch = ch1;
-			ret = 1;
-		} else if (pid == edge->remote_pid) {
-			*local_ch = ch1;
-			*remote_ch = ch0;
-			ret = 1;
-		}
-	}
-
-	return ret;
+	return 0;
 }
 
 /**
@@ -825,13 +833,25 @@
 	}
 }
 
+/**
+ * smd_channel_reset_state() - find channels in an allocation table and set them
+ *				to the specified state
+ *
+ * @shared:	Pointer to the allocation table to scan
+ * @table_id:	ID of the table
+ * @new_state:	New state that channels should be set to
+ * @pid:	Processor ID of the remote processor for the channels
+ * @num_entries: Number of entries in the table
+ *
+ * Scan the indicated table for channels between Apps and @pid.  If a valid
+ * channel is found, set the remote side of the channel to @new_state.
+ */
 static void smd_channel_reset_state(struct smd_alloc_elm *shared, int table_id,
-		unsigned new_state, unsigned pid)
+		unsigned new_state, unsigned pid, unsigned num_entries)
 {
 	unsigned n;
 	void *shared2;
 	uint32_t type;
-	void *local_ch;
 	void *remote_ch;
 	int is_word_access;
 	unsigned base_id;
@@ -848,7 +868,7 @@
 		return;
 	}
 
-	for (n = 0; n < SMD_CHANNELS; n++) {
+	for (n = 0; n < num_entries; n++) {
 		if (!shared[n].ref_count)
 			continue;
 		if (!shared[n].name[0])
@@ -857,45 +877,59 @@
 		type = SMD_CHANNEL_TYPE(shared[n].type);
 		is_word_access = is_word_access_ch(type);
 		if (is_word_access)
-			shared2 = smem_alloc(base_id + n,
-				sizeof(struct smd_shared_v2_word_access));
+			shared2 = smem_find_to_proc(base_id + n,
+				sizeof(struct smd_shared_v2_word_access), pid,
+				0);
 		else
-			shared2 = smem_alloc(base_id + n,
-				sizeof(struct smd_shared_v2));
+			shared2 = smem_find_to_proc(base_id + n,
+				sizeof(struct smd_shared_v2), pid, 0);
 		if (!shared2)
 			continue;
 
-		if (pid_is_on_edge(shared2, type, pid, &local_ch, &remote_ch,
-							is_word_access))
-			smd_reset_edge(local_ch, new_state, is_word_access);
-
-		/*
-		 * ModemFW is in the same subsystem as ModemSW, but has
-		 * separate SMD edges that need to be reset.
-		 */
-		if (pid == SMSM_MODEM &&
-				pid_is_on_edge(shared2, type, SMD_MODEM_Q6_FW,
-				 &local_ch, &remote_ch, is_word_access))
-			smd_reset_edge(local_ch, new_state, is_word_access);
+		if (!get_remote_ch(shared2, type, pid,
+					&remote_ch, is_word_access))
+			smd_reset_edge(remote_ch, new_state, is_word_access);
 	}
 }
 
+/**
+ * pid_is_on_edge() - checks to see if the processor with id pid is on the
+ * edge specified by edge_num
+ *
+ * @edge_num:		the number of the edge which is being tested
+ * @pid:		the id of the processor being tested
+ *
+ * @returns:		true if on edge, false otherwise
+ */
+static bool pid_is_on_edge(uint32_t edge_num, unsigned pid)
+{
+	struct edge_to_pid edge;
+
+	if (edge_num >= ARRAY_SIZE(edge_to_pids))
+		return 0;
+
+	edge = edge_to_pids[edge_num];
+	return (edge.local_pid == pid || edge.remote_pid == pid);
+}
 
 void smd_channel_reset(uint32_t restart_pid)
 {
 	struct smd_alloc_elm *shared_pri;
 	struct smd_alloc_elm *shared_sec;
 	unsigned long flags;
+	unsigned pri_size;
+	unsigned sec_size;
 
-	SMx_POWER_INFO("%s: starting reset\n", __func__);
+	SMD_POWER_INFO("%s: starting reset\n", __func__);
 
-	shared_pri = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared_pri) * 64);
+	shared_pri = smem_get_entry_to_proc(ID_CH_ALLOC_TBL, &pri_size,
+								restart_pid, 0);
 	if (!shared_pri) {
 		pr_err("%s: allocation table not initialized\n", __func__);
 		return;
 	}
-	shared_sec = smem_find(SMEM_CHANNEL_ALLOC_TBL_2,
-						sizeof(*shared_sec) * 64);
+	shared_sec = smem_get_entry_to_proc(SMEM_CHANNEL_ALLOC_TBL_2, &sec_size,
+								restart_pid, 0);
 
 	/* reset SMSM entry */
 	if (smsm_info.state) {
@@ -920,43 +954,33 @@
 	mutex_lock(&smd_probe_lock);
 	spin_lock_irqsave(&smd_lock, flags);
 	smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSING,
-								restart_pid);
+				restart_pid, pri_size / sizeof(*shared_pri));
 	if (shared_sec)
 		smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
-						SMD_SS_CLOSING, restart_pid);
+						SMD_SS_CLOSING, restart_pid,
+						sec_size / sizeof(*shared_sec));
 	spin_unlock_irqrestore(&smd_lock, flags);
 	mutex_unlock(&smd_probe_lock);
 
-	/* notify SMD processors */
 	mb();
 	smd_fake_irq_handler(0);
-	notify_modem_smd(NULL);
-	notify_dsp_smd(NULL);
-	notify_dsps_smd(NULL);
-	notify_wcnss_smd(NULL);
-	notify_rpm_smd(NULL);
 
 	/* change all remote states to CLOSED */
 	mutex_lock(&smd_probe_lock);
 	spin_lock_irqsave(&smd_lock, flags);
 	smd_channel_reset_state(shared_pri, PRI_ALLOC_TBL, SMD_SS_CLOSED,
-								restart_pid);
+				restart_pid, pri_size / sizeof(*shared_pri));
 	if (shared_sec)
 		smd_channel_reset_state(shared_sec, SEC_ALLOC_TBL,
-						SMD_SS_CLOSED, restart_pid);
+						SMD_SS_CLOSED, restart_pid,
+						sec_size / sizeof(*shared_sec));
 	spin_unlock_irqrestore(&smd_lock, flags);
 	mutex_unlock(&smd_probe_lock);
 
-	/* notify SMD processors */
 	mb();
 	smd_fake_irq_handler(0);
-	notify_modem_smd(NULL);
-	notify_dsp_smd(NULL);
-	notify_dsps_smd(NULL);
-	notify_wcnss_smd(NULL);
-	notify_rpm_smd(NULL);
 
-	SMx_POWER_INFO("%s: finished reset\n", __func__);
+	SMD_POWER_INFO("%s: finished reset\n", __func__);
 }
 
 /* how many bytes are available for reading */
@@ -1157,15 +1181,33 @@
 	ch->notify_other_cpu(ch);
 }
 
-static void do_smd_probe(void)
+/**
+ * do_smd_probe() - Look for newly created SMD channels a specific processor
+ *
+ * @remote_pid: remote processor id of the proc that may have created channels
+ */
+static void do_smd_probe(unsigned remote_pid)
 {
-	struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
-	if (shared->heap_info.free_offset != last_heap_free) {
-		last_heap_free = shared->heap_info.free_offset;
-		schedule_work(&probe_work);
+	unsigned free_space;
+
+	free_space = smem_get_free_space(remote_pid);
+	if (free_space != remote_info[remote_pid].free_space) {
+		remote_info[remote_pid].free_space = free_space;
+		schedule_work(&remote_info[remote_pid].probe_work);
 	}
 }
 
+/**
+ * do_smd_probe() - Look for newly created SMD channels from any remote proc
+ */
+static void do_smd_probe_all(void)
+{
+	int i;
+
+	for (i = 1; i < NUM_SMD_SUBSYSTEMS; ++i)
+		do_smd_probe(i);
+}
+
 static void smd_state_change(struct smd_channel *ch,
 			     unsigned last, unsigned next)
 {
@@ -1230,7 +1272,7 @@
 	spin_unlock_irqrestore(&smd_lock, flags);
 }
 
-static void handle_smd_irq(struct list_head *list,
+static void handle_smd_irq(struct remote_proc_info *r_info,
 		void (*notify)(smd_channel_t *ch))
 {
 	unsigned long flags;
@@ -1238,6 +1280,9 @@
 	unsigned ch_flags;
 	unsigned tmp;
 	unsigned char state_change;
+	struct list_head *list;
+
+	list = &r_info->ch_list;
 
 	spin_lock_irqsave(&smd_lock, flags);
 	list_for_each_entry(ch, list, ch_list) {
@@ -1259,14 +1304,14 @@
 		}
 		tmp = ch->half_ch->get_state(ch->recv);
 		if (tmp != ch->last_state) {
-			SMx_POWER_INFO("SMD ch%d '%s' State change %d->%d\n",
+			SMD_POWER_INFO("SMD ch%d '%s' State change %d->%d\n",
 					ch->n, ch->name, ch->last_state, tmp);
 			smd_state_change(ch, ch->last_state, tmp);
 			state_change = 1;
 		}
 		if (ch_flags & 0x3) {
 			ch->update_state(ch);
-			SMx_POWER_INFO(
+			SMD_POWER_INFO(
 				"SMD ch%d '%s' Data event 0x%x tx%d/rx%d %dr/%dw : %dr/%dw\n",
 				ch->n, ch->name,
 				ch_flags,
@@ -1281,13 +1326,13 @@
 			ch->notify(ch->priv, SMD_EVENT_DATA);
 		}
 		if (ch_flags & 0x4 && !state_change) {
-			SMx_POWER_INFO("SMD ch%d '%s' State update\n",
+			SMD_POWER_INFO("SMD ch%d '%s' State update\n",
 					ch->n, ch->name);
 			ch->notify(ch->priv, SMD_EVENT_STATUS);
 		}
 	}
 	spin_unlock_irqrestore(&smd_lock, flags);
-	do_smd_probe();
+	do_smd_probe(r_info->remote_pid);
 }
 
 static inline void log_irq(uint32_t subsystem)
@@ -1296,14 +1341,14 @@
 
 	(void) subsys;
 
-	SMx_POWER_INFO("SMD Int %s->Apps\n", subsys);
+	SMD_POWER_INFO("SMD Int %s->Apps\n", subsys);
 }
 
 irqreturn_t smd_modem_irq_handler(int irq, void *data)
 {
 	log_irq(SMD_APPS_MODEM);
 	++interrupt_stats[SMD_MODEM].smd_in_count;
-	handle_smd_irq(&smd_ch_list_modem, notify_modem_smd);
+	handle_smd_irq(&remote_info[SMD_MODEM], notify_modem_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
@@ -1312,7 +1357,7 @@
 {
 	log_irq(SMD_APPS_QDSP);
 	++interrupt_stats[SMD_Q6].smd_in_count;
-	handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
+	handle_smd_irq(&remote_info[SMD_Q6], notify_dsp_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
@@ -1321,7 +1366,7 @@
 {
 	log_irq(SMD_APPS_DSPS);
 	++interrupt_stats[SMD_DSPS].smd_in_count;
-	handle_smd_irq(&smd_ch_list_dsps, notify_dsps_smd);
+	handle_smd_irq(&remote_info[SMD_DSPS], notify_dsps_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
@@ -1330,7 +1375,7 @@
 {
 	log_irq(SMD_APPS_WCNSS);
 	++interrupt_stats[SMD_WCNSS].smd_in_count;
-	handle_smd_irq(&smd_ch_list_wcnss, notify_wcnss_smd);
+	handle_smd_irq(&remote_info[SMD_WCNSS], notify_wcnss_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
@@ -1339,18 +1384,18 @@
 {
 	log_irq(SMD_APPS_RPM);
 	++interrupt_stats[SMD_RPM].smd_in_count;
-	handle_smd_irq(&smd_ch_list_rpm, notify_rpm_smd);
+	handle_smd_irq(&remote_info[SMD_RPM], notify_rpm_smd);
 	handle_smd_irq_closing_list();
 	return IRQ_HANDLED;
 }
 
 static void smd_fake_irq_handler(unsigned long arg)
 {
-	handle_smd_irq(&smd_ch_list_modem, notify_modem_smd);
-	handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
-	handle_smd_irq(&smd_ch_list_dsps, notify_dsps_smd);
-	handle_smd_irq(&smd_ch_list_wcnss, notify_wcnss_smd);
-	handle_smd_irq(&smd_ch_list_rpm, notify_rpm_smd);
+	handle_smd_irq(&remote_info[SMD_MODEM], notify_modem_smd);
+	handle_smd_irq(&remote_info[SMD_Q6], notify_dsp_smd);
+	handle_smd_irq(&remote_info[SMD_DSPS], notify_dsps_smd);
+	handle_smd_irq(&remote_info[SMD_WCNSS], notify_wcnss_smd);
+	handle_smd_irq(&remote_info[SMD_RPM], notify_rpm_smd);
 	handle_smd_irq_closing_list();
 }
 
@@ -1376,32 +1421,32 @@
 	int need_int = 0;
 
 	spin_lock_irqsave(&smd_lock, flags);
-	list_for_each_entry(ch, &smd_ch_list_modem, ch_list) {
+	list_for_each_entry(ch, &remote_info[SMD_MODEM].ch_list, ch_list) {
 		if (smd_need_int(ch)) {
 			need_int = 1;
 			break;
 		}
 	}
-	list_for_each_entry(ch, &smd_ch_list_dsp, ch_list) {
+	list_for_each_entry(ch, &remote_info[SMD_Q6].ch_list, ch_list) {
 		if (smd_need_int(ch)) {
 			need_int = 1;
 			break;
 		}
 	}
-	list_for_each_entry(ch, &smd_ch_list_dsps, ch_list) {
+	list_for_each_entry(ch, &remote_info[SMD_DSPS].ch_list, ch_list) {
 		if (smd_need_int(ch)) {
 			need_int = 1;
 			break;
 		}
 	}
-	list_for_each_entry(ch, &smd_ch_list_wcnss, ch_list) {
+	list_for_each_entry(ch, &remote_info[SMD_WCNSS].ch_list, ch_list) {
 		if (smd_need_int(ch)) {
 			need_int = 1;
 			break;
 		}
 	}
 	spin_unlock_irqrestore(&smd_lock, flags);
-	do_smd_probe();
+	do_smd_probe_all();
 
 	if (need_int) {
 		SMD_DBG("smd_sleep_exit need interrupt\n");
@@ -1582,12 +1627,14 @@
  * @ch: pointer to the local structure for this channel
  * @table_id: the id of the table this channel resides in. 1 = first table, 2 =
  *		second table, etc
+ * @r_info: pointer to the info structure of the remote proc for this channel
  * @returns: -EINVAL for failure; 0 for success
  *
  * ch must point to an allocated instance of struct smd_channel that is zeroed
  * out, and has the n and type members already initialized to the correct values
  */
-static int smd_alloc_v2(struct smd_channel *ch, int table_id)
+static int smd_alloc_v2(struct smd_channel *ch, int table_id,
+						struct remote_proc_info *r_info)
 {
 	void *buffer;
 	unsigned buffer_sz;
@@ -1610,7 +1657,8 @@
 
 	if (is_word_access_ch(ch->type)) {
 		struct smd_shared_v2_word_access *shared2;
-		shared2 = smem_alloc(base_id + ch->n, sizeof(*shared2));
+		shared2 = smem_alloc_to_proc(base_id + ch->n, sizeof(*shared2),
+							r_info->remote_pid, 0);
 		if (!shared2) {
 			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
 			return -EINVAL;
@@ -1619,7 +1667,8 @@
 		ch->recv = &shared2->ch1;
 	} else {
 		struct smd_shared_v2 *shared2;
-		shared2 = smem_alloc(base_id + ch->n, sizeof(*shared2));
+		shared2 = smem_alloc_to_proc(base_id + ch->n, sizeof(*shared2),
+							r_info->remote_pid, 0);
 		if (!shared2) {
 			SMD_INFO("smem_alloc failed ch=%d\n", ch->n);
 			return -EINVAL;
@@ -1629,7 +1678,8 @@
 	}
 	ch->half_ch = get_half_ch_funcs(ch->type);
 
-	buffer = smem_get_entry(fifo_id + ch->n, &buffer_sz);
+	buffer = smem_get_entry_to_proc(fifo_id + ch->n, &buffer_sz,
+							r_info->remote_pid, 0);
 	if (!buffer) {
 		SMD_INFO("smem_get_entry failed\n");
 		return -EINVAL;
@@ -1654,7 +1704,8 @@
 }
 
 #else /* define v1 for older targets */
-static int smd_alloc_v2(struct smd_channel *ch, int table_id)
+static int smd_alloc_v2(struct smd_channel *ch, int table_id,
+						struct remote_proc_info *r_info)
 {
 	return -EINVAL;
 }
@@ -1662,7 +1713,8 @@
 static int smd_alloc_v1(struct smd_channel *ch)
 {
 	struct smd_shared_v1 *shared1;
-	shared1 = smem_alloc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1));
+	shared1 = smem_alloc_to_proc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1),
+							0, SMEM_ANY_HOST_FLAG);
 	if (!shared1) {
 		pr_err("smd_alloc_channel() cid %d does not exist\n", ch->n);
 		return -EINVAL;
@@ -1685,9 +1737,11 @@
  * @alloc_elm: the allocation element stored in SMEM for this channel
  * @table_id: the id of the table this channel resides in. 1 = first table, 2 =
  *		seconds table, etc
+ * @r_info: pointer to the info structure of the remote proc for this channel
  * @returns: -1 for failure; 0 for success
  */
-static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id)
+static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id,
+				struct remote_proc_info *r_info)
 {
 	struct smd_channel *ch;
 
@@ -1699,7 +1753,7 @@
 	ch->n = alloc_elm->cid;
 	ch->type = SMD_CHANNEL_TYPE(alloc_elm->type);
 
-	if (smd_alloc_v2(ch, table_id) && smd_alloc_v1(ch)) {
+	if (smd_alloc_v2(ch, table_id, r_info) && smd_alloc_v1(ch)) {
 		kfree(ch);
 		return -1;
 	}
@@ -1922,18 +1976,11 @@
 	SMD_DBG("smd_open: opening '%s'\n", ch->name);
 
 	spin_lock_irqsave(&smd_lock, flags);
-	if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_MODEM)
-		list_add(&ch->ch_list, &smd_ch_list_modem);
-	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_QDSP)
-		list_add(&ch->ch_list, &smd_ch_list_dsp);
-	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_DSPS)
-		list_add(&ch->ch_list, &smd_ch_list_dsps);
-	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_WCNSS)
-		list_add(&ch->ch_list, &smd_ch_list_wcnss);
-	else if (SMD_CHANNEL_TYPE(ch->type) == SMD_APPS_RPM)
-		list_add(&ch->ch_list, &smd_ch_list_rpm);
-	else
+	if (unlikely(ch->type == SMD_LOOPBACK_TYPE))
 		list_add(&ch->ch_list, &smd_ch_list_loopback);
+	else
+		list_add(&ch->ch_list,
+		       &remote_info[edge_to_pids[ch->type].remote_pid].ch_list);
 
 	SMD_DBG("%s: opening ch %d\n", __func__, ch->n);
 
@@ -2232,11 +2279,11 @@
 		return -ENODEV;
 
 	if (mask) {
-		SMx_POWER_INFO("SMD Masking interrupts from %s\n",
+		SMD_POWER_INFO("SMD Masking interrupts from %s\n",
 				edge_to_pids[ch->type].subsys_name);
 		irq_chip->irq_mask(irq_data);
 	} else {
-		SMx_POWER_INFO("SMD Unmasking interrupts from %s\n",
+		SMD_POWER_INFO("SMD Unmasking interrupts from %s\n",
 				edge_to_pids[ch->type].subsys_name);
 		irq_chip->irq_unmask(irq_data);
 	}
@@ -2405,8 +2452,9 @@
 	}
 	remote_spin_unlock_irqrestore(remote_spinlock, flags);
 
-	smsm_size_info = smem_alloc(SMEM_SMSM_SIZE_INFO,
-				sizeof(struct smsm_size_info_type));
+	smsm_size_info = smem_alloc_to_proc(SMEM_SMSM_SIZE_INFO,
+				sizeof(struct smsm_size_info_type), 0,
+				SMEM_ANY_HOST_FLAG);
 	if (smsm_size_info) {
 		SMSM_NUM_ENTRIES = smsm_size_info->num_entries;
 		SMSM_NUM_HOSTS = smsm_size_info->num_hosts;
@@ -2423,9 +2471,10 @@
 			"smsm_snapshot");
 
 	if (!smsm_info.state) {
-		smsm_info.state = smem_alloc2(ID_SHARED_STATE,
-					      SMSM_NUM_ENTRIES *
-					      sizeof(uint32_t));
+		smsm_info.state = smem_alloc2_to_proc(ID_SHARED_STATE,
+						SMSM_NUM_ENTRIES *
+						sizeof(uint32_t), 0,
+						SMEM_ANY_HOST_FLAG);
 
 		if (smsm_info.state) {
 			__raw_writel(0, SMSM_STATE_ADDR(SMSM_APPS_STATE));
@@ -2436,10 +2485,12 @@
 	}
 
 	if (!smsm_info.intr_mask) {
-		smsm_info.intr_mask = smem_alloc2(SMEM_SMSM_CPU_INTR_MASK,
-						  SMSM_NUM_ENTRIES *
-						  SMSM_NUM_HOSTS *
-						  sizeof(uint32_t));
+		smsm_info.intr_mask = smem_alloc2_to_proc(
+						SMEM_SMSM_CPU_INTR_MASK,
+						SMSM_NUM_ENTRIES *
+						SMSM_NUM_HOSTS *
+						sizeof(uint32_t), 0,
+						SMEM_ANY_HOST_FLAG);
 
 		if (smsm_info.intr_mask) {
 			for (i = 0; i < SMSM_NUM_ENTRIES; i++)
@@ -2454,9 +2505,10 @@
 	}
 
 	if (!smsm_info.intr_mux)
-		smsm_info.intr_mux = smem_alloc2(SMEM_SMD_SMSM_INTR_MUX,
-						 SMSM_NUM_INTR_MUX *
-						 sizeof(uint32_t));
+		smsm_info.intr_mux = smem_alloc2_to_proc(SMEM_SMD_SMSM_INTR_MUX,
+							SMSM_NUM_INTR_MUX *
+							sizeof(uint32_t), 0,
+							SMEM_ANY_HOST_FLAG);
 
 	i = smsm_cb_init();
 	if (i)
@@ -2509,7 +2561,9 @@
 	uint32_t new_state;
 	unsigned long flags;
 	int ret;
+	uint64_t timestamp;
 
+	timestamp = sched_clock();
 	ret = kfifo_avail(&smsm_snapshot_fifo);
 	if (ret < SMSM_SNAPSHOT_SIZE) {
 		pr_err("%s: SMSM snapshot full %d\n", __func__, ret);
@@ -2532,7 +2586,7 @@
 	if (use_wakelock) {
 		spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
 		if (smsm_snapshot_count == 0) {
-			SMx_POWER_INFO("SMSM snapshot wake lock\n");
+			SMSM_POWER_INFO("SMSM snapshot wake lock\n");
 			wake_lock(&smsm_snapshot_wakelock);
 		}
 		++smsm_snapshot_count;
@@ -2551,6 +2605,12 @@
 		}
 	}
 
+	ret = kfifo_in(&smsm_snapshot_fifo, &timestamp, sizeof(timestamp));
+	if (ret != sizeof(timestamp)) {
+		pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+		goto restore_snapshot_count;
+	}
+
 	/* queue wakelock usage flag */
 	ret = kfifo_in(&smsm_snapshot_fifo,
 			&use_wakelock, sizeof(use_wakelock));
@@ -2568,7 +2628,7 @@
 		if (smsm_snapshot_count) {
 			--smsm_snapshot_count;
 			if (smsm_snapshot_count == 0) {
-				SMx_POWER_INFO("SMSM snapshot wake unlock\n");
+				SMSM_POWER_INFO("SMSM snapshot wake unlock\n");
 				wake_unlock(&smsm_snapshot_wakelock);
 			}
 		} else {
@@ -2651,7 +2711,6 @@
 		if (old_apps != apps) {
 			SMSM_DBG("<SM %08x NOTIFY>\n", apps);
 			__raw_writel(apps, SMSM_STATE_ADDR(SMSM_APPS_STATE));
-			do_smd_probe();
 			notify_other_smsm(SMSM_APPS_STATE, (old_apps ^ apps));
 		}
 
@@ -2663,28 +2722,28 @@
 
 irqreturn_t smsm_modem_irq_handler(int irq, void *data)
 {
-	SMx_POWER_INFO("SMSM Int Modem->Apps\n");
+	SMSM_POWER_INFO("SMSM Int Modem->Apps\n");
 	++interrupt_stats[SMD_MODEM].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
 irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
 {
-	SMx_POWER_INFO("SMSM Int LPASS->Apps\n");
+	SMSM_POWER_INFO("SMSM Int LPASS->Apps\n");
 	++interrupt_stats[SMD_Q6].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
 irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
 {
-	SMx_POWER_INFO("SMSM Int DSPS->Apps\n");
+	SMSM_POWER_INFO("SMSM Int DSPS->Apps\n");
 	++interrupt_stats[SMD_DSPS].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
 
 irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
 {
-	SMx_POWER_INFO("SMSM Int WCNSS->Apps\n");
+	SMSM_POWER_INFO("SMSM Int WCNSS->Apps\n");
 	++interrupt_stats[SMD_WCNSS].smsm_in_count;
 	return smsm_irq_handler(irq, data);
 }
@@ -2774,7 +2833,7 @@
 	old_state = __raw_readl(SMSM_STATE_ADDR(smsm_entry));
 	new_state = (old_state & ~clear_mask) | set_mask;
 	__raw_writel(new_state, SMSM_STATE_ADDR(smsm_entry));
-	SMx_POWER_INFO("%s %d:%08x->%08x", __func__, smsm_entry,
+	SMSM_POWER_INFO("%s %d:%08x->%08x", __func__, smsm_entry,
 			old_state, new_state);
 	notify_other_smsm(SMSM_APPS_STATE, (old_state ^ new_state));
 
@@ -2818,8 +2877,12 @@
 	uint32_t use_wakelock;
 	int ret;
 	unsigned long flags;
+	uint64_t t_snapshot;
+	uint64_t t_start;
+	unsigned long nanosec_rem;
 
 	while (kfifo_len(&smsm_snapshot_fifo) >= SMSM_SNAPSHOT_SIZE) {
+		t_start = sched_clock();
 		mutex_lock(&smsm_lock);
 		for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
 			state_info = &smsm_states[n];
@@ -2835,7 +2898,7 @@
 
 			state_changes = state_info->last_value ^ new_state;
 			if (state_changes) {
-				SMx_POWER_INFO("SMSM Change %d: %08x->%08x\n",
+				SMSM_POWER_INFO("SMSM Change %d: %08x->%08x\n",
 						n, state_info->last_value,
 						new_state);
 				list_for_each_entry(cb_info,
@@ -2850,6 +2913,15 @@
 			}
 		}
 
+		ret = kfifo_out(&smsm_snapshot_fifo, &t_snapshot,
+				sizeof(t_snapshot));
+		if (ret != sizeof(t_snapshot)) {
+			pr_err("%s: snapshot underflow %d\n",
+				__func__, ret);
+			mutex_unlock(&smsm_lock);
+			return;
+		}
+
 		/* read wakelock flag */
 		ret = kfifo_out(&smsm_snapshot_fifo, &use_wakelock,
 				sizeof(use_wakelock));
@@ -2866,7 +2938,7 @@
 			if (smsm_snapshot_count) {
 				--smsm_snapshot_count;
 				if (smsm_snapshot_count == 0) {
-					SMx_POWER_INFO("SMSM snapshot"
+					SMSM_POWER_INFO("SMSM snapshot"
 						   " wake unlock\n");
 					wake_unlock(&smsm_snapshot_wakelock);
 				}
@@ -2877,6 +2949,12 @@
 			spin_unlock_irqrestore(&smsm_snapshot_count_lock,
 					flags);
 		}
+
+		t_start = t_start - t_snapshot;
+		nanosec_rem = do_div(t_start, 1000000000U);
+		SMSM_POWER_INFO(
+			"SMSM snapshot queue response time %6u.%09lu s\n",
+			(unsigned)t_start, nanosec_rem);
 	}
 }
 
@@ -3087,18 +3165,22 @@
  * smd_post_init() - SMD post initialization
  * @is_leagcy:	1 for Leagcy/platform device init sequence
  *		0 for device tree init sequence
+ * @remote_pid: remote pid that has been initialized.  Ignored when is_legacy=1
  *
  * This function is used by the legacy and device tree initialization
  * to complete the SMD init sequence.
  */
-void smd_post_init(bool is_legacy)
+void smd_post_init(bool is_legacy, unsigned remote_pid)
 {
+	int i;
+
 	if (is_legacy) {
 		smd_initialized = 1;
 		smd_alloc_loopback_channel();
-		tasklet_schedule(&smd_fake_irq_tasklet);
+		for (i = 1; i < NUM_SMD_SUBSYSTEMS; ++i)
+			schedule_work(&remote_info[i].probe_work);
 	} else {
-		schedule_work(&probe_work);
+		schedule_work(&remote_info[remote_pid].probe_work);
 	}
 }
 
@@ -3235,19 +3317,31 @@
 {
 	static bool registered;
 	int rc;
+	int i;
 
 	if (registered)
 		return 0;
 
 	smd_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smd");
 	if (!smd_log_ctx) {
-		pr_err("%s: unable to create logging context\n", __func__);
+		pr_err("%s: unable to create SMD logging context\n", __func__);
+		msm_smd_debug_mask = 0;
+	}
+
+	smsm_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smsm");
+	if (!smsm_log_ctx) {
+		pr_err("%s: unable to create SMSM logging context\n", __func__);
 		msm_smd_debug_mask = 0;
 	}
 
 	registered = true;
 
-	INIT_WORK(&probe_work, smd_channel_probe_worker);
+	for (i = 0; i < NUM_SMD_SUBSYSTEMS; ++i) {
+		remote_info[i].remote_pid = i;
+		remote_info[i].free_space = UINT_MAX;
+		INIT_WORK(&remote_info[i].probe_work, smd_channel_probe_worker);
+		INIT_LIST_HEAD(&remote_info[i].ch_list);
+	}
 
 	channel_close_wq = create_singlethread_workqueue("smd_channel_close");
 	if (IS_ERR(channel_close_wq)) {
diff --git a/arch/arm/mach-msm/smd_init_dt.c b/arch/arm/mach-msm/smd_init_dt.c
index d888a72..640656c 100644
--- a/arch/arm/mach-msm/smd_init_dt.c
+++ b/arch/arm/mach-msm/smd_init_dt.c
@@ -259,7 +259,7 @@
 		smd_set_edge_subsys_name(edge, pilstr);
 
 	smd_set_edge_initialized(edge);
-	smd_post_init(0);
+	smd_post_init(0, remote_pid);
 	return 0;
 
 missing_key:
diff --git a/arch/arm/mach-msm/smd_init_plat.c b/arch/arm/mach-msm/smd_init_plat.c
index c6f6cd9..c58b150 100644
--- a/arch/arm/mach-msm/smd_init_plat.c
+++ b/arch/arm/mach-msm/smd_init_plat.c
@@ -502,7 +502,7 @@
 		pr_err("smd_post_init() failed ret = %d\n", ret);
 		return ret;
 	}
-	smd_post_init(1);
+	smd_post_init(1, 0);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index 4664197..812a7d6 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -230,7 +230,8 @@
 	MSM_SMSM_DEBUG = 1U << 1,
 	MSM_SMD_INFO = 1U << 2,
 	MSM_SMSM_INFO = 1U << 3,
-	MSM_SMx_POWER_INFO = 1U << 4,
+	MSM_SMD_POWER_INFO = 1U << 4,
+	MSM_SMSM_POWER_INFO = 1U << 5,
 };
 
 struct interrupt_config {
@@ -261,7 +262,7 @@
 extern irqreturn_t smd_rpm_irq_handler(int irq, void *data);
 
 extern int msm_smd_driver_register(void);
-extern void smd_post_init(bool is_legacy);
+extern void smd_post_init(bool is_legacy, unsigned remote_pid);
 extern int smsm_post_init(void);
 
 extern struct interrupt_config *smd_get_intr_config(uint32_t edge);
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 1ec2a78..f41240a 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -16,12 +16,14 @@
 #include <linux/moduleparam.h>
 #include <linux/printk.h>
 #include <linux/notifier.h>
+#include <linux/of.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 <mach/msm_ipc_logging.h>
 
 #include "smem_private.h"
 
@@ -45,13 +47,29 @@
 	MSM_SMEM_INFO = 1U << 1,
 };
 
-static int msm_smem_debug_mask;
+static int msm_smem_debug_mask = MSM_SMEM_INFO;
 module_param_named(debug_mask, msm_smem_debug_mask,
 			int, S_IRUGO | S_IWUSR | S_IWGRP);
+static void *smem_ipc_log_ctx;
+#define NUM_LOG_PAGES 4
 
+#define IPC_LOG(x...) do {                                   \
+		if (smem_ipc_log_ctx)                        \
+			ipc_log_string(smem_ipc_log_ctx, x); \
+	} while (0)
+
+
+#define LOG_ERR(x...) do {  \
+		pr_err(x);  \
+		IPC_LOG(x); \
+	} while (0)
 #define SMEM_DBG(x...) do {                               \
 		if (msm_smem_debug_mask & MSM_SMEM_DEBUG) \
-			pr_debug(x);                      \
+			IPC_LOG(x);                       \
+	} while (0)
+#define SMEM_INFO(x...) do {                             \
+		if (msm_smem_debug_mask & MSM_SMEM_INFO) \
+			IPC_LOG(x);                      \
 	} while (0)
 
 #define SMEM_SPINLOCK_SMEM_ALLOC       "S:3"
@@ -68,6 +86,61 @@
 static RAW_NOTIFIER_HEAD(smem_module_init_notifier_list);
 static DEFINE_MUTEX(smem_module_init_notifier_lock);
 
+/* smem security feature components */
+#define SMEM_TOC_IDENTIFIER 0x434f5424 /* "$TOC" */
+#define SMEM_TOC_MAX_EXCLUSIONS 4
+#define SMEM_PART_HDR_IDENTIFIER 0x54525024 /* "$PRT" */
+#define SMEM_ALLOCATION_CANARY 0xa5a5
+
+struct smem_toc_entry {
+	uint32_t offset;
+	uint32_t size;
+	uint32_t flags;
+	uint16_t host0;
+	uint16_t host1;
+	uint32_t size_cacheline;
+	uint32_t reserved[3];
+	uint32_t exclusion_sizes[SMEM_TOC_MAX_EXCLUSIONS];
+};
+
+struct smem_toc {
+	/* Identifier is a constant, set to SMEM_TOC_IDENTIFIER. */
+	uint32_t identifier;
+	uint32_t version;
+	uint32_t num_entries;
+	uint32_t reserved[5];
+	struct smem_toc_entry entry[];
+};
+
+struct smem_partition_header {
+	/* Identifier is a constant, set to SMEM_PART_HDR_IDENTIFIER. */
+	uint32_t identifier;
+	uint16_t host0;
+	uint16_t host1;
+	uint32_t size;
+	uint32_t offset_free_uncached;
+	uint32_t offset_free_cached;
+	uint32_t reserved[3];
+};
+
+struct smem_partition_allocation_header {
+	/* Canary is a constant, set to SMEM_ALLOCATION_CANARY */
+	uint16_t canary;
+	uint16_t smem_type;
+	uint32_t size; /* includes padding bytes */
+	uint16_t padding_data;
+	uint16_t padding_hdr;
+	uint32_t reserved[1];
+};
+
+struct smem_partition_info {
+	uint32_t partition_num;
+	uint32_t offset;
+	uint32_t size_cacheline;
+};
+
+static struct smem_partition_info partitions[NUM_SMEM_SUBSYSTEMS];
+/* end smem security feature components */
 
 struct restart_notifier_block {
 	unsigned processor;
@@ -128,7 +201,7 @@
 		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__,
+				SMEM_INFO("%s: overflow %p %x\n", __func__,
 					MSM_SHARED_RAM_BASE, offset);
 				return NULL;
 			}
@@ -147,7 +220,7 @@
 
 		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
 				(uintptr_t)smem_areas[i].virt_addr, offset)) {
-			pr_err("%s: overflow %p %x\n", __func__,
+			SMEM_INFO("%s: overflow %p %x\n", __func__,
 				smem_areas[i].virt_addr, offset);
 			return NULL;
 		}
@@ -201,6 +274,22 @@
 EXPORT_SYMBOL(smem_alloc);
 
 /**
+ * smem_alloc_to_proc - Find existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size:     Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_alloc_to_proc(unsigned id, unsigned size, unsigned to_proc,
+								unsigned flags)
+{
+	return smem_find_to_proc(id, size, to_proc, flags);
+}
+EXPORT_SYMBOL(smem_alloc_to_proc);
+
+/**
  * __smem_get_entry - Get pointer and size of existing SMEM item
  *
  * @id:              ID of SMEM item
@@ -246,6 +335,138 @@
 	return ret;
 }
 
+/**
+ * __smem_get_entry_to_proc - Get pointer and size of existing SMEM item with
+ *                   security support
+ *
+ * @id:              ID of SMEM item
+ * @size:            Pointer to size variable for storing the result
+ * @to_proc:         SMEM host that shares the item with apps
+ * @flags:           Item attribute flags
+ * @skip_init_check: True means do not verify that SMEM has been initialized
+ * @use_rspinlock:   True to use the remote spinlock
+ * @returns:         Pointer to SMEM item or NULL if it doesn't exist
+ */
+static void *__smem_get_entry_to_proc(unsigned id,
+					unsigned *size,
+					unsigned to_proc,
+					unsigned flags,
+					bool skip_init_check,
+					bool use_rspinlock)
+{
+	struct smem_partition_header *hdr;
+	unsigned long lflags = 0;
+	void *item = NULL;
+	struct smem_partition_allocation_header *alloc_hdr;
+	uint32_t partition_num;
+	uint32_t a_hdr_size;
+	int rc;
+
+	SMEM_DBG("%s(%u, %u, %u, %u, %d, %d)\n", __func__, id, *size, to_proc,
+					flags, skip_init_check, use_rspinlock);
+
+	if (!skip_init_check && !smem_initialized_check())
+		return NULL;
+
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %d\n", __func__, id);
+		return NULL;
+	}
+
+	if (!(flags & SMEM_ANY_HOST_FLAG) && to_proc >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("%s: id %u invalid to_proc %d\n", __func__, id,
+								to_proc);
+		return NULL;
+	}
+
+	if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset)
+		return __smem_get_entry(id, size, skip_init_check,
+								use_rspinlock);
+
+	partition_num = partitions[to_proc].partition_num;
+	hdr = smem_areas[0].virt_addr + partitions[to_proc].offset;
+	if (unlikely(!spinlocks_initialized)) {
+		rc = init_smem_remote_spinlock();
+		if (unlikely(rc)) {
+			SMEM_INFO(
+				"%s: id:%u remote spinlock init failed %d\n",
+						__func__, id, rc);
+			return NULL;
+		}
+	}
+	if (use_rspinlock)
+		remote_spin_lock_irqsave(&remote_spinlock, lflags);
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR(
+			"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								hdr);
+		BUG();
+	}
+
+	if (flags & SMEM_ITEM_CACHED_FLAG) {
+		a_hdr_size = ALIGN(sizeof(*alloc_hdr),
+				partitions[to_proc].size_cacheline);
+		for (alloc_hdr = (void *)(hdr) + hdr->size - a_hdr_size;
+				(void *)(alloc_hdr) > (void *)(hdr) +
+					hdr->offset_free_cached;
+				alloc_hdr = (void *)(alloc_hdr) -
+						alloc_hdr->size - a_hdr_size) {
+			if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) {
+				LOG_ERR(
+					"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								alloc_hdr);
+				BUG();
+
+			}
+			if (alloc_hdr->smem_type == id) {
+				/* 8 byte alignment to match legacy */
+				*size = ALIGN(alloc_hdr->size -
+						alloc_hdr->padding_data, 8);
+				item = (void *)(alloc_hdr) - alloc_hdr->size;
+				break;
+			}
+		}
+	} else {
+		for (alloc_hdr = (void *)(hdr) + sizeof(*hdr);
+				(void *)(alloc_hdr) < (void *)(hdr) +
+					hdr->offset_free_uncached;
+				alloc_hdr = (void *)(alloc_hdr) +
+						sizeof(*alloc_hdr) +
+						alloc_hdr->padding_hdr +
+						alloc_hdr->size) {
+			if (alloc_hdr->canary != SMEM_ALLOCATION_CANARY) {
+				LOG_ERR(
+					"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								alloc_hdr);
+				BUG();
+
+			}
+			if (alloc_hdr->smem_type == id) {
+				/* 8 byte alignment to match legacy */
+				*size = ALIGN(alloc_hdr->size -
+						alloc_hdr->padding_data, 8);
+				item = (void *)(alloc_hdr) +
+						sizeof(*alloc_hdr) +
+						alloc_hdr->padding_hdr;
+				break;
+			}
+		}
+	}
+	if (use_rspinlock)
+		remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+
+	return item;
+}
+
 static void *__smem_find(unsigned id, unsigned size_in, bool skip_init_check)
 {
 	unsigned size;
@@ -257,7 +478,7 @@
 
 	size_in = ALIGN(size_in, 8);
 	if (size_in != size) {
-		pr_err("smem_find(%d, %d): wrong size %d\n",
+		SMEM_INFO("smem_find(%u, %u): wrong size %u\n",
 			id, size_in, size);
 		return 0;
 	}
@@ -271,6 +492,189 @@
 }
 EXPORT_SYMBOL(smem_find);
 
+/**
+ * smem_find_to_proc - Find existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size_in:  Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_find_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	unsigned size;
+	void *ptr;
+
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, size_in, to_proc,
+									flags);
+
+	ptr = smem_get_entry_to_proc(id, &size, to_proc, flags);
+	if (!ptr)
+		return 0;
+
+	size_in = ALIGN(size_in, 8);
+	if (size_in != size) {
+		SMEM_INFO("smem_find_to_proc(%u, %u, %u, %u): wrong size %u\n",
+			id, size_in, to_proc, flags, size);
+		return 0;
+	}
+
+	return ptr;
+}
+EXPORT_SYMBOL(smem_find_to_proc);
+
+/**
+ * alloc_item_nonsecure - Allocate an SMEM item in the nonsecure partition
+ *
+ * @id:              ID of SMEM item
+ * @size_in:         Size to allocate
+ * @returns:         Pointer to SMEM item or NULL for error
+ *
+ * Assumes the id parameter is valid and does not already exist.  Assumes
+ * size_in is already adjusted for alignment, if necessary.  Requires the
+ * remote spinlock to already be locked.
+ */
+static void *alloc_item_nonsecure(unsigned id, unsigned size_in)
+{
+	void *smem_base = MSM_SHARED_RAM_BASE;
+	struct smem_shared *shared = smem_base;
+	struct smem_heap_entry *toc = shared->heap_toc;
+	void *ret = NULL;
+
+	if (shared->heap_info.heap_remaining >= size_in) {
+		toc[id].offset = shared->heap_info.free_offset;
+		toc[id].size = size_in;
+		/*
+		 * wmb() is necessary to ensure the allocation data is
+		 * consistent before setting the allocated flag to prevent race
+		 * conditions with remote processors
+		 */
+		wmb();
+		toc[id].allocated = 1;
+
+		shared->heap_info.free_offset += size_in;
+		shared->heap_info.heap_remaining -= size_in;
+		ret = smem_base + toc[id].offset;
+		/*
+		 * wmb() is necessary to ensure the heap data is consistent
+		 * before continuing to prevent race conditions with remote
+		 * processors
+		 */
+		wmb();
+	} else {
+		SMEM_INFO("%s: id %u not enough memory %u (required %u)\n",
+			__func__, id, shared->heap_info.heap_remaining,
+			size_in);
+	}
+
+	return ret;
+}
+
+/**
+ * alloc_item_secure - Allocate an SMEM item in a secure partition
+ *
+ * @id:              ID of SMEM item
+ * @size_in:         Size to allocate
+ * @to_proc:         SMEM host that shares the item with apps
+ * @flags:           Item attribute flags
+ * @returns:         Pointer to SMEM item or NULL for error
+ *
+ * Assumes the id parameter is valid and does  not already exist.  Assumes
+ * size_in is the raw size requested by the client.  Assumes to_proc is a valid
+ * host, and a valid partition to that host exists.  Requires the remote
+ * spinlock to already be locked.
+ */
+static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	void *smem_base = MSM_SHARED_RAM_BASE;
+	struct smem_partition_header *hdr;
+	struct smem_partition_allocation_header *alloc_hdr;
+	uint32_t a_hdr_size;
+	uint32_t a_data_size;
+	uint32_t size_cacheline;
+	uint32_t free_space;
+	uint32_t partition_num;
+	void *ret = NULL;
+
+	hdr = smem_base + partitions[to_proc].offset;
+	partition_num = partitions[to_proc].partition_num;
+
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR(
+			"%s: SMEM corruption detected.  Partition %d to %d at %p\n",
+								__func__,
+								partition_num,
+								to_proc,
+								hdr);
+		BUG();
+	}
+
+	size_cacheline = partitions[to_proc].size_cacheline;
+	free_space = hdr->offset_free_cached -
+					hdr->offset_free_uncached;
+
+	if (flags & SMEM_ITEM_CACHED_FLAG) {
+		a_hdr_size = ALIGN(sizeof(*alloc_hdr), size_cacheline);
+		a_data_size = ALIGN(size_in, size_cacheline);
+		if (free_space < a_hdr_size + a_data_size) {
+			SMEM_INFO(
+				"%s: id %u not enough memory %u (required %u)\n",
+						__func__, id, free_space,
+						a_hdr_size + a_data_size);
+			return ret;
+		}
+		alloc_hdr = (void *)(hdr) + hdr->offset_free_cached -
+								a_hdr_size;
+		alloc_hdr->canary = SMEM_ALLOCATION_CANARY;
+		alloc_hdr->smem_type = id;
+		alloc_hdr->size = a_data_size;
+		alloc_hdr->padding_data = a_data_size - size_in;
+		alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr);
+		hdr->offset_free_cached = hdr->offset_free_cached -
+						a_hdr_size - a_data_size;
+		ret = (void *)(alloc_hdr) - a_data_size;
+		/*
+		 * The SMEM protocol currently does not support cacheable
+		 * areas within the smem region, but if it ever does in the
+		 * future, then cache management needs to be done here.
+		 * The area of memory this item is allocated from will need to
+		 * be dynamically made cachable, and a cache flush of the
+		 * allocation header using __cpuc_flush_dcache_area and
+		 * outer_flush_area will need to be done.
+		 */
+	} else {
+		a_hdr_size = sizeof(*alloc_hdr);
+		a_data_size = ALIGN(size_in, 8);
+		if (free_space < a_hdr_size + a_data_size) {
+			SMEM_INFO(
+				"%s: id %u not enough memory %u (required %u)\n",
+						__func__, id, free_space,
+						a_hdr_size + a_data_size);
+			return ret;
+		}
+		alloc_hdr = (void *)(hdr) + hdr->offset_free_uncached;
+		alloc_hdr->canary = SMEM_ALLOCATION_CANARY;
+		alloc_hdr->smem_type = id;
+		alloc_hdr->size = a_data_size;
+		alloc_hdr->padding_data = a_data_size - size_in;
+		alloc_hdr->padding_hdr = a_hdr_size - sizeof(*alloc_hdr);
+		hdr->offset_free_uncached = hdr->offset_free_uncached +
+						a_hdr_size + a_data_size;
+		ret = alloc_hdr + 1;
+	}
+	/*
+	 * wmb() is necessary to ensure the heap and allocation data is
+	 * consistent before continuing to prevent race conditions with remote
+	 * processors
+	 */
+	wmb();
+
+	return ret;
+}
+
 /* smem_alloc2 returns the pointer to smem item.  If it is not allocated,
  * it allocates it and then returns the pointer to it.
  */
@@ -285,13 +689,15 @@
 	if (!smem_initialized_check())
 		return NULL;
 
-	if (id >= SMEM_NUM_ITEMS)
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %u\n", __func__, id);
 		return NULL;
+	}
 
 	if (unlikely(!spinlocks_initialized)) {
 		rc = init_smem_remote_spinlock();
 		if (unlikely(rc)) {
-			pr_err("%s: remote spinlock init failed %d\n",
+			SMEM_INFO("%s: remote spinlock init failed %d\n",
 								__func__, rc);
 			return NULL;
 		}
@@ -300,34 +706,102 @@
 	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);
+		SMEM_INFO("%s: %u already allocated\n", __func__, id);
 		if (size_in != toc[id].size)
-			pr_err("%s: wrong size %u (expected %u)\n",
+			SMEM_INFO("%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);
+		SMEM_INFO("%s: allocating %u\n", __func__, id);
+		ret = alloc_item_nonsecure(id, size_in);
 	}
-	wmb();
 	remote_spin_unlock_irqrestore(&remote_spinlock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(smem_alloc2);
 
+/**
+ * smem_alloc2_to_proc - Find an existing item, otherwise allocate it with
+ *				security support
+ *
+ * @id:       ID of SMEM item
+ * @size_in:  Size of the SMEM item
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it couldn't be found/allocated
+ */
+void *smem_alloc2_to_proc(unsigned id, unsigned size_in, unsigned to_proc,
+								unsigned flags)
+{
+	unsigned long lflags;
+	void *ret = NULL;
+	int rc;
+	unsigned size_out;
+	unsigned a_size_in;
+
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, size_in, to_proc,
+									flags);
+
+	if (!smem_initialized_check())
+		return NULL;
+
+	if (id >= SMEM_NUM_ITEMS) {
+		SMEM_INFO("%s: invalid id %u\n", __func__, id);
+		return NULL;
+	}
+
+	if (!(flags & SMEM_ANY_HOST_FLAG) && to_proc >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("%s: invalid to_proc %u for id %u\n", __func__,
+								to_proc, id);
+		return NULL;
+	}
+
+	if (unlikely(!spinlocks_initialized)) {
+		rc = init_smem_remote_spinlock();
+		if (unlikely(rc)) {
+			SMEM_INFO("%s: id:%u remote spinlock init failed %d\n",
+							__func__, id, rc);
+			return NULL;
+		}
+	}
+
+	a_size_in = ALIGN(size_in, 8);
+	remote_spin_lock_irqsave(&remote_spinlock, lflags);
+
+	ret = __smem_get_entry_to_proc(id, &size_out, to_proc, flags, true,
+									false);
+	if (ret) {
+		SMEM_INFO("%s: %u already allocated\n", __func__, id);
+		if (a_size_in == size_out) {
+			remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+			return ret;
+		} else {
+			remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+			SMEM_INFO("%s: id %u wrong size %u (expected %u)\n",
+				__func__, id, size_out, a_size_in);
+			return NULL;
+		}
+	}
+
+	if (id > SMEM_FIXED_ITEM_LAST) {
+		SMEM_INFO("%s: allocating %u size %u to_proc %u flags %u\n",
+					__func__, id, size_in, to_proc, flags);
+		if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset)
+			ret = alloc_item_nonsecure(id, a_size_in);
+		else
+			ret = alloc_item_secure(id, size_in, to_proc, flags);
+
+	} else {
+		SMEM_INFO("%s: attempted to allocate non-dynamic item %u\n",
+								__func__, id);
+	}
+
+	remote_spin_unlock_irqrestore(&remote_spinlock, lflags);
+	return ret;
+}
+EXPORT_SYMBOL(smem_alloc2_to_proc);
+
 void *smem_get_entry(unsigned id, unsigned *size)
 {
 	return __smem_get_entry(id, size, false, true);
@@ -335,6 +809,24 @@
 EXPORT_SYMBOL(smem_get_entry);
 
 /**
+ * smem_get_entry_to_proc - Get existing item with security support
+ *
+ * @id:       ID of SMEM item
+ * @size:     Pointer to size variable for storing the result
+ * @to_proc:  SMEM host that shares the item with apps
+ * @flags:    Item attribute flags
+ * @returns:  Pointer to SMEM item or NULL if it doesn't exist
+ */
+void *smem_get_entry_to_proc(unsigned id, unsigned *size, unsigned to_proc,
+								unsigned flags)
+{
+	SMEM_DBG("%s(%u, %u, %u, %u)\n", __func__, id, *size, to_proc, flags);
+
+	return __smem_get_entry_to_proc(id, size, to_proc, flags, false, true);
+}
+EXPORT_SYMBOL(smem_get_entry_to_proc);
+
+/**
  * smem_get_entry_no_rlock - Get existing item without using remote spinlock
  *
  * @id:       ID of SMEM item
@@ -365,9 +857,50 @@
 EXPORT_SYMBOL(smem_get_remote_spinlock);
 
 /**
+ * smem_get_free_space() - Get the available allocation free space for a
+ *				partition
+ *
+ * @to_proc: remote SMEM host.  Determines the applicable partition
+ * @returns: size in bytes available to allocate
+ *
+ * Helper function for SMD so that SMD only scans the channel allocation
+ * table for a partition when it is reasonably certain that a channel has
+ * actually been created, because scanning can be expensive.  Creating a channel
+ * will consume some of the free space in a partition, so SMD can compare the
+ * last free space size against the current free space size to determine if
+ * a channel may have been created.  SMD can't do this directly, because the
+ * necessary partition internals are restricted to just SMEM.
+ */
+unsigned smem_get_free_space(unsigned to_proc)
+{
+	struct smem_partition_header *hdr;
+	struct smem_shared *shared;
+
+	if (to_proc >= NUM_SMEM_SUBSYSTEMS) {
+		pr_err("%s: invalid to_proc:%d\n", __func__, to_proc);
+		return UINT_MAX;
+	}
+
+	if (partitions[to_proc].offset) {
+		if (unlikely(OVERFLOW_ADD_UNSIGNED(uintptr_t,
+					(uintptr_t)smem_areas[0].virt_addr,
+					partitions[to_proc].offset))) {
+			pr_err("%s: unexpected overflow detected\n", __func__);
+			return UINT_MAX;
+		}
+		hdr = smem_areas[0].virt_addr + partitions[to_proc].offset;
+		return hdr->offset_free_cached - hdr->offset_free_uncached;
+	} else {
+		shared = (void *)MSM_SHARED_RAM_BASE;
+		return shared->heap_info.heap_remaining;
+	}
+}
+EXPORT_SYMBOL(smem_get_free_space);
+
+/**
  * init_smem_remote_spinlock - Reentrant remote spinlock initialization
  *
- * @returns: sucess or error code for failure
+ * @returns: success or error code for failure
  */
 static int init_smem_remote_spinlock(void)
 {
@@ -408,7 +941,7 @@
 
 	if (likely(checked)) {
 		if (unlikely(!is_inited))
-			pr_err("%s: smem not initialized\n", __func__);
+			LOG_ERR("%s: smem not initialized\n", __func__);
 		return is_inited;
 	}
 
@@ -416,7 +949,7 @@
 	if (checked) {
 		spin_unlock_irqrestore(&smem_init_check_lock, flags);
 		if (unlikely(!is_inited))
-			pr_err("%s: smem not initialized\n", __func__);
+			LOG_ERR("%s: smem not initialized\n", __func__);
 		return is_inited;
 	}
 
@@ -431,8 +964,17 @@
 									true);
 	if (version_array == NULL)
 		goto failed;
-	if (version_array[MODEM_SBL_VERSION_INDEX] != SMEM_VERSION << 16)
+
+	/*
+	 * The Modem SBL is now the Master SBL version and is required to
+	 * pre-initialize SMEM and fill in any necessary configuration
+	 * structures.  Without the extra configuration data, the SMEM driver
+	 * cannot be properly initialized.
+	 */
+	if (version_array[MODEM_SBL_VERSION_INDEX] != SMEM_VERSION << 16) {
+		pr_err("%s: SBL version not correct\n", __func__);
 		goto failed;
+	}
 
 	is_inited = 1;
 	checked = 1;
@@ -443,7 +985,8 @@
 	is_inited = 0;
 	checked = 1;
 	spin_unlock_irqrestore(&smem_init_check_lock, flags);
-	pr_err("%s: bootloader failure detected, shared memory not inited\n",
+	LOG_ERR(
+		"%s: shared memory needs to be initialized by SBL before booting\n",
 								__func__);
 	return is_inited;
 }
@@ -458,7 +1001,7 @@
 
 		notifier = container_of(this,
 					struct restart_notifier_block, nb);
-		SMEM_DBG("%s: ssrestart for processor %d ('%s')\n",
+		SMEM_INFO("%s: ssrestart for processor %d ('%s')\n",
 				__func__, notifier->processor,
 				notifier->name);
 
@@ -478,8 +1021,8 @@
 			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);
+				LOG_ERR("%s: unable to dump smem %d\n",
+								__func__, ret);
 		}
 	}
 
@@ -494,7 +1037,7 @@
 
 	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",
+		LOG_ERR("%s: Unable to create smem ramdump device.\n",
 			__func__);
 		smem_ramdump_dev = NULL;
 	}
@@ -546,6 +1089,124 @@
 	mutex_unlock(&smem_module_init_notifier_lock);
 }
 
+/**
+ * smem_init_security_partition - Init local structures for a secured smem
+ *                   partition that has apps as one of the hosts
+ *
+ * @entry:           Entry in the security TOC for the partition to init
+ * @num:             Partition ID
+ *
+ * Initialize local data structures to point to a secured smem partition
+ * that is accessible by apps and another processor.  Assumes that one of the
+ * listed hosts is apps.  Verifiess that the partition is valid, otherwise will
+ * skip.  Checks for memory corruption and will BUG() if detected.  Assumes
+ * smem_areas is already initialized and that smem_areas[0] corresponds to the
+ * smem region with the secured partitions.
+ */
+static void smem_init_security_partition(struct smem_toc_entry *entry,
+								uint32_t num)
+{
+	uint16_t remote_host;
+	struct smem_partition_header *hdr;
+
+	if (!entry->offset) {
+		SMEM_INFO("Skipping smem partition %d - bad offset\n", num);
+		return;
+	}
+	if (!entry->size) {
+		SMEM_INFO("Skipping smem partition %d - bad size\n", num);
+		return;
+	}
+	if (!entry->size_cacheline) {
+		SMEM_INFO("Skipping smem partition %d - bad cacheline\n", num);
+		return;
+	}
+
+	if (entry->host0 == SMEM_APPS)
+		remote_host = entry->host1;
+	else
+		remote_host = entry->host0;
+
+	if (remote_host >= NUM_SMEM_SUBSYSTEMS) {
+		SMEM_INFO("Skipping smem partition %d - bad remote:%d\n", num,
+								remote_host);
+		return;
+	}
+	if (partitions[remote_host].offset) {
+		SMEM_INFO("Skipping smem partition %d - duplicate of %d\n", num,
+					partitions[remote_host].partition_num);
+		return;
+	}
+
+	hdr = smem_areas[0].virt_addr + entry->offset;
+
+	if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) {
+		LOG_ERR("Smem partition %d hdr magic is bad\n", num);
+		BUG();
+	}
+	if (!hdr->size) {
+		LOG_ERR("Smem partition %d size is 0\n", num);
+		BUG();
+	}
+	if (hdr->offset_free_uncached > hdr->size) {
+		LOG_ERR("Smem partition %d uncached heap exceeds size\n", num);
+		BUG();
+	}
+	if (hdr->offset_free_cached > hdr->size) {
+		LOG_ERR("Smem partition %d cached heap exceeds size\n", num);
+		BUG();
+	}
+	if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) {
+		LOG_ERR("Smem partition %d hosts don't match TOC\n", num);
+		BUG();
+	}
+	if (hdr->host0 != remote_host && hdr->host1 != remote_host) {
+		LOG_ERR("Smem partition %d hosts don't match TOC\n", num);
+		BUG();
+	}
+
+	partitions[remote_host].partition_num = num;
+	partitions[remote_host].offset = entry->offset;
+	partitions[remote_host].size_cacheline = entry->size_cacheline;
+	SMEM_INFO("Partition %d offset:%x remote:%d\n", num, entry->offset,
+								remote_host);
+}
+
+/**
+ * smem_init_security - Init local support for secured smem
+ *
+ * Looks for a valid security TOC, and if one is found, parses it looking for
+ * partitions that apps can access.  If any such partitions are found, do the
+ * required local initialization to support them.  Assumes smem_areas is inited
+ * and smem_area[0] corresponds to the smem region with the TOC.
+ */
+static void smem_init_security(void)
+{
+	struct smem_toc *toc;
+	uint32_t i;
+
+	SMEM_DBG("%s\n", __func__);
+
+	toc = smem_areas[0].virt_addr + smem_areas[0].size - 4 * 1024;
+
+	if (toc->identifier != SMEM_TOC_IDENTIFIER) {
+		LOG_ERR("%s failed: invalid TOC magic\n", __func__);
+		return;
+	}
+
+	for (i = 0; i < toc->num_entries; ++i) {
+		SMEM_DBG("Partition %d host0:%d host1:%d\n", i,
+							toc->entry[i].host0,
+							toc->entry[i].host1);
+
+		if (toc->entry[i].host0 == SMEM_APPS ||
+					toc->entry[i].host1 == SMEM_APPS)
+			smem_init_security_partition(&toc->entry[i], i);
+	}
+
+	SMEM_DBG("%s done\n", __func__);
+}
+
 static int msm_smem_probe(struct platform_device *pdev)
 {
 	char *key;
@@ -558,6 +1219,7 @@
 	struct ramdump_segment *ramdump_segments_tmp = NULL;
 	struct smem_area *smem_areas_tmp = NULL;
 	int smem_idx = 0;
+	bool security_enabled;
 
 	if (!smem_initialized_check())
 		return -ENODEV;
@@ -565,7 +1227,7 @@
 	key = "irq-reg-base";
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
 	if (!r) {
-		pr_err("%s: missing '%s'\n", __func__, key);
+		LOG_ERR("%s: missing '%s'\n", __func__, key);
 		return -ENODEV;
 	}
 
@@ -580,7 +1242,7 @@
 
 		++num_smem_areas;
 		if (num_smem_areas > 999) {
-			pr_err("%s: max num aux mem regions reached\n",
+			LOG_ERR("%s: max num aux mem regions reached\n",
 								__func__);
 			break;
 		}
@@ -589,14 +1251,14 @@
 	key = "smem";
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
 	if (!r) {
-		pr_err("%s: missing '%s'\n", __func__, key);
+		LOG_ERR("%s: missing '%s'\n", __func__, key);
 		return -ENODEV;
 	}
 
 	smem_areas_tmp = kmalloc_array(num_smem_areas, sizeof(struct smem_area),
 				GFP_KERNEL);
 	if (!smem_areas_tmp) {
-		pr_err("%s: smem areas kmalloc failed\n", __func__);
+		LOG_ERR("%s: smem areas kmalloc failed\n", __func__);
 		ret = -ENOMEM;
 		goto free_smem_areas;
 	}
@@ -604,7 +1266,7 @@
 	ramdump_segments_tmp = kmalloc_array(num_smem_areas,
 			sizeof(struct ramdump_segment), GFP_KERNEL);
 	if (!ramdump_segments_tmp) {
-		pr_err("%s: ramdump segment kmalloc failed\n", __func__);
+		LOG_ERR("%s: ramdump segment kmalloc failed\n", __func__);
 		ret = -ENOMEM;
 		goto free_smem_areas;
 	}
@@ -640,7 +1302,7 @@
 				smem_areas_tmp[smem_idx].virt_addr);
 
 		if (!smem_areas_tmp[smem_idx].virt_addr) {
-			pr_err("%s: ioremap_nocache() of addr:%pa size: %pa\n",
+			LOG_ERR("%s: ioremap_nocache() of addr:%pa size: %pa\n",
 				__func__,
 				&smem_areas_tmp[smem_idx].phys_addr,
 				&smem_areas_tmp[smem_idx].size);
@@ -651,7 +1313,8 @@
 		if (OVERFLOW_ADD_UNSIGNED(uintptr_t,
 				(uintptr_t)smem_areas_tmp[smem_idx].virt_addr,
 				smem_areas_tmp[smem_idx].size)) {
-			pr_err("%s: invalid virtual address block %i: %p:%pa\n",
+			LOG_ERR(
+				"%s: invalid virtual address block %i: %p:%pa\n",
 					__func__, smem_idx,
 					smem_areas_tmp[smem_idx].virt_addr,
 					&smem_areas_tmp[smem_idx].size);
@@ -662,18 +1325,26 @@
 
 		++smem_idx;
 		if (smem_idx > 999) {
-			pr_err("%s: max num aux mem regions reached\n",
+			LOG_ERR("%s: max num aux mem regions reached\n",
 							__func__);
 			break;
 		}
 	}
 
-	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
-	if (ret)
-		pr_err("%s: of_platform_populate failed %d\n", __func__, ret);
-
 	smem_areas = smem_areas_tmp;
 	smem_ramdump_segments = ramdump_segments_tmp;
+
+	key = "mpu-enabled";
+	security_enabled = of_property_read_bool(pdev->dev.of_node, key);
+	if (security_enabled) {
+		SMEM_INFO("smem security enabled\n");
+		smem_init_security();
+	}
+
+	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (ret)
+		LOG_ERR("%s: of_platform_populate failed %d\n", __func__, ret);
+
 	return 0;
 
 free_smem_areas:
@@ -710,15 +1381,21 @@
 
 	registered = true;
 
+	smem_ipc_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smem");
+	if (!smem_ipc_log_ctx) {
+		pr_err("%s: unable to create logging context\n", __func__);
+		msm_smem_debug_mask = 0;
+	}
+
 	rc = init_smem_remote_spinlock();
 	if (rc) {
-		pr_err("%s: remote spinlock init failed %d\n", __func__, rc);
+		LOG_ERR("%s: remote spinlock init failed %d\n", __func__, rc);
 		return rc;
 	}
 
 	rc = platform_driver_register(&msm_smem_driver);
 	if (rc) {
-		pr_err("%s: msm_smem_driver register failed %d\n",
+		LOG_ERR("%s: msm_smem_driver register failed %d\n",
 							__func__, rc);
 		return rc;
 	}
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
index ceb8028..3fa842f 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -76,4 +76,21 @@
  * @nb: Notifier block to be unregistered
  */
 int smem_module_init_notifier_unregister(struct notifier_block *nb);
+
+/**
+ * smem_get_free_space() - Get the available allocation free space for a
+ *				partition
+ *
+ * @to_proc: remote SMEM host.  Determines the applicable partition
+ * @returns: size in bytes available to allocate
+ *
+ * Helper function for SMD so that SMD only scans the channel allocation
+ * table for a partition when it is reasonably certain that a channel has
+ * actually been created, because scanning can be expensive.  Creating a channel
+ * will consume some of the free space in a partition, so SMD can compare the
+ * last free space size against the current free space size to determine if
+ * a channel may have been created.  SMD can't do this directly, because the
+ * necessary partition internals are restricted to just SMEM.
+ */
+unsigned smem_get_free_space(unsigned to_proc);
 #endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index e82ea2b..34ae4e6 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -734,6 +734,46 @@
 #endif
 }
 
+#define MLK(b, t) b, t, ((t) - (b)) >> 10
+#define MLM(b, t) b, t, ((t) - (b)) >> 20
+#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+void print_vmalloc_lowmem_info(void)
+{
+	int i;
+	void *va_start, *va_end;
+
+	printk(KERN_NOTICE
+		"	   vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+		MLM(VMALLOC_START, VMALLOC_END));
+
+	for (i = meminfo.nr_banks - 1; i >= 0; i--) {
+		if (!meminfo.bank[i].highmem) {
+			va_start = __va(meminfo.bank[i].start);
+			va_end = __va(meminfo.bank[i].start +
+						meminfo.bank[i].size);
+			printk(KERN_NOTICE
+			 "	    lowmem : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+			MLM((unsigned long)va_start, (unsigned long)va_end));
+		}
+		if (i && ((meminfo.bank[i-1].start + meminfo.bank[i-1].size) !=
+			   meminfo.bank[i].start)) {
+			if (meminfo.bank[i-1].start + meminfo.bank[i-1].size
+				   <= MAX_HOLE_ADDRESS) {
+				va_start = __va(meminfo.bank[i-1].start
+						+ meminfo.bank[i-1].size);
+				va_end = __va(meminfo.bank[i].start);
+				printk(KERN_NOTICE
+				"	   vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+					   MLM((unsigned long)va_start,
+						   (unsigned long)va_end));
+			}
+		}
+	}
+}
+#endif
+
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much
  * memory is free.  This is done after various parts of the system have
@@ -814,10 +854,6 @@
 		reserved_pages << (PAGE_SHIFT-10),
 		totalhigh_pages << (PAGE_SHIFT-10));
 
-#define MLK(b, t) b, t, ((t) - (b)) >> 10
-#define MLM(b, t) b, t, ((t) - (b)) >> 20
-#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
-
 	printk(KERN_NOTICE "Virtual kernel memory layout:\n"
 			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -827,20 +863,7 @@
 			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 			"    ITCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
 #endif
-			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
-			"    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-			"    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#ifdef CONFIG_HIGHMEM
-			"    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#endif
-#ifdef CONFIG_MODULES
-			"    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
-#endif
-			"      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
-			"       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
-
+			"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n",
 			MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
 				(PAGE_SIZE)),
 #ifdef CONFIG_ARM_USE_USER_ACCESSIBLE_TIMERS
@@ -852,25 +875,39 @@
 			MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
 			MLK(ITCM_OFFSET, (unsigned long) itcm_end),
 #endif
-			MLK(FIXADDR_START, FIXADDR_TOP),
-			MLM(VMALLOC_START, VMALLOC_END),
-			MLM(PAGE_OFFSET, (unsigned long)high_memory),
+			MLK(FIXADDR_START, FIXADDR_TOP));
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	print_vmalloc_lowmem_info();
+#else
+	printk(KERN_NOTICE
+		   "    vmalloc : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+		   "    lowmem  : 0x%08lx - 0x%08lx   (%4ld MB)\n",
+		   MLM(VMALLOC_START, VMALLOC_END),
+		   MLM(PAGE_OFFSET, (unsigned long)high_memory));
+#endif
 #ifdef CONFIG_HIGHMEM
-			MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
+	printk(KERN_NOTICE
+		   "    pkmap   : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+#ifdef CONFIG_MODULES
+		   "    modules : 0x%08lx - 0x%08lx   (%4ld MB)\n"
+#endif
+		   "      .text : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "      .init : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "      .data : 0x%p" " - 0x%p" "   (%4d kB)\n"
+		   "       .bss : 0x%p" " - 0x%p" "   (%4d kB)\n",
+#ifdef CONFIG_HIGHMEM
+		   MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
 				(PAGE_SIZE)),
 #endif
 #ifdef CONFIG_MODULES
-			MLM(MODULES_VADDR, MODULES_END),
+		   MLM(MODULES_VADDR, MODULES_END),
 #endif
 
-			MLK_ROUNDUP(_text, _etext),
-			MLK_ROUNDUP(__init_begin, __init_end),
-			MLK_ROUNDUP(_sdata, _edata),
-			MLK_ROUNDUP(__bss_start, __bss_stop));
-
-#undef MLK
-#undef MLM
-#undef MLK_ROUNDUP
+		   MLK_ROUNDUP(_text, _etext),
+		   MLK_ROUNDUP(__init_begin, __init_end),
+		   MLK_ROUNDUP(_sdata, _edata),
+		   MLK_ROUNDUP(__bss_start, __bss_stop));
 
 	/*
 	 * Check boundaries twice: Some fundamental inconsistencies can
@@ -878,7 +915,7 @@
 	 */
 #ifdef CONFIG_MMU
 	BUILD_BUG_ON(TASK_SIZE				> MODULES_VADDR);
-	BUG_ON(TASK_SIZE 				> MODULES_VADDR);
+	BUG_ON(TASK_SIZE				> MODULES_VADDR);
 #endif
 
 #ifdef CONFIG_HIGHMEM
@@ -897,6 +934,9 @@
 	}
 }
 
+#undef MLK
+#undef MLM
+#undef MLK_ROUNDUP
 void free_initmem(void)
 {
 	unsigned long reclaimed_initmem;
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index e5a60a9..509f59d 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -871,6 +871,7 @@
 {
 	struct map_desc *md;
 	struct vm_struct *vm;
+	int rc = 0;
 
 	if (!nr)
 		return;
@@ -881,11 +882,13 @@
 		create_mapping(md);
 		vm->addr = (void *)(md->virtual & PAGE_MASK);
 		vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
-		vm->phys_addr = __pfn_to_phys(md->pfn); 
-		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; 
+		vm->phys_addr = __pfn_to_phys(md->pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
 		vm->flags |= VM_ARM_MTYPE(md->type);
 		vm->caller = iotable_init;
-		vm_area_add_early(vm++);
+		rc = vm_area_check_early(vm);
+		if (!rc)
+			vm_area_add_early(vm++);
 	}
 }
 
@@ -999,6 +1002,18 @@
 {
 	int i, j, highmem = 0;
 
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	unsigned long hole_start;
+	for (i = 0; i < (meminfo.nr_banks - 1); i++) {
+		hole_start = meminfo.bank[i].start + meminfo.bank[i].size;
+		if (hole_start != meminfo.bank[i+1].start) {
+			if (hole_start <= MAX_HOLE_ADDRESS) {
+				vmalloc_min = (void *) (vmalloc_min +
+				(meminfo.bank[i+1].start - hole_start));
+			}
+		}
+	}
+#endif
 #ifdef CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0
 	find_memory_hole();
 #endif
@@ -1382,12 +1397,21 @@
 static void __init map_lowmem(void)
 {
 	struct memblock_region *reg;
+	struct vm_struct *vm;
+	phys_addr_t start;
+	phys_addr_t end;
+	unsigned long vaddr;
+	unsigned long pfn;
+	unsigned long length;
+	unsigned int type;
+	int nr = 0;
 
 	/* Map all the lowmem memory banks. */
 	for_each_memblock(memory, reg) {
-		phys_addr_t start = reg->base;
-		phys_addr_t end = start + reg->size;
 		struct map_desc map;
+		nr++;
+		start = reg->base;
+		end = start + reg->size;
 
 		if (end > arm_lowmem_limit)
 			end = arm_lowmem_limit;
@@ -1440,6 +1464,32 @@
 
 		create_mapping(&map);
 	}
+
+	vm = early_alloc_aligned(sizeof(*vm) * nr, __alignof__(*vm));
+
+	for_each_memblock(memory, reg) {
+
+		start = reg->base;
+		end = start + reg->size;
+
+		if (end > arm_lowmem_limit)
+			end = arm_lowmem_limit;
+		if (start >= end)
+			break;
+
+		pfn = __phys_to_pfn(start);
+		vaddr = __phys_to_virt(start);
+		length = end - start;
+		type = MT_MEMORY;
+
+		vm->addr = (void *)(vaddr & PAGE_MASK);
+		vm->size = PAGE_ALIGN(length + (vaddr & ~PAGE_MASK));
+		vm->phys_addr = __pfn_to_phys(pfn);
+		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+		vm->flags |= VM_ARM_MTYPE(type);
+		vm->caller = map_lowmem;
+		vm_area_add_early(vm++);
+	}
 }
 
 /*
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index 415c73e..90451ca 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -136,10 +136,28 @@
 	buf = __ion_secure_cma_allocate(heap, buffer, len, align, flags);
 
 	if (buf) {
+		int ret;
+
 		buf->secure.want_delayed_unsecure = 0;
 		atomic_set(&buf->secure.secure_cnt, 0);
 		mutex_init(&buf->secure.lock);
 		buf->secure.is_secure = 1;
+		buf->secure.ignore_check = true;
+
+		/*
+		 * make sure the size is set before trying to secure
+		 */
+		buffer->size = len;
+		ret = ion_cp_secure_buffer(buffer, ION_CP_V2, 0, 0);
+		if (ret) {
+			/*
+			 * Don't treat the secure buffer failing here as an
+			 * error for backwards compatibility reasons. If
+			 * the secure fails, the map will also fail so there
+			 * is no security risk.
+			 */
+			pr_debug("%s: failed to secure buffer\n", __func__);
+		}
 		return 0;
 	} else {
 		return -ENOMEM;
@@ -153,6 +171,8 @@
 	struct ion_secure_cma_buffer_info *info = buffer->priv_virt;
 
 	dev_dbg(dev, "Release buffer %p\n", buffer);
+
+	ion_cp_unsecure_buffer(buffer, 1);
 	/* release memory */
 	dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle);
 	sg_free_table(info->table);
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
index d315fc4..7ffab09 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.c
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -286,7 +286,7 @@
 		goto out_unlock;
 	}
 
-	if (atomic_read(&buf->secure_cnt)) {
+	if (atomic_read(&buf->secure_cnt) && !buf->ignore_check) {
 		if (buf->version != version || buf->data != data) {
 			pr_err("%s: Trying to re-secure buffer with different values",
 				__func__);
diff --git a/drivers/gpu/ion/msm/ion_cp_common.h b/drivers/gpu/ion/msm/ion_cp_common.h
index 8ae19be..ded6af9 100644
--- a/drivers/gpu/ion/msm/ion_cp_common.h
+++ b/drivers/gpu/ion/msm/ion_cp_common.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
@@ -38,6 +38,10 @@
 	struct mutex lock;
 	int version;
 	void *data;
+	/*
+	 * secure is happening at allocation time, ignore version/data check
+	 */
+	bool ignore_check;
 };
 
 #if defined(CONFIG_ION_MSM)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 06ca31c..4dbe5c1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -399,7 +399,6 @@
 #if defined(CONFIG_SECURE_TOUCH)
 	atomic_t st_enabled;
 	atomic_t st_pending_irqs;
-	struct completion st_completion;
 	struct completion st_powerdown;
 #endif
 };
@@ -1002,11 +1001,16 @@
 }
 
 #if defined(CONFIG_SECURE_TOUCH)
+static void mxt_secure_touch_notify(struct mxt_data *data)
+{
+	sysfs_notify(&data->client->dev.kobj, NULL, "secure_touch");
+}
+
 static irqreturn_t mxt_filter_interrupt(struct mxt_data *data)
 {
 	if (atomic_read(&data->st_enabled)) {
 		if (atomic_cmpxchg(&data->st_pending_irqs, 0, 1) == 0)
-			complete(&data->st_completion);
+			mxt_secure_touch_notify(data);
 		return IRQ_HANDLED;
 	}
 	return IRQ_NONE;
@@ -1998,7 +2002,7 @@
 
 		pm_runtime_put(data->client->adapter->dev.parent);
 		atomic_set(&data->st_enabled, 0);
-		complete(&data->st_completion);
+		mxt_secure_touch_notify(data);
 		mxt_interrupt(data->client->irq, data);
 		complete(&data->st_powerdown);
 		break;
@@ -2013,7 +2017,6 @@
 			err = -EIO;
 			break;
 		}
-		INIT_COMPLETION(data->st_completion);
 		INIT_COMPLETION(data->st_powerdown);
 		atomic_set(&data->st_enabled, 1);
 		synchronize_irq(data->client->irq);
@@ -2032,20 +2035,18 @@
 				    struct device_attribute *attr, char *buf)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
-	int err;
+	int val = 0;
 
 	if (atomic_read(&data->st_enabled) == 0)
 		return -EBADF;
 
-	err = wait_for_completion_interruptible(&data->st_completion);
-
-	if (err)
-		return err;
-
-	if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) != 1)
+	if (atomic_cmpxchg(&data->st_pending_irqs, -1, 0) == -1)
 		return -EINVAL;
 
-	return scnprintf(buf, PAGE_SIZE, "%u", 1);
+	if (atomic_cmpxchg(&data->st_pending_irqs, 1, 0) == 1)
+		val = 1;
+
+	return scnprintf(buf, PAGE_SIZE, "%u", val);
 }
 
 static DEVICE_ATTR(secure_touch_enable, 0666, mxt_secure_touch_enable_show,
@@ -2074,15 +2075,17 @@
 
 
 #if defined(CONFIG_SECURE_TOUCH)
-static void mxt_secure_touch_stop(struct mxt_data *data)
+static void mxt_secure_touch_stop(struct mxt_data *data, int blocking)
 {
 	if (atomic_read(&data->st_enabled)) {
-		complete(&data->st_completion);
-		wait_for_completion_interruptible(&data->st_powerdown);
+		atomic_set(&data->st_pending_irqs, -1);
+		mxt_secure_touch_notify(data);
+		if (blocking)
+			wait_for_completion_interruptible(&data->st_powerdown);
 	}
 }
 #else
-static void mxt_secure_touch_stop(struct mxt_data *data)
+static void mxt_secure_touch_stop(struct mxt_data *data, int blocking)
 {
 }
 #endif
@@ -2090,7 +2093,7 @@
 static int mxt_start(struct mxt_data *data)
 {
 	int error;
-	mxt_secure_touch_stop(data);
+	mxt_secure_touch_stop(data, 1);
 
 	/* restore the old power state values and reenable touch */
 	error = __mxt_write_reg(data->client, data->t7_start_addr,
@@ -2108,7 +2111,7 @@
 {
 	int error;
 	u8 t7_data[T7_DATA_SIZE] = {0};
-	mxt_secure_touch_stop(data);
+	mxt_secure_touch_stop(data, 1);
 
 	error = __mxt_write_reg(data->client, data->t7_start_addr,
 				T7_DATA_SIZE, t7_data);
@@ -2523,7 +2526,7 @@
 
 	/* calibrate */
 	if (data->pdata->need_calibration) {
-		mxt_secure_touch_stop(data);
+		mxt_secure_touch_stop(data, 1);
 		error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
 					MXT_COMMAND_CALIBRATE, 1);
 		if (error < 0)
@@ -2836,13 +2839,14 @@
 	struct mxt_data *mxt_dev_data =
 		container_of(self, struct mxt_data, fb_notif);
 
-	if (evdata && evdata->data && event == FB_EVENT_BLANK && mxt_dev_data &&
-			mxt_dev_data->client) {
-		blank = evdata->data;
-		if (*blank == FB_BLANK_UNBLANK)
-			mxt_resume(&mxt_dev_data->client->dev);
-		else if (*blank == FB_BLANK_POWERDOWN)
-			mxt_suspend(&mxt_dev_data->client->dev);
+	if (evdata && evdata->data && mxt_dev_data && mxt_dev_data->client) {
+		if (event == FB_EVENT_BLANK) {
+			blank = evdata->data;
+			if (*blank == FB_BLANK_UNBLANK)
+				mxt_resume(&mxt_dev_data->client->dev);
+			else if (*blank == FB_BLANK_POWERDOWN)
+				mxt_suspend(&mxt_dev_data->client->dev);
+		}
 	}
 
 	return 0;
@@ -2867,7 +2871,6 @@
 #if defined(CONFIG_SECURE_TOUCH)
 static void __devinit mxt_secure_touch_init(struct mxt_data *data)
 {
-	init_completion(&data->st_completion);
 	init_completion(&data->st_powerdown);
 }
 #else
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index bdac3fd..aa8159f 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -22,6 +22,7 @@
  */
 
 #include "gt9xx.h"
+#include <linux/mutex.h>
 
 #define DATA_LENGTH_UINT    512
 #define CMD_HEAD_LENGTH     (sizeof(st_cmd_head) - sizeof(u8 *))
@@ -53,6 +54,8 @@
 
 static struct proc_dir_entry *goodix_proc_entry;
 
+static struct mutex lock;
+
 static s32 goodix_tool_write(struct file *filp, const char __user *buff,
 						unsigned long len, void *data);
 static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
@@ -188,7 +191,7 @@
 
 s32 init_wr_node(struct i2c_client *client)
 {
-	s32 i;
+	u8 i;
 
 	gt_client = client;
 	memset(&cmd_head, 0, sizeof(cmd_head));
@@ -202,8 +205,8 @@
 		i--;
 	}
 	if (i) {
-		DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
-		GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+		DATA_LENGTH = i * DATA_LENGTH_UINT;
+		dev_dbg(&client->dev, "Applied memory size:%d.", DATA_LENGTH);
 	} else {
 		GTP_ERROR("Apply for memory failed.");
 		return FAIL;
@@ -214,8 +217,9 @@
 
 	register_i2c_func();
 
+	mutex_init(&lock);
 	tool_set_proc_name(procname);
-	goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+	goodix_proc_entry = create_proc_entry(procname, 0660, NULL);
 	if (goodix_proc_entry == NULL) {
 		GTP_ERROR("Couldn't create proc entry!");
 		return FAIL;
@@ -334,9 +338,13 @@
 	GTP_DEBUG_FUNC();
 	GTP_DEBUG_ARRAY((u8 *)buff, len);
 
+	mutex_lock(&lock);
 	ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
-	if (ret)
+	if (ret) {
 		GTP_ERROR("copy_from_user failed.");
+		ret = -EACCES;
+		goto exit;
+	}
 
 	GTP_DEBUG("wr  :0x%02x.", cmd_head.wr);
 	GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
@@ -354,6 +362,19 @@
 	GTP_DEBUG("len:%d.", (s32)len);
 	GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
 
+	if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) {
+		pr_err("data len %d > data buff %d, rejected!\n",
+			cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH));
+		ret = -EINVAL;
+		goto exit;
+	}
+	if (cmd_head.addr_len > GTP_ADDR_LENGTH) {
+		pr_err(" addr len %d > data buff %d, rejected!\n",
+			cmd_head.addr_len, GTP_ADDR_LENGTH);
+		ret = -EINVAL;
+		goto exit;
+	}
+
 	if (cmd_head.wr == 1) {
 		/*  copy_from_user(&cmd_head.data[cmd_head.addr_len],
 				&buff[CMD_HEAD_LENGTH], cmd_head.data_len); */
@@ -373,7 +394,8 @@
 		if (cmd_head.flag == 1) {
 			if (FAIL == comfirm()) {
 				GTP_ERROR("[WRITE]Comfirm fail!");
-				return FAIL;
+				ret = -EINVAL;
+				goto exit;
 			}
 		} else if (cmd_head.flag == 2) {
 			/* Need interrupt! */
@@ -382,7 +404,8 @@
 		&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
 		cmd_head.data_len + cmd_head.addr_len) <= 0) {
 			GTP_ERROR("[WRITE]Write data failed!");
-			return FAIL;
+			ret = -EIO;
+			goto exit;
 		}
 
 		GTP_DEBUG_ARRAY(
@@ -391,7 +414,8 @@
 		if (cmd_head.delay)
 			msleep(cmd_head.delay);
 
-		return cmd_head.data_len + CMD_HEAD_LENGTH;
+		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+		goto exit;
 	} else if (cmd_head.wr == 3) {  /* Write ic type */
 
 		ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
@@ -399,30 +423,40 @@
 		if (ret)
 			GTP_ERROR("copy_from_user failed.");
 
+		if (cmd_head.data_len > sizeof(IC_TYPE)) {
+			pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
+			cmd_head.data_len, sizeof(IC_TYPE));
+			ret = -EINVAL;
+			goto exit;
+		}
 		memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
 
 		register_i2c_func();
 
-		return cmd_head.data_len + CMD_HEAD_LENGTH;
-	} else if (cmd_head.wr == 3) {
+		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+		goto exit;
+	} else if (cmd_head.wr == 5) {
 
 		/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
 
-		return cmd_head.data_len + CMD_HEAD_LENGTH;
+		ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+		goto exit;
 	} else if (cmd_head.wr == 7) { /* disable irq! */
 		gtp_irq_disable(i2c_get_clientdata(gt_client));
 
 		#if GTP_ESD_PROTECT
 		gtp_esd_switch(gt_client, SWITCH_OFF);
 		#endif
-		return CMD_HEAD_LENGTH;
+		ret = CMD_HEAD_LENGTH;
+		goto exit;
 	} else if (cmd_head.wr == 9) { /* enable irq! */
 		gtp_irq_enable(i2c_get_clientdata(gt_client));
 
 		#if GTP_ESD_PROTECT
 		gtp_esd_switch(gt_client, SWITCH_ON);
 		#endif
-		return CMD_HEAD_LENGTH;
+		ret = CMD_HEAD_LENGTH;
+		goto exit;
 	} else if (cmd_head.wr == 17) {
 		struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
 		ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
@@ -436,27 +470,41 @@
 			ts->gtp_rawdiff_mode = false;
 			GTP_DEBUG("gtp leave rawdiff.");
 		}
-		return CMD_HEAD_LENGTH;
+		ret = CMD_HEAD_LENGTH;
+		goto exit;
 	}
 #ifdef UPDATE_FUNCTIONS
 	else if (cmd_head.wr == 11) { /* Enter update mode! */
-		if (FAIL == gup_enter_update_mode(gt_client))
-			return FAIL;
+		if (FAIL == gup_enter_update_mode(gt_client)) {
+			ret = -EBUSY;
+			goto exit;
+		}
 	} else if (cmd_head.wr == 13) { /* Leave update mode! */
 		gup_leave_update_mode();
 	} else if (cmd_head.wr == 15) { /* Update firmware! */
 		show_len = 0;
 		total_len = 0;
+		if (cmd_head.data_len + 1 > DATA_LENGTH) {
+			pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
+			cmd_head.data_len + 1, DATA_LENGTH);
+			ret = -EINVAL;
+			goto exit;
+		}
 		memset(cmd_head.data, 0, cmd_head.data_len + 1);
 		memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
 					cmd_head.data_len);
 
-		if (FAIL == gup_update_proc((void *)cmd_head.data))
-			return FAIL;
+		if (FAIL == gup_update_proc((void *)cmd_head.data)) {
+			ret = -EBUSY;
+			goto exit;
+		}
 	}
 #endif
+	ret = CMD_HEAD_LENGTH;
 
-	return CMD_HEAD_LENGTH;
+exit:
+	mutex_unlock(&lock);
+	return ret;
 }
 
 /*******************************************************
@@ -470,10 +518,14 @@
 static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
 							int *eof, void *data)
 {
+	s32 ret;
 	GTP_DEBUG_FUNC();
 
+	mutex_lock(&lock);
 	if (cmd_head.wr % 2) {
-		return FAIL;
+		pr_err("<< [READ]command head wrong\n");
+		ret = -EINVAL;
+		goto exit;
 	} else if (!cmd_head.wr) {
 		u16 len = 0;
 		s16 data_len = 0;
@@ -482,7 +534,8 @@
 		if (cmd_head.flag == 1) {
 			if (FAIL == comfirm()) {
 				GTP_ERROR("[READ]Comfirm fail!");
-				return FAIL;
+				ret = -EINVAL;
+				goto exit;
 			}
 		} else if (cmd_head.flag == 2) {
 			/* Need interrupt! */
@@ -505,11 +558,12 @@
 			else
 				len = data_len;
 
-			data_len -= DATA_LENGTH;
+			data_len -= len;
 
 			if (tool_i2c_read(cmd_head.data, len) <= 0) {
 				GTP_ERROR("[READ]Read data failed!");
-				return FAIL;
+				ret = -EINVAL;
+				goto exit;
 			}
 			memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
 									len);
@@ -525,15 +579,14 @@
 
 		GTP_DEBUG("Return ic type:%s len:%d.", page,
 						(s32)cmd_head.data_len);
-		return cmd_head.data_len;
+		ret = cmd_head.data_len;
+		goto exit;
 		/* return sizeof(IC_TYPE_NAME); */
 	} else if (cmd_head.wr == 4) {
 		page[0] = show_len >> 8;
 		page[1] = show_len & 0xff;
 		page[2] = total_len >> 8;
 		page[3] = total_len & 0xff;
-
-		return cmd_head.data_len;
 	} else if (6 == cmd_head.wr) {
 		/* Read error code! */
 	} else if (8 == cmd_head.wr) { /*Read driver version */
@@ -544,6 +597,9 @@
 		memcpy(page, GTP_DRIVER_VERSION, tmp_len);
 		page[tmp_len] = 0;
 	}
+	ret = cmd_head.data_len;
 
-	return cmd_head.data_len;
+exit:
+	mutex_unlock(&lock);
+	return ret;
 }
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 0a92d51..70c1307 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -2031,6 +2031,9 @@
 static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
 		unsigned char intr_mask)
 {
+	if (!fwu)
+		return;
+
 	if (fwu->intr_mask & intr_mask)
 		fwu->interrupt_flag = true;
 
@@ -2116,6 +2119,7 @@
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Failed to alloc mem for fwu\n",
 				__func__);
+		retval = -ENOMEM;
 		goto exit;
 	}
 
@@ -2141,10 +2145,12 @@
 		dev_dbg(&rmi4_data->i2c_client->dev,
 				"%s: Failed to read PDT properties, assuming 0x00\n",
 				__func__);
+		goto exit_free_mem;
 	} else if (pdt_props.has_bsr) {
 		dev_err(&rmi4_data->i2c_client->dev,
 				"%s: Reflash for LTS not currently supported\n",
 				__func__);
+		retval = -EINVAL;
 		goto exit_free_mem;
 	}
 
@@ -2243,7 +2249,7 @@
 	fwu = NULL;
 
 exit:
-	return 0;
+	return retval;
 }
 
 static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index aec655c..4e75971 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -2378,8 +2378,12 @@
 				link) {
 			if ((exp_fhandler->func_init != NULL) &&
 					(exp_fhandler->inserted == false)) {
-				exp_fhandler->func_init(rmi4_data);
-				exp_fhandler->inserted = true;
+				if (exp_fhandler->func_init(rmi4_data) < 0) {
+					list_del(&exp_fhandler->link);
+					kfree(exp_fhandler);
+				} else {
+					exp_fhandler->inserted = true;
+				}
 			} else if ((exp_fhandler->func_init == NULL) &&
 					(exp_fhandler->inserted == true)) {
 				exp_fhandler->func_remove(rmi4_data);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index 32d74ba..16a1616 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -41,6 +41,7 @@
 	struct msm_actuator_move_params_t *move_params)
 {
 	int32_t rc = 0;
+	struct msm_camera_i2c_reg_setting reg_setting;
 	CDBG("Enter\n");
 
 	if (a_ctrl->curr_step_pos != 0) {
@@ -49,10 +50,12 @@
 			a_ctrl->initial_code, 0, 0);
 		a_ctrl->func_tbl->actuator_parse_i2c_params(a_ctrl,
 			a_ctrl->initial_code, 0, 0);
+		reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+		reg_setting.data_type = a_ctrl->i2c_data_type;
+		reg_setting.size = a_ctrl->i2c_tbl_index;
 		rc = a_ctrl->i2c_client.i2c_func_tbl->
 			i2c_write_table_w_microdelay(
-			&a_ctrl->i2c_client, a_ctrl->i2c_reg_tbl,
-			a_ctrl->i2c_tbl_index, a_ctrl->i2c_data_type);
+			&a_ctrl->i2c_client, &reg_setting);
 		if (rc < 0) {
 			pr_err("%s: i2c write error:%d\n",
 				__func__, rc);
@@ -73,7 +76,7 @@
 	uint16_t i2c_byte1 = 0, i2c_byte2 = 0;
 	uint16_t value = 0;
 	uint32_t size = a_ctrl->reg_tbl_size, i = 0;
-	struct msm_camera_i2c_reg_tbl *i2c_tbl = a_ctrl->i2c_reg_tbl;
+	struct msm_camera_i2c_reg_array *i2c_tbl = a_ctrl->i2c_reg_tbl;
 	CDBG("Enter\n");
 	for (i = 0; i < size; i++) {
 		if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {
@@ -195,6 +198,7 @@
 	int32_t dest_step_position = move_params->dest_step_pos;
 	int32_t rc = 0;
 	int32_t num_steps = move_params->num_steps;
+	struct msm_camera_i2c_reg_setting reg_setting;
 	CDBG("Enter\n");
 
 	if (num_steps == 0)
@@ -206,10 +210,11 @@
 		a_ctrl->region_params[0].code_per_step),
 		move_params->ringing_params[0].hw_params, 0);
 
+	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+	reg_setting.data_type = a_ctrl->i2c_data_type;
+	reg_setting.size = a_ctrl->i2c_tbl_index;
 	rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
-		&a_ctrl->i2c_client,
-		a_ctrl->i2c_reg_tbl, a_ctrl->i2c_tbl_index,
-		a_ctrl->i2c_data_type);
+		&a_ctrl->i2c_client, &reg_setting);
 	if (rc < 0) {
 		pr_err("i2c write error:%d\n", rc);
 		return rc;
@@ -233,6 +238,7 @@
 	uint16_t curr_lens_pos = 0;
 	int dir = move_params->dir;
 	int32_t num_steps = move_params->num_steps;
+	struct msm_camera_i2c_reg_setting reg_setting;
 
 	CDBG("called, dir %d, num_steps %d\n", dir, num_steps);
 
@@ -280,10 +286,11 @@
 		a_ctrl->curr_step_pos = target_step_pos;
 	}
 
+	reg_setting.reg_setting = a_ctrl->i2c_reg_tbl;
+	reg_setting.data_type = a_ctrl->i2c_data_type;
+	reg_setting.size = a_ctrl->i2c_tbl_index;
 	rc = a_ctrl->i2c_client.i2c_func_tbl->i2c_write_table_w_microdelay(
-		&a_ctrl->i2c_client,
-		a_ctrl->i2c_reg_tbl, a_ctrl->i2c_tbl_index,
-		a_ctrl->i2c_data_type);
+		&a_ctrl->i2c_client, &reg_setting);
 	if (rc < 0) {
 		pr_err("i2c write error:%d\n", rc);
 		return rc;
@@ -439,7 +446,7 @@
 	kfree(a_ctrl->i2c_reg_tbl);
 
 	a_ctrl->i2c_reg_tbl =
-		kmalloc(sizeof(struct msm_camera_i2c_reg_tbl) *
+		kmalloc(sizeof(struct msm_camera_i2c_reg_array) *
 		(set_info->af_tuning_params.total_steps + 1), GFP_KERNEL);
 	if (!a_ctrl->i2c_reg_tbl) {
 		pr_err("kmalloc fail\n");
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
index c4a4137..809c9cf 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.h
@@ -77,7 +77,7 @@
 	uint32_t total_steps;
 	uint16_t pwd_step;
 	uint16_t initial_code;
-	struct msm_camera_i2c_reg_tbl *i2c_reg_tbl;
+	struct msm_camera_i2c_reg_array *i2c_reg_tbl;
 	uint16_t i2c_tbl_index;
 	enum cci_i2c_master_t cci_master;
 	uint32_t subdev_id;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index d11798e..968dcd7 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -26,6 +26,8 @@
 #define V4L2_IDENT_CCI 50005
 #define CCI_I2C_QUEUE_0_SIZE 64
 #define CCI_I2C_QUEUE_1_SIZE 16
+#define CYCLES_PER_MICRO_SEC 4915
+#define CCI_MAX_DELAY 10000
 
 #define CCI_TIMEOUT msecs_to_jiffies(100)
 
@@ -178,13 +180,13 @@
 {
 	uint16_t i = 0, j = 0, k = 0, h = 0, len = 0;
 	int32_t rc = 0;
-	uint32_t cmd = 0;
+	uint32_t cmd = 0, delay = 0;
 	uint8_t data[10];
 	uint16_t reg_addr = 0;
-	struct msm_camera_cci_i2c_write_cfg *i2c_msg =
+	struct msm_camera_i2c_reg_setting *i2c_msg =
 		&c_ctrl->cfg.cci_i2c_write_cfg;
 	uint16_t cmd_size = i2c_msg->size;
-	struct msm_camera_i2c_reg_conf *i2c_cmd = i2c_msg->reg_conf_tbl;
+	struct msm_camera_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting;
 	enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
 
 	if (i2c_cmd == NULL) {
@@ -213,6 +215,7 @@
 	while (cmd_size) {
 		CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
 			cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
+		delay = i2c_cmd->delay;
 		data[i++] = CCI_I2C_WRITE_CMD;
 		if (i2c_cmd->reg_addr)
 			reg_addr = i2c_cmd->reg_addr;
@@ -257,6 +260,17 @@
 				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
 				master * 0x200 + queue * 0x100);
 		}
+		if ((delay > 0) && (delay < CCI_MAX_DELAY)) {
+			cmd = (uint32_t)((delay * CYCLES_PER_MICRO_SEC) /
+				0x100);
+			cmd <<= 4;
+			cmd |= CCI_I2C_WAIT_CMD;
+			CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n",
+				__func__, cmd);
+			msm_camera_io_w(cmd, cci_dev->base +
+				CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
+				master * 0x200 + queue * 0x100);
+		}
 		i = 0;
 	}
 	return rc;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
index 16edaae..6067f26 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
@@ -64,13 +64,6 @@
 	uint16_t i2c_queue;
 };
 
-struct msm_camera_cci_i2c_write_cfg {
-	struct msm_camera_i2c_reg_conf *reg_conf_tbl;
-	enum msm_camera_i2c_reg_addr_type addr_type;
-	enum msm_camera_i2c_data_type data_type;
-	uint16_t size;
-};
-
 struct msm_camera_cci_i2c_read_cfg {
 	uint16_t addr;
 	enum msm_camera_i2c_reg_addr_type addr_type;
@@ -90,7 +83,7 @@
 	struct msm_camera_cci_client *cci_info;
 	enum msm_cci_cmd_type cmd;
 	union {
-		struct msm_camera_cci_i2c_write_cfg cci_i2c_write_cfg;
+		struct msm_camera_i2c_reg_setting cci_i2c_write_cfg;
 		struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg;
 		struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
 		struct msm_camera_cci_gpio_cfg gpio_cfg;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
index 3792247..8d9274b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c
@@ -108,7 +108,7 @@
 {
 	int32_t rc = -EFAULT;
 	struct msm_camera_cci_ctrl cci_ctrl;
-	struct msm_camera_i2c_reg_conf reg_conf_tbl;
+	struct msm_camera_i2c_reg_array reg_conf_tbl;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
@@ -122,7 +122,7 @@
 	reg_conf_tbl.reg_data = data;
 	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
 	cci_ctrl.cci_info = client->cci_client;
-	cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = &reg_conf_tbl;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = &reg_conf_tbl;
 	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.size = 1;
@@ -142,7 +142,7 @@
 	int32_t rc = -EFAULT;
 	uint8_t i = 0;
 	struct msm_camera_cci_ctrl cci_ctrl;
-	struct msm_camera_i2c_reg_conf reg_conf_tbl[num_byte];
+	struct msm_camera_i2c_reg_array reg_conf_tbl[num_byte];
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
@@ -152,13 +152,15 @@
 	S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n",
 			  __func__, addr, num_byte);
 	memset(reg_conf_tbl, 0,
-		num_byte * sizeof(struct msm_camera_i2c_reg_conf));
+		num_byte * sizeof(struct msm_camera_i2c_reg_array));
 	reg_conf_tbl[0].reg_addr = addr;
-	for (i = 0; i < num_byte; i++)
+	for (i = 0; i < num_byte; i++) {
 		reg_conf_tbl[i].reg_data = data[i];
+		reg_conf_tbl[i].delay = 0;
+	}
 	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
 	cci_ctrl.cci_info = client->cci_client;
-	cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = reg_conf_tbl;
 	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = MSM_CAMERA_I2C_BYTE_DATA;
 	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
 	cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte;
@@ -173,10 +175,8 @@
 	struct msm_camera_i2c_client *client,
 	struct msm_camera_i2c_reg_setting *write_setting)
 {
-	int i;
 	int32_t rc = -EFAULT;
-	struct msm_camera_i2c_reg_array *reg_setting;
-	uint16_t client_addr_type;
+	struct msm_camera_cci_ctrl cci_ctrl;
 
 	if (!client || !write_setting)
 		return rc;
@@ -187,24 +187,26 @@
 		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	reg_setting = write_setting->reg_setting;
-	client_addr_type = client->addr_type;
-	client->addr_type = write_setting->addr_type;
-
-	for (i = 0; i < write_setting->size; i++) {
-		rc = msm_camera_cci_i2c_write(client, reg_setting->reg_addr,
-			reg_setting->reg_data, write_setting->data_type);
-		if (rc < 0)
-			return rc;
-		reg_setting++;
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting =
+		write_setting->reg_setting;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
 	}
+	rc = cci_ctrl.status;
 	if (write_setting->delay > 20)
 		msleep(write_setting->delay);
 	else if (write_setting->delay)
 		usleep_range(write_setting->delay * 1000, (write_setting->delay
 			* 1000) + 1000);
 
-	client->addr_type = client_addr_type;
 	return rc;
 }
 
@@ -250,30 +252,34 @@
 
 int32_t msm_camera_cci_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type)
+	struct msm_camera_i2c_reg_setting *write_setting)
 {
-	int i;
 	int32_t rc = -EFAULT;
+	struct msm_camera_cci_ctrl cci_ctrl;
 
-	if (!client || !reg_tbl)
+	if (!client || !write_setting)
 		return rc;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
-		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
-		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	for (i = 0; i < size; i++) {
-		rc = msm_camera_cci_i2c_write(client, reg_tbl->reg_addr,
-			reg_tbl->reg_data, data_type);
-		if (rc < 0)
-			return rc;
-		if (reg_tbl->delay)
-			usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
-		reg_tbl++;
+	cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
+	cci_ctrl.cci_info = client->cci_client;
+	cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting =
+		write_setting->reg_setting;
+	cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
+	cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size;
+	rc = v4l2_subdev_call(client->cci_client->cci_subdev,
+			core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
+	if (rc < 0) {
+		pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
+		return rc;
 	}
+	rc = cci_ctrl.status;
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
index 389e9d9..763c131 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_i2c.h
@@ -25,12 +25,6 @@
 	enum msm_camera_i2c_reg_addr_type addr_type;
 };
 
-struct msm_camera_i2c_reg_tbl {
-	uint16_t reg_addr;
-	uint16_t reg_data;
-	uint16_t delay;
-};
-
 struct msm_camera_i2c_fn_t {
 	int (*i2c_read) (struct msm_camera_i2c_client *, uint32_t, uint16_t *,
 		enum msm_camera_i2c_data_type);
@@ -46,8 +40,7 @@
 		struct msm_camera_i2c_seq_reg_setting *);
 	int32_t (*i2c_write_table_w_microdelay)
 		(struct msm_camera_i2c_client *,
-		struct msm_camera_i2c_reg_tbl *, uint16_t,
-		enum msm_camera_i2c_data_type);
+		struct msm_camera_i2c_reg_setting *);
 	int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t);
 	int32_t (*i2c_write_conf_tbl)(struct msm_camera_i2c_client *client,
 		struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
@@ -81,8 +74,7 @@
 
 int32_t msm_camera_cci_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type);
+	struct msm_camera_i2c_reg_setting *write_setting);
 
 int32_t msm_camera_cci_i2c_write_conf_tbl(
 	struct msm_camera_i2c_client *client,
@@ -118,8 +110,7 @@
 
 int32_t msm_camera_qup_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type);
+	struct msm_camera_i2c_reg_setting *write_setting);
 
 int32_t msm_camera_qup_i2c_write_conf_tbl(
 	struct msm_camera_i2c_client *client,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
index 60d1509..d5b89b7 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c
@@ -308,29 +308,31 @@
 
 int32_t msm_camera_qup_i2c_write_table_w_microdelay(
 	struct msm_camera_i2c_client *client,
-	struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
-	enum msm_camera_i2c_data_type data_type)
+	struct msm_camera_i2c_reg_setting *write_setting)
 {
 	int i;
 	int32_t rc = -EFAULT;
+	struct msm_camera_i2c_reg_array *reg_setting = NULL;
 
-	if (!client || !reg_tbl)
+	if (!client || !write_setting)
 		return rc;
 
 	if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
 		&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
-		|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
-		&& data_type != MSM_CAMERA_I2C_WORD_DATA))
+		|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
+		&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
 		return rc;
 
-	for (i = 0; i < size; i++) {
-		rc = msm_camera_qup_i2c_write(client, reg_tbl->reg_addr,
-			reg_tbl->reg_data, data_type);
+	reg_setting = write_setting->reg_setting;
+	for (i = 0; i < write_setting->size; i++) {
+		rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr,
+			reg_setting->reg_data, write_setting->data_type);
 		if (rc < 0)
 			break;
-		if (reg_tbl->delay)
-			usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
-		reg_tbl++;
+		if (reg_setting->delay)
+			usleep_range(reg_setting->delay,
+				reg_setting->delay + 1000);
+		reg_setting++;
 	}
 	return rc;
 }
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 6ef389c..e5315bd 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1384,15 +1384,25 @@
 static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
+	struct request_queue *q = mq->queue;
 	struct mmc_card *card = md->queue.card;
 	int ret = 0;
 
 	ret = mmc_flush_cache(card);
-	if (ret)
+	if (ret == -ETIMEDOUT) {
+		pr_info("%s: requeue flush request after timeout", __func__);
+		spin_lock_irq(q->queue_lock);
+		blk_requeue_request(q, req);
+		spin_unlock_irq(q->queue_lock);
+		ret = 0;
+		goto exit;
+	} else if (ret) {
+		pr_err("%s: notify flush error to upper layers", __func__);
 		ret = -EIO;
+	}
 
 	blk_end_request_all(req, ret);
-
+exit:
 	return ret ? 0 : 1;
 }
 
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 91efb12..1e2d367 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -60,7 +60,7 @@
 #define MMC_BKOPS_MAX_TIMEOUT	(30 * 1000) /* max time to wait in ms */
 
 /* Flushing a large amount of cached data may take a long time. */
-#define MMC_FLUSH_REQ_TIMEOUT_MS 30000 /* msec */
+#define MMC_FLUSH_REQ_TIMEOUT_MS 90000 /* msec */
 
 static struct workqueue_struct *workqueue;
 
@@ -3339,7 +3339,7 @@
 						EXT_CSD_FLUSH_CACHE, 1,
 						MMC_FLUSH_REQ_TIMEOUT_MS);
 		if (err == -ETIMEDOUT) {
-			pr_debug("%s: cache flush timeout\n",
+			pr_err("%s: cache flush timeout\n",
 					mmc_hostname(card->host));
 			rc = mmc_interrupt_hpi(card);
 			if (rc)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index a7ce6ae..2c8598b 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2687,6 +2687,9 @@
 		goto vreg_deinit;
 	}
 
+	/* Unset HC_MODE_EN bit in HC_MODE register */
+	writel_relaxed(0, (msm_host->core_mem + CORE_HC_MODE));
+
 	/* Set SW_RST bit in POWER register (Offset 0x0) */
 	writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
 			CORE_SW_RST, msm_host->core_mem + CORE_POWER);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f9f3802..0cb0491 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -110,7 +110,7 @@
 		sdhci_readl(host, SDHCI_INT_ENABLE),
 		sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
 	pr_info(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
-		sdhci_readw(host, SDHCI_ACMD12_ERR),
+		sdhci_readw(host, SDHCI_AUTO_CMD_ERR),
 		sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
 	pr_info(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n",
 		sdhci_readl(host, SDHCI_CAPABILITIES),
@@ -118,6 +118,12 @@
 	pr_info(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
 		sdhci_readw(host, SDHCI_COMMAND),
 		sdhci_readl(host, SDHCI_MAX_CURRENT));
+	pr_info(DRIVER_NAME ": Resp 1:   0x%08x | Resp 0:   0x%08x\n",
+		sdhci_readl(host, SDHCI_RESPONSE + 0x4),
+		sdhci_readl(host, SDHCI_RESPONSE));
+	pr_info(DRIVER_NAME ": Resp 3:   0x%08x | Resp 2:   0x%08x\n",
+		sdhci_readl(host, SDHCI_RESPONSE + 0xC),
+		sdhci_readl(host, SDHCI_RESPONSE + 0x8));
 	pr_info(DRIVER_NAME ": Host ctl2: 0x%08x\n",
 		sdhci_readw(host, SDHCI_HOST_CONTROL2));
 
@@ -278,7 +284,8 @@
 		SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
 		SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
 		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
-		SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+		SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |
+			     SDHCI_INT_AUTO_CMD_ERR);
 
 	if (soft) {
 		/* force clock reconfiguration */
@@ -2440,6 +2447,7 @@
 
 static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 {
+	u16 auto_cmd_status;
 	BUG_ON(intmask == 0);
 
 	if (!host->cmd) {
@@ -2456,6 +2464,18 @@
 			SDHCI_INT_INDEX))
 		host->cmd->error = -EILSEQ;
 
+	if (intmask & SDHCI_INT_AUTO_CMD_ERR) {
+		auto_cmd_status = sdhci_readw(host, SDHCI_AUTO_CMD_ERR);
+		if (auto_cmd_status & (SDHCI_AUTO_CMD12_NOT_EXEC |
+				       SDHCI_AUTO_CMD_INDEX_ERR |
+				       SDHCI_AUTO_CMD_ENDBIT_ERR))
+			host->cmd->error = -EIO;
+		else if (auto_cmd_status & SDHCI_AUTO_CMD_TIMEOUT_ERR)
+			host->cmd->error = -ETIMEDOUT;
+		else if (auto_cmd_status & SDHCI_AUTO_CMD_CRC_ERR)
+			host->cmd->error = -EILSEQ;
+	}
+
 	if (host->quirks2 & SDHCI_QUIRK2_IGNORE_CMDCRC_FOR_TUNING) {
 		if ((host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS400) ||
 			(host->cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) ||
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index a3d8442..3db99c4 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -135,21 +135,29 @@
 #define  SDHCI_INT_DATA_CRC	0x00200000
 #define  SDHCI_INT_DATA_END_BIT	0x00400000
 #define  SDHCI_INT_BUS_POWER	0x00800000
-#define  SDHCI_INT_ACMD12ERR	0x01000000
+#define  SDHCI_INT_AUTO_CMD_ERR	0x01000000
 #define  SDHCI_INT_ADMA_ERROR	0x02000000
 
 #define  SDHCI_INT_NORMAL_MASK	0x00007FFF
 #define  SDHCI_INT_ERROR_MASK	0xFFFF8000
 
 #define  SDHCI_INT_CMD_MASK	(SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
-		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
+		SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX | \
+				 SDHCI_INT_AUTO_CMD_ERR)
+
 #define  SDHCI_INT_DATA_MASK	(SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
 		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
 		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
 		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
 #define SDHCI_INT_ALL_MASK	((unsigned int)-1)
 
-#define SDHCI_ACMD12_ERR	0x3C
+#define SDHCI_AUTO_CMD_ERR		0x3C
+#define SDHCI_AUTO_CMD12_NOT_EXEC	0x0001
+#define SDHCI_AUTO_CMD_TIMEOUT_ERR	0x0002
+#define SDHCI_AUTO_CMD_CRC_ERR		0x0004
+#define SDHCI_AUTO_CMD_ENDBIT_ERR	0x0008
+#define SDHCI_AUTO_CMD_INDEX_ERR	0x0010
+#define SDHCI_AUTO_CMD12_NOT_ISSUED	0x0080
 
 #define SDHCI_HOST_CONTROL2		0x3E
 #define  SDHCI_CTRL_UHS_MASK		0x0007
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index d35bdaa..64d1478 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -98,6 +98,12 @@
 #define PRONTO_PMU_CBCR_OFFSET        0x0008
 #define PRONTO_PMU_CBCR_CLK_EN        BIT(0)
 
+#define PRONTO_PMU_COM_CPU_CBCR_OFFSET     0x0030
+#define PRONTO_PMU_COM_AHB_CBCR_OFFSET     0x0034
+#define PRONTO_PMU_CFG_OFFSET              0x1004
+#define PRONTO_PMU_COM_CSR_OFFSET          0x1040
+#define PRONTO_PMU_SOFT_RESET_OFFSET       0x104C
+
 #define MSM_PRONTO_A2XB_BASE		0xfb100400
 #define A2XB_CFG_OFFSET				0x00
 #define A2XB_INT_SRC_OFFSET			0x0c
@@ -477,8 +483,34 @@
 	reg = readl_relaxed(reg_addr);
 	pr_info_ratelimited("%s:  PRONTO_PMU_SPARE %08x\n", __func__, reg);
 
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CPU_CBCR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_AHB_CBCR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_CFG %08x\n", __func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CSR %08x\n",
+						__func__, reg);
+
+	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_SOFT_RESET %08x\n",
+						__func__, reg);
+
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
+	pr_info_ratelimited("%s:  PRONTO_PMU_COM_GDSCR %08x\n",
+						__func__, reg);
 	reg >>= 31;
 
 	if (!reg) {
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 1cf901e..8d9da6b 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -89,14 +89,30 @@
 }
 EXPORT_SYMBOL(sensor_get_id);
 
+static long get_min(struct sensor_info *sensor, long temp)
+{
+	long min = LONG_MIN;
+	struct sensor_threshold *pos, *var;
+
+	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW)
+			if (pos->temp < temp && pos->temp > min)
+				min = pos->temp;
+	}
+
+	return min;
+}
+
 static void __update_sensor_thresholds(struct sensor_info *sensor)
 {
-	int min = INT_MIN;
-	int max = INT_MAX;
+	long min = LONG_MIN;
+	long max = LONG_MAX;
+	long max_of_min = LONG_MIN;
+	long min_of_max = LONG_MAX;
 	struct sensor_threshold *pos, *var;
 	enum thermal_trip_type type;
 	int i;
-	unsigned long curr_temp;
+	long curr_temp;
 
 	for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
 		(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
@@ -106,36 +122,58 @@
 			sensor->max_idx = i;
 		if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
 			sensor->min_idx = i;
+		sensor->tz->ops->get_trip_temp(sensor->tz,
+			THERMAL_TRIP_CONFIGURABLE_LOW, &sensor->threshold_min);
+		sensor->tz->ops->get_trip_temp(sensor->tz,
+			THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max);
 	}
 
-	get_cpu();
 	sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
 	list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
-		if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
-				(pos->temp < (int)curr_temp))
-			if (pos->temp > min)
+		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) {
+			if (pos->temp > max_of_min)
+				max_of_min = pos->temp;
+			if (pos->temp < curr_temp && pos->temp > min)
 				min = pos->temp;
-		if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
-				(pos->temp > (int)curr_temp))
-			if (pos->temp < max)
+		}
+		if (pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) {
+			if (pos->temp < min_of_max)
+				min_of_max = pos->temp;
+			if (pos->temp > curr_temp && pos->temp < max)
 				max = pos->temp;
+		}
 	}
-	put_cpu();
+
+	pr_debug("sensor %d: min of max: %ld max of min: %ld\n",
+			sensor->sensor_id, max_of_min, min_of_max);
+
+	/* If we haven't found a max and min bounding the curr_temp,
+	 * use the min of max and max of min instead.
+	 */
+	if (max == LONG_MAX)
+		max = min_of_max;
+	if (min == LONG_MIN) {
+		min = get_min(sensor, max);
+		if (min == LONG_MIN)
+			min = max_of_min;
+	}
 
 	if (sensor->tz->ops->set_trip_temp) {
-		if (max != INT_MAX) {
+		if (max != sensor->threshold_max) {
 			sensor->tz->ops->set_trip_temp(sensor->tz,
 				sensor->max_idx, max);
 			sensor->threshold_max = max;
 		}
-		if (min != INT_MIN) {
+		if (min != sensor->threshold_min) {
 			sensor->tz->ops->set_trip_temp(sensor->tz,
 				sensor->min_idx, min);
 			sensor->threshold_min = min;
 		}
 	}
 
-	pr_debug("sensor %d, min: %d, max %d\n", sensor->sensor_id, min, max);
+	pr_debug("sensor %d: curr_temp: %ld min: %ld max: %ld\n",
+		sensor->sensor_id, curr_temp,
+		sensor->threshold_min, sensor->threshold_max);
 }
 
 static void sensor_update_work(struct work_struct *work)
@@ -151,7 +189,7 @@
  * Do NOT call sensor_set_trip from this function
  */
 int thermal_sensor_trip(struct thermal_zone_device *tz,
-		enum thermal_trip_type trip, unsigned long temp)
+		enum thermal_trip_type trip, long temp)
 {
 	struct sensor_threshold *pos, *var;
 	int ret = -ENODEV;
@@ -168,10 +206,10 @@
 			continue;
 		if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
 			(pos->temp <= tz->sensor.threshold_min) &&
-			(pos->temp >= (int) temp)) ||
+			(pos->temp >= temp)) ||
 			((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
 				(pos->temp >= tz->sensor.threshold_max) &&
-				(pos->temp <= (int)temp))) {
+				(pos->temp <= temp))) {
 			pos->notify(trip, temp, pos->data);
 		}
 	}
@@ -235,29 +273,6 @@
 }
 EXPORT_SYMBOL(sensor_cancel_trip);
 
-static int sensor_get_trip_temp(struct thermal_zone_device *tz,
-		int type, unsigned long *temp)
-{
-	struct sensor_info *sensor = get_sensor(tz->id);
-
-	if (!sensor)
-		return -EFAULT;
-
-	switch (type) {
-	case THERMAL_TRIP_CONFIGURABLE_HI:
-		*temp = tz->sensor.threshold_max;
-		break;
-	case THERMAL_TRIP_CONFIGURABLE_LOW:
-		*temp = tz->sensor.threshold_min;
-		break;
-	default:
-		tz->ops->get_trip_temp(tz, type, temp);
-		break;
-	}
-
-	return 0;
-}
-
 static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data)
 {
 	struct thermal_zone_device *tz = (struct thermal_zone_device *)data;
@@ -310,7 +325,7 @@
 	sensor->sensor_id = tz->id;
 	sensor->tz = tz;
 	sensor->threshold_min = 0;
-	sensor->threshold_max = INT_MAX;
+	sensor->threshold_max = LONG_MAX;
 	sensor->max_idx = -1;
 	sensor->min_idx = -1;
 	mutex_init(&sensor->lock);
@@ -511,7 +526,7 @@
 	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
 		return -EINVAL;
 
-	ret = sensor_get_trip_temp(tz, trip, &temperature);
+	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
 
 	if (ret)
 		return ret;
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index 9ca3461..531c814 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -65,6 +65,7 @@
 				panel_data);
 
 	if (enable) {
+		dsi_ctrl_gpio_request(ctrl_pdata);
 		mdss_dsi_panel_reset(pdata, 1);
 
 		rc = dsi_cmds_tx_v2(pdata, &dsi_panel_tx_buf,
@@ -82,6 +83,7 @@
 					ctrl_pdata->off_cmds.cmd_cnt);
 
 		mdss_dsi_panel_reset(pdata, 0);
+		dsi_ctrl_gpio_free(ctrl_pdata);
 	}
 	return rc;
 }
@@ -145,59 +147,17 @@
 	ctrl_pdata->disp_en_gpio = of_get_named_gpio(np,
 		"qcom,platform-enable-gpio", 0);
 
-	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+	if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
 		pr_err("%s:%d, Disp_en gpio not specified\n",
 						__func__, __LINE__);
-	} else {
-		rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
-		if (rc) {
-			pr_err("request reset gpio failed, rc=%d\n",
-			       rc);
-			gpio_free(ctrl_pdata->disp_en_gpio);
-			return -ENODEV;
-		}
-	}
 
+	ctrl_pdata->disp_te_gpio = -1;
 	if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) {
 		ctrl_pdata->disp_te_gpio = of_get_named_gpio(np,
 						"qcom,platform-te-gpio", 0);
-		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+		if (!gpio_is_valid(ctrl_pdata->disp_te_gpio))
 			pr_err("%s:%d, Disp_te gpio not specified\n",
 							__func__, __LINE__);
-		} else {
-			rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
-			if (rc) {
-				pr_err("request TE gpio failed, rc=%d\n",
-								       rc);
-				gpio_free(ctrl_pdata->disp_te_gpio);
-				return -ENODEV;
-			}
-			rc = gpio_tlmm_config(GPIO_CFG(
-					ctrl_pdata->disp_te_gpio, 1,
-					GPIO_CFG_INPUT,
-					GPIO_CFG_PULL_DOWN,
-					GPIO_CFG_2MA),
-					GPIO_CFG_ENABLE);
-
-			if (rc) {
-				pr_err("%s: unable to config tlmm = %d\n",
-					__func__, ctrl_pdata->disp_te_gpio);
-				gpio_free(ctrl_pdata->disp_te_gpio);
-				return -ENODEV;
-			}
-
-			rc = gpio_direction_input(ctrl_pdata->disp_te_gpio);
-			if (rc) {
-				pr_err("set_direction for disp_en gpio failed, rc=%d\n",
-								       rc);
-				gpio_free(ctrl_pdata->disp_te_gpio);
-				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-					gpio_free(ctrl_pdata->disp_en_gpio);
-				return -ENODEV;
-			}
-			pr_debug("%s: te_gpio=%d\n", __func__,
-					ctrl_pdata->disp_te_gpio);
-		}
 	}
 
 	rc = of_property_read_u32_array(np,
@@ -211,45 +171,18 @@
 
 	ctrl_pdata->rst_gpio = of_get_named_gpio(np,
 					"qcom,platform-reset-gpio", 0);
-	if (!gpio_is_valid(ctrl_pdata->rst_gpio)) {
+	if (!gpio_is_valid(ctrl_pdata->rst_gpio))
 		pr_err("%s:%d, reset gpio not specified\n",
 						__func__, __LINE__);
-	} else {
-		rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
-		if (rc) {
-			pr_err("request reset gpio failed, rc=%d\n",
-				rc);
-			gpio_free(ctrl_pdata->rst_gpio);
-			if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-				gpio_free(ctrl_pdata->disp_en_gpio);
-			if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
-				gpio_free(ctrl_pdata->disp_te_gpio);
-			return -ENODEV;
-		}
-	}
 
+	ctrl_pdata->mode_gpio = -1;
 	if (ctrl_pdata->panel_data.panel_info.mode_gpio_state !=
 						MODE_GPIO_NOT_VALID) {
 		ctrl_pdata->mode_gpio = of_get_named_gpio(np,
 						"qcom,platform-mode-gpio", 0);
-		if (!gpio_is_valid(ctrl_pdata->mode_gpio)) {
+		if (!gpio_is_valid(ctrl_pdata->mode_gpio))
 			pr_info("%s:%d, reset gpio not specified\n",
 							__func__, __LINE__);
-		} else {
-			rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
-			if (rc) {
-				pr_err("request panel mode gpio failed,rc=%d\n",
-									rc);
-				gpio_free(ctrl_pdata->mode_gpio);
-				if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-					gpio_free(ctrl_pdata->disp_en_gpio);
-				if (gpio_is_valid(ctrl_pdata->rst_gpio))
-					gpio_free(ctrl_pdata->rst_gpio);
-				if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
-					gpio_free(ctrl_pdata->disp_te_gpio);
-				return -ENODEV;
-			}
-		}
 	}
 	return 0;
 }
@@ -268,15 +201,81 @@
 		module_power->vreg_config = NULL;
 	}
 	module_power->num_vreg = 0;
+}
 
-	if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
-		gpio_free(ctrl_pdata->disp_en_gpio);
-	if (gpio_is_valid(ctrl_pdata->rst_gpio))
-		gpio_free(ctrl_pdata->rst_gpio);
+int dsi_ctrl_gpio_request(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	int rc = 0;
+
+	if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
+		rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable");
+		if (rc)
+			goto gpio_request_err4;
+
+		ctrl_pdata->disp_en_gpio_requested = 1;
+	}
+
+	if (gpio_is_valid(ctrl_pdata->rst_gpio)) {
+		rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n");
+		if (rc)
+			goto gpio_request_err3;
+
+		ctrl_pdata->rst_gpio_requested = 1;
+	}
+
+	if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
+		rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
+		if (rc)
+			goto gpio_request_err2;
+
+		ctrl_pdata->disp_te_gpio_requested = 1;
+	}
+
+	if (gpio_is_valid(ctrl_pdata->mode_gpio)) {
+		rc = gpio_request(ctrl_pdata->mode_gpio, "panel_mode");
+		if (rc)
+			goto gpio_request_err1;
+
+		ctrl_pdata->mode_gpio_requested = 1;
+	}
+
+	return rc;
+
+gpio_request_err1:
 	if (gpio_is_valid(ctrl_pdata->disp_te_gpio))
 		gpio_free(ctrl_pdata->disp_te_gpio);
-	if (gpio_is_valid(ctrl_pdata->mode_gpio))
+gpio_request_err2:
+	if (gpio_is_valid(ctrl_pdata->rst_gpio))
+		gpio_free(ctrl_pdata->rst_gpio);
+gpio_request_err3:
+	if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
+		gpio_free(ctrl_pdata->disp_en_gpio);
+gpio_request_err4:
+	ctrl_pdata->disp_en_gpio_requested = 0;
+	ctrl_pdata->rst_gpio_requested = 0;
+	ctrl_pdata->disp_te_gpio_requested = 0;
+	ctrl_pdata->mode_gpio_requested = 0;
+	return rc;
+}
+
+void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+	if (ctrl_pdata->disp_en_gpio_requested) {
+		gpio_free(ctrl_pdata->disp_en_gpio);
+		ctrl_pdata->disp_en_gpio_requested = 0;
+	}
+	if (ctrl_pdata->rst_gpio_requested) {
+		gpio_free(ctrl_pdata->rst_gpio);
+		ctrl_pdata->rst_gpio_requested = 0;
+	}
+	if (ctrl_pdata->disp_te_gpio_requested) {
+		gpio_free(ctrl_pdata->disp_te_gpio);
+		ctrl_pdata->disp_te_gpio_requested = 0;
+	}
+	if (ctrl_pdata->mode_gpio_requested) {
 		gpio_free(ctrl_pdata->mode_gpio);
+		ctrl_pdata->mode_gpio_requested = 0;
+	}
 }
 
 static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index a554856..e15f640 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -70,6 +70,10 @@
 int dsi_ctrl_config_init(struct platform_device *pdev,
 				struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
+int dsi_ctrl_gpio_request(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+
+void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
+
 struct mdss_panel_cfg *mdp3_panel_intf_type(int intf_val);
 
 int mdp3_panel_get_boot_cfg(void);
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 8a5f1ee..eff60a3 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -35,6 +35,9 @@
 #include <linux/uaccess.h>
 #include <linux/file.h>
 #include <linux/msm_kgsl.h>
+#include <linux/major.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
 
 #include <mach/board.h>
 #include <mach/clk.h>
@@ -583,6 +586,41 @@
 	return 0;
 }
 
+struct reg_dump {
+	int start_addr;
+	int num_reads;
+};
+
+struct reg_dump ppp_reg[] = {
+	{0x10108, 3},
+	{0x10118, 6},
+	{0x10138, 9},
+	{0x10158, 1},
+	{0x10164, 7},
+	{0x1019C, 1},
+	{0x101b8, 2},
+	{0x101c0, 8},
+};
+
+static int mdp3_iommu_fault_handler(struct iommu_domain *domain,
+		struct device *dev, unsigned long iova, int flags, void *token)
+{
+	unsigned int addr, val;
+	int i, j;
+	pr_err("MDP IOMMU page fault: iova 0x%lx\n", iova);
+	for (i = 0; i < ARRAY_SIZE(ppp_reg); i++) {
+		for (j = 0; j < ppp_reg[i].num_reads; j++) {
+			addr = ppp_reg[i].start_addr + (j*4);
+			val = MDP3_REG_READ(addr);
+			pr_err("TMsg: Addr= 0x%08x, val= 0x%08x\n",
+				(unsigned int)addr, (unsigned int)val);
+		}
+	}
+	panic("PPP pagefault, shutting down for easier debugging\n");
+	return 0;
+}
+
+
 int mdp3_iommu_attach(int context)
 {
 	struct mdp3_iommu_ctx_map *context_map;
@@ -658,6 +696,9 @@
 			else
 				return PTR_ERR(mdp3_iommu_domains[i].domain);
 		}
+		iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
+			mdp3_iommu_fault_handler,
+			NULL);
 	}
 
 	mdp3_res->domains = mdp3_iommu_domains;
@@ -1594,6 +1635,45 @@
 	}
 }
 
+int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd)
+{
+	struct platform_device *pdev = mfd->pdev;
+	int rc;
+	u32 offsets[2];
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+				"qcom,memblock-reserve", offsets, 2);
+
+	if (rc) {
+		pr_err("fail to get memblock-reserve property\n");
+		return rc;
+	}
+
+	if (mdp3_res->splash_mem_addr != offsets[0])
+		rc = -EINVAL;
+
+	mdp3_res->splash_mem_addr = offsets[0];
+	mdp3_res->splash_mem_size = offsets[1];
+
+	pr_debug("memaddr=%x size=%x\n", mdp3_res->splash_mem_addr,
+		mdp3_res->splash_mem_size);
+
+	return rc;
+}
+
+void mdp3_release_splash_memory(void)
+{
+	/* Give back the reserved memory to the system */
+	if (mdp3_res->splash_mem_addr) {
+		pr_debug("mdp3_release_splash_memory\n");
+		memblock_free(mdp3_res->splash_mem_addr,
+				mdp3_res->splash_mem_size);
+		free_bootmem_late(mdp3_res->splash_mem_addr,
+				mdp3_res->splash_mem_size);
+		mdp3_res->splash_mem_addr = 0;
+	}
+}
+
 struct mdp3_dma *mdp3_get_dma_pipe(int capability)
 {
 	int i;
@@ -1684,6 +1764,8 @@
 		rc = (status == 0x080000);
 	}
 
+	mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_S_IBUF_ADDR);
+
 	mdp3_clk_update(MDP3_CLK_AHB, 0);
 	mdp3_clk_update(MDP3_CLK_CORE, 0);
 	return rc;
@@ -1717,12 +1799,6 @@
 		goto splash_on_err;
 	}
 
-	rc = mdp3_continuous_splash_copy(pdata);
-	if (rc) {
-		pr_err("fail to copy continuous splash image\n");
-		goto splash_on_err;
-	}
-
 	mdp3_irq_register();
 
 	if (pdata->event_handler) {
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 2f73c42..caee34f 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -149,6 +149,8 @@
 
 	struct early_suspend suspend_handler;
 	struct mdss_panel_cfg pan_cfg;
+	u32 splash_mem_addr;
+	u32 splash_mem_size;
 };
 
 struct mdp3_img_data {
@@ -181,6 +183,8 @@
 int mdp3_iommu_disable(int client);
 int mdp3_iommu_is_attached(int client);
 void mdp3_free(void);
+int mdp3_parse_dt_splash(struct msm_fb_data_type *mfd);
+void mdp3_release_splash_memory(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 ac3fd3a..08bff9a 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -742,7 +742,8 @@
 	return rc;
 }
 
-static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd)
+static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
+					struct mdp_display_commit *cmt_data)
 {
 	struct mdp3_session_data *mdp3_session;
 	struct mdp3_img_data *data;
@@ -758,8 +759,8 @@
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
 		mdp3_ctrl_reset(mfd);
-		mdp3_free();
 	}
+	mdp3_release_splash_memory();
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -805,9 +806,9 @@
 
 	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
 		pr_debug("continuous splash screen, IOMMU not attached\n");
-		mdp3_ctrl_off(mfd);
-		mdp3_ctrl_on(mfd);
+		mdp3_ctrl_reset(mfd);
 	}
+	mdp3_release_splash_memory();
 
 	mutex_lock(&mdp3_session->lock);
 
@@ -1359,8 +1360,13 @@
 	struct mdp3_session_data *mdp3_session = NULL;
 	u32 intf_type = MDP3_DMA_OUTPUT_SEL_DSI_VIDEO;
 	int rc;
+	int splash_mismatch = 0;
 
 	pr_debug("mdp3_ctrl_init\n");
+	rc = mdp3_parse_dt_splash(mfd);
+	if (rc)
+		splash_mismatch = 1;
+
 	mdp3_interface->on_fnc = mdp3_ctrl_on;
 	mdp3_interface->off_fnc = mdp3_ctrl_off;
 	mdp3_interface->do_histogram = NULL;
@@ -1405,7 +1411,7 @@
 	mdp3_session->dma->output_config.out_sel = intf_type;
 	mdp3_session->mfd = mfd;
 	mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
-	mdp3_session->status = 0;
+	mdp3_session->status = mdp3_session->intf->active;
 	mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
 	mdp3_bufq_init(&mdp3_session->bufq_in);
 	mdp3_bufq_init(&mdp3_session->bufq_out);
@@ -1435,6 +1441,11 @@
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
 	pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
 
+	if (splash_mismatch) {
+		pr_err("splash memory mismatch, stop splash\n");
+		mdp3_ctrl_off(mfd);
+	}
+
 init_done:
 	if (IS_ERR_VALUE(rc))
 		kfree(mdp3_session);
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index e1f2d10..6e62cc7 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -498,6 +498,7 @@
 
 	src_w = req->src_rect.w;
 	dst_h = blit_op->dst.roi.height;
+	pr_err("TMsg: In workaround. srcw= %d, dstH=%d\n", src_w, dst_h);
 	/* bg tile fetching HW workaround */
 	for (i = 0; i < (req->dst_rect.h / 16); i++) {
 		/* this tile size */
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index e156116..b794ac4 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -289,6 +289,7 @@
 {
 	int ret = 0;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	struct mdss_panel_info *panel_info = NULL;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -305,6 +306,7 @@
 	ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
 				panel_data);
 
+	panel_info = &ctrl_pdata->panel_data.panel_info;
 	pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
 				ctrl_pdata, ctrl_pdata->ndx);
 
@@ -335,6 +337,11 @@
 		return ret;
 	}
 
+	if (panel_info->dynamic_fps
+	    && (panel_info->dfps_update == DFPS_SUSPEND_RESUME_MODE)
+	    && (panel_info->new_fps != panel_info->mipi.frame_rate))
+		panel_info->mipi.frame_rate = panel_info->new_fps;
+
 	pr_debug("%s-:\n", __func__);
 
 	return ret;
@@ -350,6 +357,7 @@
 	u32 ystride, bpp, data, dst_bpp;
 	u32 dummy_xres, dummy_yres;
 	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 hsync_period, vsync_period;
 
 	if (pdata == NULL) {
 		pr_err("%s: Invalid input data\n", __func__);
@@ -412,11 +420,16 @@
 			pdata->panel_info.bpp);
 	height = pdata->panel_info.yres;
 
-	mipi  = &pdata->panel_info.mipi;
 	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
 		dummy_xres = pdata->panel_info.lcdc.xres_pad;
 		dummy_yres = pdata->panel_info.lcdc.yres_pad;
+	}
 
+	vsync_period = vspw + vbp + height + dummy_yres + vfp;
+	hsync_period = hspw + hbp + width + dummy_xres + hfp;
+
+	mipi  = &pdata->panel_info.mipi;
+	if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24,
 			((hspw + hbp + width + dummy_xres) << 16 |
 			(hspw + hbp)));
@@ -424,9 +437,8 @@
 			((vspw + vbp + height + dummy_yres) << 16 |
 			(vspw + vbp)));
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C,
-			(vspw + vbp + height + dummy_yres +
-				vfp - 1) << 16 | (hspw + hbp +
-				width + dummy_xres + hfp - 1));
+				((vsync_period - 1) << 16)
+				| (hsync_period - 1));
 
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x30, (hspw << 16));
 		MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x34, 0);
@@ -591,6 +603,102 @@
 	return ret;
 }
 
+static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
+{
+	int rc = 0;
+	struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+	u32 dsi_ctrl;
+
+	pr_debug("%s+:\n", __func__);
+
+	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->panel_data.panel_info.dynamic_fps) {
+		pr_err("%s: Dynamic fps not enabled for this panel\n",
+					__func__);
+		return -EINVAL;
+	}
+
+	if (new_fps !=
+		ctrl_pdata->panel_data.panel_info.mipi.frame_rate) {
+		rc = mdss_dsi_clk_div_config
+			(&ctrl_pdata->panel_data.panel_info, new_fps);
+		if (rc) {
+			pr_err("%s: unable to initialize the clk dividers\n",
+							__func__);
+			return rc;
+		}
+		ctrl_pdata->pclk_rate =
+			ctrl_pdata->panel_data.panel_info.mipi.dsi_pclk_rate;
+		ctrl_pdata->byte_clk_rate =
+			ctrl_pdata->panel_data.panel_info.clk_rate / 8;
+
+		if (pdata->panel_info.dfps_update
+				== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
+			dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) +
+					    0x0004);
+			ctrl_pdata->panel_data.panel_info.mipi.frame_rate =
+									new_fps;
+			dsi_ctrl &= ~0x2;
+			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+							dsi_ctrl);
+			mdss_dsi_controller_cfg(true, pdata);
+			mdss_dsi_clk_ctrl(ctrl_pdata, 0);
+			mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+			dsi_ctrl |= 0x2;
+			MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004,
+							dsi_ctrl);
+		}
+	} else {
+		pr_debug("%s: Panel is already at this FPS\n", __func__);
+	}
+
+	return rc;
+}
+
+static int mdss_dsi_ctl_partial_update(struct mdss_panel_data *pdata)
+{
+	int rc = -EINVAL;
+	u32 data;
+	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);
+
+	/* DSI_COMMAND_MODE_MDP_STREAM_CTRL */
+	data = (((pdata->panel_info.roi_w * 3) + 1) << 16) |
+			(pdata->panel_info.mipi.vc << 8) | DTYPE_DCS_LWRITE;
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x60, data);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x58, data);
+
+	/* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */
+	data = pdata->panel_info.roi_h << 16 | pdata->panel_info.roi_w;
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x64, data);
+	MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, data);
+
+	if (ctrl_pdata->partial_update_fnc)
+		rc = ctrl_pdata->partial_update_fnc(pdata);
+
+	if (rc) {
+		pr_err("%s: unable to initialize the panel\n",
+				__func__);
+		return rc;
+	}
+
+	return rc;
+}
+
 static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
 				  int event, void *arg)
 {
@@ -644,6 +752,12 @@
 		break;
 	case MDSS_EVENT_DSI_CMDLIST_KOFF:
 		mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
+	case MDSS_EVENT_PANEL_UPDATE_FPS:
+		if (arg != NULL) {
+			rc = mdss_dsi_dfps_config(pdata, (int)arg);
+			pr_debug("%s:update fps to = %d\n",
+				__func__, (int)arg);
+		}
 		break;
 	case MDSS_EVENT_CONT_SPLASH_BEGIN:
 		if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) {
@@ -651,6 +765,9 @@
 			rc = mdss_dsi_blank(pdata);
 		}
 		break;
+	case MDSS_EVENT_ENABLE_PARTIAL_UPDATE:
+		rc = mdss_dsi_ctl_partial_update(pdata);
+		break;
 	default:
 		pr_debug("%s: unhandled event=%d\n", __func__, event);
 		break;
@@ -952,77 +1069,25 @@
 {
 	struct mipi_panel_info *mipi;
 	int rc, i, len;
-	u8 lanes = 0, bpp;
-	u32 h_period, v_period, dsi_pclk_rate, tmp[9];
+	u32 tmp[9];
 	struct device_node *dsi_ctrl_np = NULL;
 	struct platform_device *ctrl_pdev = NULL;
+	bool dynamic_fps;
 	const char *data;
 	struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
 
-	h_period = ((pinfo->lcdc.h_pulse_width)
-			+ (pinfo->lcdc.h_back_porch)
-			+ (pinfo->xres)
-			+ (pinfo->lcdc.h_front_porch));
-
-	v_period = ((pinfo->lcdc.v_pulse_width)
-			+ (pinfo->lcdc.v_back_porch)
-			+ (pinfo->yres)
-			+ (pinfo->lcdc.v_front_porch));
-
-	mipi  = &pinfo->mipi;
 	mipi  = &(pinfo->mipi);
 
 	pinfo->type =
 		((mipi->mode == DSI_VIDEO_MODE)
 			? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
 
-	if (mipi->data_lane3)
-		lanes += 1;
-	if (mipi->data_lane2)
-		lanes += 1;
-	if (mipi->data_lane1)
-		lanes += 1;
-	if (mipi->data_lane0)
-		lanes += 1;
-
-
-	if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
-	    || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
-	    || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
-		bpp = 3;
-	else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
-		 || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
-		bpp = 2;
-	else
-		bpp = 3;		/* Default format set to RGB888 */
-
-	if (!pinfo->clk_rate) {
-		h_period += pinfo->lcdc.xres_pad;
-		v_period += pinfo->lcdc.yres_pad;
-
-		if (lanes > 0) {
-			pinfo->clk_rate =
-			((h_period * v_period * (mipi->frame_rate) * bpp * 8)
-			   / lanes);
-		} else {
-			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
-			pinfo->clk_rate =
-				(h_period * v_period
-					 * (mipi->frame_rate) * bpp * 8);
-		}
-	}
-	pll_divider_config.clk_rate = pinfo->clk_rate;
-
-	rc = mdss_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate);
+	rc = mdss_dsi_clk_div_config(pinfo, mipi->frame_rate);
 	if (rc) {
 		pr_err("%s: unable to initialize the clk dividers\n", __func__);
 		return rc;
 	}
 
-	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
-		dsi_pclk_rate = 35000000;
-	mipi->dsi_pclk_rate = dsi_pclk_rate;
-
 	dsi_ctrl_np = of_parse_phandle(pan_node,
 				"qcom,mdss-dsi-panel-controller", 0);
 	if (!dsi_ctrl_np) {
@@ -1088,6 +1153,43 @@
 	ctrl_pdata->shared_pdata.broadcast_enable = of_property_read_bool(
 		pan_node, "qcom,mdss-dsi-panel-broadcast-mode");
 
+	dynamic_fps = of_property_read_bool(pan_node,
+					  "qcom,mdss-dsi-pan-enable-dynamic-fps");
+	if (dynamic_fps) {
+		pinfo->dynamic_fps = true;
+		data = of_get_property(pan_node,
+					  "qcom,mdss-dsi-pan-fps-update", NULL);
+		if (data) {
+			if (!strcmp(data, "dfps_suspend_resume_mode")) {
+				pinfo->dfps_update =
+						DFPS_SUSPEND_RESUME_MODE;
+				pr_debug("%s: dfps mode: suspend/resume\n",
+								__func__);
+			} else if (!strcmp(data,
+					    "dfps_immediate_clk_mode")) {
+				pinfo->dfps_update =
+						DFPS_IMMEDIATE_CLK_UPDATE_MODE;
+				pr_debug("%s: dfps mode: Immediate clk\n",
+								__func__);
+			} else {
+				pr_debug("%s: dfps to default mode\n",
+								__func__);
+				pinfo->dfps_update =
+						DFPS_SUSPEND_RESUME_MODE;
+				pr_debug("%s: dfps mode: suspend/resume\n",
+								__func__);
+			}
+		} else {
+			pr_debug("%s: dfps update mode not configured\n",
+								__func__);
+				pinfo->dynamic_fps =
+								false;
+				pr_debug("%s: dynamic FPS disabled\n",
+								__func__);
+		}
+		pinfo->new_fps = pinfo->mipi.frame_rate;
+	}
+
 	ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
 		"qcom,platform-enable-gpio", 0);
 
@@ -1219,7 +1321,7 @@
 	 * register in mdp driver
 	 */
 
-	ctrl_pdata->pclk_rate = dsi_pclk_rate;
+	ctrl_pdata->pclk_rate = mipi->dsi_pclk_rate;
 	ctrl_pdata->byte_clk_rate = pinfo->clk_rate / 8;
 	pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
 			ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 2d63532..b2b20f2 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -313,6 +313,7 @@
 	int ndx;	/* panel_num */
 	int (*on) (struct mdss_panel_data *pdata);
 	int (*off) (struct mdss_panel_data *pdata);
+	int (*partial_update_fnc) (struct mdss_panel_data *pdata);
 	struct mdss_panel_data panel_data;
 	unsigned char *ctrl_base;
 	int reg_size;
@@ -330,11 +331,16 @@
 	int disp_en_gpio;
 	int disp_te_gpio;
 	int mode_gpio;
+	int rst_gpio_requested;
+	int disp_en_gpio_requested;
+	int disp_te_gpio_requested;
+	int mode_gpio_requested;
 	int bklt_ctrl;	/* backlight ctrl */
 	int pwm_period;
 	int pwm_pmic_gpio;
 	int pwm_lpg_chan;
 	int bklt_max;
+	int new_fps;
 	struct pwm_device *pwm_bl;
 	struct dsi_drv_cm_data shared_pdata;
 	u32 pclk_rate;
@@ -397,8 +403,8 @@
 void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 
 void mipi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
-int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
-			    u32 *expected_dsi_pclk);
+int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
+			    int frame_rate);
 int mdss_dsi_clk_init(struct platform_device *pdev,
 		      struct mdss_dsi_ctrl_pdata *ctrl_pdata);
 void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 203900c..f37a6cc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -209,6 +209,61 @@
 	}
 }
 
+static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00};	/* DTYPE_DCS_LWRITE */
+static char paset[] = {0x2b, 0x00, 0x00, 0x05, 0x00};	/* DTYPE_DCS_LWRITE */
+
+static struct dsi_cmd_desc partial_update_enable_cmd[] = {
+	{{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(caset)}, caset},
+	{{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset)}, paset},
+};
+
+static int mdss_dsi_panel_partial_update(struct mdss_panel_data *pdata)
+{
+	struct mipi_panel_info *mipi;
+	struct mdss_dsi_ctrl_pdata *ctrl = NULL;
+	struct dcs_cmd_req cmdreq;
+	int rc = 0;
+
+	if (pdata == NULL) {
+		pr_err("%s: Invalid input data\n", __func__);
+		return -EINVAL;
+	}
+
+	ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+				panel_data);
+	mipi  = &pdata->panel_info.mipi;
+
+	pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx);
+
+	caset[1] = (((pdata->panel_info.roi_x) & 0xFF00) >> 8);
+	caset[2] = (((pdata->panel_info.roi_x) & 0xFF));
+	caset[3] = (((pdata->panel_info.roi_x - 1 + pdata->panel_info.roi_w)
+								& 0xFF00) >> 8);
+	caset[4] = (((pdata->panel_info.roi_x - 1 + pdata->panel_info.roi_w)
+								& 0xFF));
+	partial_update_enable_cmd[0].payload = caset;
+
+	paset[1] = (((pdata->panel_info.roi_y) & 0xFF00) >> 8);
+	paset[2] = (((pdata->panel_info.roi_y) & 0xFF));
+	paset[3] = (((pdata->panel_info.roi_y - 1 + pdata->panel_info.roi_h)
+								& 0xFF00) >> 8);
+	paset[4] = (((pdata->panel_info.roi_y - 1 + pdata->panel_info.roi_h)
+								& 0xFF));
+	partial_update_enable_cmd[1].payload = paset;
+
+	pr_debug("%s: enabling partial update\n", __func__);
+	memset(&cmdreq, 0, sizeof(cmdreq));
+	cmdreq.cmds = partial_update_enable_cmd;
+	cmdreq.cmds_cnt = 2;
+	cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL;
+	cmdreq.rlen = 0;
+	cmdreq.cb = NULL;
+
+	mdss_dsi_cmdlist_put(ctrl, &cmdreq);
+
+	return rc;
+}
+
 static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
 							u32 bl_level)
 {
@@ -759,6 +814,7 @@
 	int rc = 0;
 	static const char *panel_name;
 	bool cont_splash_enabled;
+	bool partial_update_enabled;
 
 	if (!node) {
 		pr_err("%s: no panel node\n", __func__);
@@ -795,6 +851,18 @@
 		ctrl_pdata->panel_data.panel_info.cont_splash_enabled = 1;
 	}
 
+	partial_update_enabled = of_property_read_bool(node,
+						"qcom,partial-update-enabled");
+	if (partial_update_enabled) {
+		pr_info("%s:%d Partial update enabled.\n", __func__, __LINE__);
+		ctrl_pdata->panel_data.panel_info.partial_update_enabled = 1;
+		ctrl_pdata->partial_update_fnc = mdss_dsi_panel_partial_update;
+	} else {
+		pr_info("%s:%d Partial update disabled.\n", __func__, __LINE__);
+		ctrl_pdata->panel_data.panel_info.partial_update_enabled = 0;
+		ctrl_pdata->partial_update_fnc = NULL;
+	}
+
 	ctrl_pdata->on = mdss_dsi_panel_on;
 	ctrl_pdata->off = mdss_dsi_panel_off;
 	ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 793cbd7..74b0217 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1431,7 +1431,7 @@
 		MDP_DISPLAY_COMMIT_OVERLAY) {
 		mdss_fb_wait_for_fence(mfd);
 		if (mfd->mdp.kickoff_fnc)
-			mfd->mdp.kickoff_fnc(mfd);
+			mfd->mdp.kickoff_fnc(mfd, &fb_backup->disp_commit);
 		mdss_fb_update_backlight(mfd);
 		mdss_fb_signal_timeline(mfd);
 	} else {
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index fd96e63..1f85373 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -63,7 +63,8 @@
 	int (*off_fnc)(struct msm_fb_data_type *mfd);
 	/* called to release resources associated to the process */
 	int (*release_fnc)(struct msm_fb_data_type *mfd);
-	int (*kickoff_fnc)(struct msm_fb_data_type *mfd);
+	int (*kickoff_fnc)(struct msm_fb_data_type *mfd,
+					struct mdp_display_commit *data);
 	int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
 	void (*dma_fnc)(struct msm_fb_data_type *mfd);
 	int (*cursor_update)(struct msm_fb_data_type *mfd,
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index 0fd3655..7117779 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -327,7 +327,7 @@
 {
 	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
 
-	if (!device || feature_type > HDMI_TX_FEAT_MAX) {
+	if (!device || feature_type >= HDMI_TX_FEAT_MAX) {
 		DEV_ERR("%s: invalid input\n", __func__);
 		return NULL;
 	}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 351d52b..7338d85 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -114,6 +114,13 @@
 struct mdss_mdp_ctl;
 typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
 
+struct mdss_mdp_img_rect {
+	u16 x;
+	u16 y;
+	u16 w;
+	u16 h;
+};
+
 struct mdss_mdp_vsync_handler {
 	bool enabled;
 	bool cmd_post_flush;
@@ -153,6 +160,7 @@
 	u32 bus_ib_quota;
 	u32 clk_rate;
 	u32 perf_changed;
+	int force_screen_state;
 
 	struct mdss_data_type *mdata;
 	struct msm_fb_data_type *mfd;
@@ -164,6 +172,9 @@
 	struct mdss_panel_data *panel_data;
 	struct mdss_mdp_vsync_handler vsync_handler;
 
+	struct mdss_mdp_img_rect roi;
+	u8 roi_changed;
+
 	int (*start_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
 	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
@@ -175,7 +186,7 @@
 					struct mdss_mdp_vsync_handler *);
 	int (*remove_vsync_handler) (struct mdss_mdp_ctl *,
 					struct mdss_mdp_vsync_handler *);
-
+	int (*config_fps_fnc) (struct mdss_mdp_ctl *ctl, int new_fps);
 	void *priv_data;
 	u32 wb_type;
 };
@@ -190,6 +201,7 @@
 	u8 params_changed;
 	u16 width;
 	u16 height;
+	struct mdss_mdp_img_rect roi;
 	u8 cursor_enabled;
 	u8 rotator_mode;
 
@@ -197,13 +209,6 @@
 	struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
 };
 
-struct mdss_mdp_img_rect {
-	u16 x;
-	u16 y;
-	u16 w;
-	u16 h;
-};
-
 struct mdss_mdp_format_params {
 	u32 format;
 	u8 is_yuv;
@@ -387,6 +392,9 @@
 	struct mdss_mdp_data free_list[MAX_FREE_LIST_SIZE];
 	int free_list_size;
 	int ad_state;
+
+	u32 splash_mem_addr;
+	u32 splash_mem_size;
 };
 
 struct mdss_mdp_perf_params {
@@ -395,6 +403,17 @@
 	u32 mdp_clk_rate;
 };
 
+/**
+ * enum mdss_screen_state - Screen states that MDP can be forced into
+ *
+ * @MDSS_SCREEN_DEFAULT:	Do not force MDP into any screen state.
+ * @MDSS_SCREEN_FORCE_BLANK:	Force MDP to generate blank color fill screen.
+ */
+enum mdss_screen_state {
+	MDSS_SCREEN_DEFAULT,
+	MDSS_SCREEN_FORCE_BLANK,
+};
+
 #define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
 static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
 				      u32 reg, u32 val)
@@ -420,7 +439,6 @@
 
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_iommu_attach(struct mdss_data_type *mdata);
-int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
 void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
 		u32 intr_type, u32 intf_num);
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -446,14 +464,13 @@
 int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd);
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
+		struct mdp_display_commit *data);
 
 struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
 					struct msm_fb_data_type *mfd);
 int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl);
-int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata);
-void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata);
 int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
@@ -571,6 +588,9 @@
 int mdss_mdp_get_img(struct msmfb_data *img, struct mdss_mdp_img_data *data);
 u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd);
 int mdss_mdp_calc_phase_step(u32 src, u32 dst, u32 *out_phase);
+void mdss_mdp_intersect_rect(struct mdss_mdp_img_rect *res_rect,
+	const struct mdss_mdp_img_rect *dst_rect,
+	const struct mdss_mdp_img_rect *sci_rect);
 
 int mdss_mdp_wb_kickoff(struct msm_fb_data_type *mfd);
 int mdss_mdp_wb_ioctl_handler(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
@@ -583,11 +603,13 @@
 int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
 int mdss_mdp_calib_config_buffer(struct mdp_calib_config_buffer *cfg,
 						u32 *copyback);
-
+int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps);
 int mdss_mdp_pipe_is_staged(struct mdss_mdp_pipe *pipe);
 int mdss_mdp_writeback_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
 struct mdss_mdp_ctl *mdss_mdp_ctl_mixer_switch(struct mdss_mdp_ctl *ctl,
 					       u32 return_type);
+void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl,
+					struct mdp_display_commit *data);
 
 int mdss_mdp_wb_set_format(struct msm_fb_data_type *mfd, int dst_format);
 int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d2c684f..503effa 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -428,6 +428,7 @@
 	ctl->add_vsync_handler = NULL;
 	ctl->remove_vsync_handler = NULL;
 	ctl->panel_data = NULL;
+	ctl->config_fps_fnc = NULL;
 	mutex_unlock(&mdss_mdp_ctl_lock);
 
 	return 0;
@@ -602,18 +603,6 @@
 	return 0;
 }
 
-void mdss_mdp_ctl_splash_start(struct mdss_panel_data *pdata)
-{
-	switch (pdata->panel_info.type) {
-	case MIPI_VIDEO_PANEL:
-		mdss_mdp_video_copy_splash_screen(pdata);
-		break;
-	case MIPI_CMD_PANEL:
-	default:
-		break;
-	}
-}
-
 int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl)
 {
 	switch (ctl->panel_data->panel_info.type) {
@@ -727,6 +716,7 @@
 
 	ctl->width = width;
 	ctl->height = height;
+	ctl->roi = (struct mdss_mdp_img_rect) {0, 0, width, height};
 
 	if (!ctl->mixer_left) {
 		ctl->mixer_left =
@@ -745,6 +735,7 @@
 
 	ctl->mixer_left->width = width;
 	ctl->mixer_left->height = height;
+	ctl->mixer_left->roi = (struct mdss_mdp_img_rect) {0, 0, width, height};
 
 	if (split_ctl) {
 		pr_debug("split display detected\n");
@@ -767,6 +758,8 @@
 		}
 		ctl->mixer_right->width = width;
 		ctl->mixer_right->height = height;
+		ctl->mixer_right->roi = (struct mdss_mdp_img_rect)
+						{0, 0, width, height};
 	} else if (ctl->mixer_right) {
 		mdss_mdp_mixer_free(ctl->mixer_right);
 		ctl->mixer_right = NULL;
@@ -1219,6 +1212,48 @@
 	return ret;
 }
 
+void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl,
+		struct mdp_display_commit *data)
+{
+	struct mdss_mdp_img_rect temp_roi, mixer_roi;
+
+	temp_roi.x = data->roi.x;
+	temp_roi.y = data->roi.y;
+	temp_roi.w = data->roi.w;
+	temp_roi.h = data->roi.h;
+
+	/*
+	 * No Partial Update for:
+	 * 1) dual DSI panels
+	 * 2) non-cmd mode panels
+	*/
+	if (!temp_roi.w || !temp_roi.h || ctl->mixer_right ||
+			(ctl->panel_data->panel_info.type != MIPI_CMD_PANEL) ||
+			!ctl->panel_data->panel_info.partial_update_enabled) {
+		temp_roi = (struct mdss_mdp_img_rect)
+				{0, 0, ctl->mixer_left->width,
+					ctl->mixer_left->height};
+	}
+
+	ctl->roi_changed = 0;
+	if (((temp_roi.x != ctl->roi.x) ||
+			(temp_roi.y != ctl->roi.y)) ||
+			((temp_roi.w != ctl->roi.w) ||
+			 (temp_roi.h != ctl->roi.h))) {
+		ctl->roi = temp_roi;
+		ctl->roi_changed++;
+
+		mixer_roi = ctl->mixer_left->roi;
+		if ((mixer_roi.w != temp_roi.w) ||
+			(mixer_roi.h != temp_roi.h)) {
+			ctl->mixer_left->roi = temp_roi;
+			ctl->mixer_left->params_changed++;
+		}
+	}
+	pr_debug("ROI requested: [%d, %d, %d, %d]\n",
+			ctl->roi.x, ctl->roi.y, ctl->roi.w, ctl->roi.h);
+}
+
 static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
 				struct mdss_mdp_mixer *mixer)
 {
@@ -1227,12 +1262,24 @@
 	u32 mixercfg = 0, blend_color_out = 0, bg_alpha_enable = 0;
 	u32 fg_alpha = 0, bg_alpha = 0;
 	int stage, secure = 0;
+	int screen_state;
+	int outsize = 0;
+
+	screen_state = ctl->force_screen_state;
 
 	if (!mixer)
 		return -ENODEV;
 
 	pr_debug("setup mixer=%d\n", mixer->num);
 
+	outsize = (mixer->roi.h << 16) | mixer->roi.w;
+	mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, outsize);
+
+	if (screen_state == MDSS_SCREEN_FORCE_BLANK) {
+		mixercfg = MDSS_MDP_LM_BORDER_COLOR;
+		goto update_mixer;
+	}
+
 	pipe = mixer->stage_pipe[MDSS_MDP_STAGE_BASE];
 	if (pipe == NULL) {
 		mixercfg = MDSS_MDP_LM_BORDER_COLOR;
@@ -1340,6 +1387,7 @@
 	if (mixer->cursor_enabled)
 		mixercfg |= MDSS_MDP_LM_CURSOR_OUT;
 
+update_mixer:
 	pr_debug("mixer=%d mixer_cfg=%x\n", mixer->num, mixercfg);
 
 	if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
@@ -1601,6 +1649,16 @@
 	return 0;
 }
 
+int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl, int fps)
+{
+	int ret = 0;
+
+	if (ctl->config_fps_fnc)
+		ret = ctl->config_fps_fnc(ctl, fps);
+
+	return ret;
+}
+
 int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
 				 ktime_t *wakeup_time)
 {
@@ -1739,7 +1797,8 @@
 	mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
-	if (mixer1_changed || mixer2_changed) {
+	if (mixer1_changed || mixer2_changed
+			|| ctl->force_screen_state) {
 		perf_update = mdss_mdp_ctl_perf_update(ctl);
 
 		if (ctl->prepare_fnc)
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index 920c231..addb9b0 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -428,6 +428,22 @@
 	return rc;
 }
 
+static int mdss_mdp_cmd_set_partial_roi(struct mdss_mdp_ctl *ctl)
+{
+	int rc = 0;
+	if (ctl->roi.w && ctl->roi.h && ctl->roi_changed &&
+			ctl->panel_data->panel_info.partial_update_enabled) {
+		ctl->panel_data->panel_info.roi_x = ctl->roi.x;
+		ctl->panel_data->panel_info.roi_y = ctl->roi.y;
+		ctl->panel_data->panel_info.roi_w = ctl->roi.w;
+		ctl->panel_data->panel_info.roi_h = ctl->roi.h;
+
+		rc = mdss_mdp_ctl_intf_event(ctl,
+				MDSS_EVENT_ENABLE_PARTIAL_UPDATE, NULL);
+	}
+	return rc;
+}
+
 int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_cmd_ctx *ctx;
@@ -450,13 +466,15 @@
 		WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc);
 	}
 
-	mdss_mdp_cmd_clk_on(ctx);
+	mdss_mdp_cmd_set_partial_roi(ctl);
 
 	/*
 	 * tx dcs command if had any
 	 */
 	mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_CMDLIST_KOFF, NULL);
 
+	mdss_mdp_cmd_clk_on(ctx);
+
 	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);
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index c78339a..8d4ca2b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -16,6 +16,8 @@
 #include <linux/iopoll.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
@@ -109,7 +111,7 @@
 	return 0;
 }
 
-static int mdss_mdp_video_timegen_setup(struct mdss_mdp_video_ctx *ctx,
+static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
 					struct intf_timing_params *p)
 {
 	u32 hsync_period, vsync_period;
@@ -117,7 +119,9 @@
 	u32 active_h_start, active_h_end, active_v_start, active_v_end;
 	u32 den_polarity, hsync_polarity, vsync_polarity;
 	u32 display_hctl, active_hctl, hsync_ctl, polarity_ctl;
+	struct mdss_mdp_video_ctx *ctx;
 
+	ctx = ctl->priv_data;
 	hsync_period = p->hsync_pulse_width + p->h_back_porch +
 			p->width + p->h_front_porch;
 	vsync_period = p->vsync_pulse_width + p->v_back_porch +
@@ -180,7 +184,7 @@
 
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_HSYNC_CTL, hsync_ctl);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
-			   vsync_period * hsync_period);
+			vsync_period * hsync_period);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0,
 			   p->vsync_pulse_width * hsync_period);
 	mdp_video_write(ctx, MDSS_MDP_REG_INTF_DISPLAY_HCTL, display_hctl);
@@ -440,6 +444,88 @@
 			ctl->underrun_cnt);
 }
 
+static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
+{
+	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_panel_data *pdata;
+	int rc = 0;
+	u32 hsync_period, vsync_period;
+
+	pr_debug("Updating fps for ctl=%d\n", ctl->num);
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	pdata = ctl->panel_data;
+	if (pdata == NULL) {
+		pr_err("%s: Invalid panel data\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!pdata->panel_info.dynamic_fps) {
+		pr_err("%s: Dynamic fps not enabled for this panel\n",
+						__func__);
+		return -EINVAL;
+	}
+
+	vsync_period = mdss_panel_get_vtotal(&pdata->panel_info);
+	hsync_period = mdss_panel_get_htotal(&pdata->panel_info);
+
+	if (pdata->panel_info.dfps_update
+			!= DFPS_SUSPEND_RESUME_MODE) {
+		if (pdata->panel_info.dfps_update
+				== DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
+			if (!ctx->timegen_en) {
+				pr_err("TG is OFF. DFPS mode invalid\n");
+				return -EINVAL;
+			}
+			ctl->force_screen_state = MDSS_SCREEN_FORCE_BLANK;
+			mdss_mdp_display_commit(ctl, NULL);
+			mdss_mdp_display_wait4comp(ctl);
+			mdp_video_write(ctx,
+					MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+			/*
+			 * Need to wait for atleast one vsync time for proper
+			 * TG OFF before doing changes on interfaces
+			 */
+			msleep(20);
+			rc = mdss_mdp_ctl_intf_event(ctl,
+						MDSS_EVENT_PANEL_UPDATE_FPS,
+						(void *)new_fps);
+			WARN(rc, "intf %d panel fps update error (%d)\n",
+							ctl->intf_num, rc);
+			mdp_video_write(ctx,
+					MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
+			/*
+			 * Add memory barrier to make sure the MDP Video
+			 * mode engine is enabled before next frame is sent
+			 */
+			mb();
+			ctl->force_screen_state = MDSS_SCREEN_DEFAULT;
+			mdss_mdp_display_commit(ctl, NULL);
+			mdss_mdp_display_wait4comp(ctl);
+		} else {
+			pr_err("intf %d panel, unknown FPS mode\n",
+							ctl->intf_num);
+			return -EINVAL;
+		}
+	} else {
+		rc = mdss_mdp_ctl_intf_event(ctl,
+					MDSS_EVENT_PANEL_UPDATE_FPS,
+					(void *)new_fps);
+		WARN(rc, "intf %d panel fps update error (%d)\n",
+						ctl->intf_num, rc);
+	}
+
+	return rc;
+}
+
+
+
+
 static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_video_ctx *ctx;
@@ -492,67 +578,13 @@
 	return 0;
 }
 
-int mdss_mdp_video_copy_splash_screen(struct mdss_panel_data *pdata)
-{
-	void *virt = NULL;
-	unsigned long bl_fb_addr = 0;
-	unsigned long *bl_fb_addr_va;
-	unsigned long  pipe_addr, pipe_src_size;
-	u32 height, width, rgb_size, bpp;
-	size_t size;
-	static struct ion_handle *ihdl;
-	struct ion_client *iclient = mdss_get_ionclient();
-	static ion_phys_addr_t phys;
-
-	pipe_addr = MDSS_MDP_REG_SSPP_OFFSET(3) +
-		MDSS_MDP_REG_SSPP_SRC0_ADDR;
-	pipe_src_size =
-		MDSS_MDP_REG_SSPP_OFFSET(3) + MDSS_MDP_REG_SSPP_SRC_SIZE;
-
-	bpp        = 3;
-	rgb_size   = MDSS_MDP_REG_READ(pipe_src_size);
-	bl_fb_addr = MDSS_MDP_REG_READ(pipe_addr);
-
-	height = (rgb_size >> 16) & 0xffff;
-	width  = rgb_size & 0xffff;
-	size = PAGE_ALIGN(height * width * bpp);
-	pr_debug("%s:%d splash_height=%d splash_width=%d Buffer size=%d\n",
-			__func__, __LINE__, height, width, size);
-
-	ihdl = ion_alloc(iclient, size, SZ_1M,
-			ION_HEAP(ION_QSECOM_HEAP_ID), 0);
-	if (IS_ERR_OR_NULL(ihdl)) {
-		pr_err("unable to alloc fbmem from ion (%p)\n", ihdl);
-		return -ENOMEM;
-	}
-
-	pdata->panel_info.splash_ihdl = ihdl;
-
-	virt = ion_map_kernel(iclient, ihdl);
-	ion_phys(iclient, ihdl, &phys, &size);
-
-	pr_debug("%s %d Allocating %u bytes at 0x%lx (%pa phys)\n",
-			__func__, __LINE__, size,
-			(unsigned long int)virt, &phys);
-
-	bl_fb_addr_va = (unsigned long *)ioremap(bl_fb_addr, size);
-	memcpy(virt, bl_fb_addr_va, size);
-	iounmap(bl_fb_addr_va);
-
-	MDSS_MDP_REG_WRITE(pipe_addr, phys);
-	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_CTL_FLUSH + MDSS_MDP_REG_CTL_OFFSET(0),
-			0x48);
-
-	return 0;
-}
-
 int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl)
 {
-	struct ion_client *iclient = mdss_get_ionclient();
 	struct mdss_panel_data *pdata;
 	int ret = 0, off;
 	int mdss_mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
 	int mdss_v2_intf_off = 0;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
 
 	off = 0;
 
@@ -578,7 +610,12 @@
 			mdss_v2_intf_off, 0);
 	/* wait for 1 VSYNC for the pipe to be unstaged */
 	msleep(20);
-	ion_free(iclient, pdata->panel_info.splash_ihdl);
+
+	/* Give back the reserved memory to the system */
+	memblock_free(mdp5_data->splash_mem_addr, mdp5_data->splash_mem_size);
+	free_bootmem_late(mdp5_data->splash_mem_addr,
+				 mdp5_data->splash_mem_size);
+
 	ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_FINISH,
 			NULL);
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
@@ -654,7 +691,7 @@
 			pinfo->bpp);
 	itp.vsync_pulse_width = pinfo->lcdc.v_pulse_width;
 
-	if (mdss_mdp_video_timegen_setup(ctx, &itp)) {
+	if (mdss_mdp_video_timegen_setup(ctl, &itp)) {
 		pr_err("unable to get timing parameters\n");
 		return -EINVAL;
 	}
@@ -666,6 +703,7 @@
 	ctl->read_line_cnt_fnc = mdss_mdp_video_line_count;
 	ctl->add_vsync_handler = mdss_mdp_video_add_vsync_handler;
 	ctl->remove_vsync_handler = mdss_mdp_video_remove_vsync_handler;
+	ctl->config_fps_fnc = mdss_mdp_video_config_fps;
 
 	return 0;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index fcc87f6..948f275 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -22,6 +22,7 @@
 #include <linux/uaccess.h>
 #include <linux/delay.h>
 #include <linux/msm_mdp.h>
+#include <linux/memblock.h>
 
 #include <mach/iommu_domains.h>
 #include <mach/event_timer.h>
@@ -45,6 +46,7 @@
 static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
 static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
+static int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd);
 
 static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
 				struct mdp_overlay *req)
@@ -824,7 +826,8 @@
 	activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time);
 }
 
-int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd)
+int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
+				struct mdp_display_commit *data)
 {
 	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
 	struct mdss_mdp_pipe *pipe;
@@ -847,6 +850,9 @@
 		return ret;
 	}
 
+	if (data)
+		mdss_mdp_set_roi(ctl, data);
+
 	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
 		struct mdss_mdp_data *buf;
 		/*
@@ -1052,7 +1058,7 @@
 	mutex_unlock(&mdp5_data->ov_lock);
 
 	if (cnt)
-		mfd->mdp.kickoff_fnc(mfd);
+		mfd->mdp.kickoff_fnc(mfd, NULL);
 
 	list_for_each_entry_safe(rot, tmp, &mdp5_data->rot_proc_list, list) {
 		if (rot->pid == pid) {
@@ -1073,7 +1079,7 @@
 	if (!mfd)
 		return -ENODEV;
 
-	ret = mfd->mdp.kickoff_fnc(mfd);
+	ret = mfd->mdp.kickoff_fnc(mfd, NULL);
 	if (!ret)
 		pr_err("error displaying\n");
 
@@ -1336,7 +1342,7 @@
 
 	if (!fbi->fix.smem_start || fbi->fix.smem_len == 0 ||
 	     mdp5_data->borderfill_enable) {
-		mfd->mdp.kickoff_fnc(mfd);
+		mfd->mdp.kickoff_fnc(mfd, NULL);
 		return;
 	}
 
@@ -1410,7 +1416,7 @@
 
 	if ((fbi->var.activate & FB_ACTIVATE_VBL) ||
 	    (fbi->var.activate & FB_ACTIVATE_FORCE))
-		mfd->mdp.kickoff_fnc(mfd);
+		mfd->mdp.kickoff_fnc(mfd, NULL);
 
 	return;
 
@@ -1465,6 +1471,96 @@
 	return rc;
 }
 
+static ssize_t dynamic_fps_sysfs_rda_dfps(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+		return 0;
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected for fb%d\n", mfd->index);
+		return -ENODEV;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n",
+		       pdata->panel_info.mipi.frame_rate);
+	pr_debug("%s: '%d'\n", __func__,
+		pdata->panel_info.mipi.frame_rate);
+
+	return ret;
+} /* dynamic_fps_sysfs_rda_dfps */
+
+static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int dfps, rc = 0;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+
+	rc = kstrtoint(buf, 10, &dfps);
+	if (rc) {
+		pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+		return rc;
+	}
+
+	if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
+		return 0;
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected for fb%d\n", mfd->index);
+		return -ENODEV;
+	}
+
+	if (dfps == pdata->panel_info.mipi.frame_rate) {
+		pr_debug("%s: FPS is already %d\n",
+			__func__, dfps);
+		return count;
+	}
+
+	if (dfps < 30) {
+		pr_err("Unsupported FPS. Configuring to min_fps = 30\n");
+		dfps = 30;
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	} else if (dfps > 60) {
+		pr_err("Unsupported FPS. Configuring to max_fps = 60\n");
+		dfps = 60;
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	} else {
+		rc = mdss_mdp_ctl_update_fps(mdp5_data->ctl, dfps);
+	}
+	if (!rc) {
+		pr_info("%s: configured to '%d' FPS\n", __func__, dfps);
+	} else {
+		pr_err("Failed to configure '%d' FPS. rc = %d\n",
+							dfps, rc);
+		return rc;
+	}
+	pdata->panel_info.new_fps = dfps;
+	return count;
+} /* dynamic_fps_sysfs_wta_dfps */
+
+
+static DEVICE_ATTR(dynamic_fps, S_IRUGO | S_IWUSR, dynamic_fps_sysfs_rda_dfps,
+	dynamic_fps_sysfs_wta_dfps);
+
+static struct attribute *dynamic_fps_fs_attrs[] = {
+	&dev_attr_dynamic_fps.attr,
+	NULL,
+};
+static struct attribute_group dynamic_fps_fs_attrs_group = {
+	.attrs = dynamic_fps_fs_attrs,
+};
+
 static ssize_t mdss_mdp_vsync_show_event(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -2068,7 +2164,7 @@
 		break;
 	case MSMFB_OVERLAY_COMMIT:
 		mdss_fb_wait_for_fence(mfd);
-		ret = mfd->mdp.kickoff_fnc(mfd);
+		ret = mfd->mdp.kickoff_fnc(mfd, NULL);
 		mdss_fb_signal_timeline(mfd);
 		break;
 	case MSMFB_METADATA_SET:
@@ -2144,7 +2240,7 @@
 		(mfd->panel_info->type != WRITEBACK_PANEL)) {
 		rc = mdss_mdp_overlay_start(mfd);
 		if (!IS_ERR_VALUE(rc))
-			rc = mdss_mdp_overlay_kickoff(mfd);
+			rc = mdss_mdp_overlay_kickoff(mfd, NULL);
 	} else {
 		rc = mdss_mdp_ctl_setup(mdp5_data->ctl);
 		if (rc)
@@ -2197,7 +2293,7 @@
 
 	if (need_cleanup) {
 		pr_debug("cleaning up pipes on fb%d\n", mfd->index);
-		mdss_mdp_overlay_kickoff(mfd);
+		mdss_mdp_overlay_kickoff(mfd, NULL);
 	}
 
 	rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
@@ -2230,7 +2326,6 @@
 	if (pdata->panel_info.cont_splash_enabled) {
 		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 		mdss_mdp_footswitch_ctrl_splash(1);
-		mdss_mdp_ctl_splash_start(pdata);
 	}
 	return 0;
 }
@@ -2292,6 +2387,15 @@
 		goto init_fail;
 	}
 
+	if (mfd->panel_info->type == MIPI_VIDEO_PANEL) {
+		rc = sysfs_create_group(&dev->kobj,
+			&dynamic_fps_fs_attrs_group);
+		if (rc) {
+			pr_err("Error dfps sysfs creation ret=%d\n", rc);
+			goto init_fail;
+		}
+	}
+
 	pm_runtime_set_suspended(&mfd->pdev->dev);
 	pm_runtime_enable(&mfd->pdev->dev);
 
@@ -2308,8 +2412,48 @@
 	return rc;
 }
 
+static __ref int mdss_mdp_overlay_splash_parse_dt(struct msm_fb_data_type *mfd)
+{
+	struct platform_device *pdev = mfd->pdev;
+	struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
+	int len = 0, rc = 0;
+	u32 offsets[2];
+
+	of_find_property(pdev->dev.of_node, "qcom,memblock-reserve", &len);
+
+	if (len < 1) {
+		pr_debug("mem reservation for splash screen fb not present\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	len = len/sizeof(u32);
+
+	rc = of_property_read_u32_array(pdev->dev.of_node,
+			"qcom,memblock-reserve", offsets, len);
+	if (rc) {
+		pr_debug("Error reading mem reserve settings for fb\n");
+		goto error;
+	}
+
+	if (!memblock_is_reserved(offsets[0])) {
+		pr_debug("failed to reserve memory for fb splash\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	mdp5_mdata->splash_mem_addr = offsets[0];
+	mdp5_mdata->splash_mem_size = offsets[1];
+	pr_debug("memaddr=%x size=%x\n", mdp5_mdata->splash_mem_addr,
+		mdp5_mdata->splash_mem_size);
+
+error:
+	return rc;
+}
+
 static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd)
 {
+	int rc = 0;
 	struct platform_device *pdev = mfd->pdev;
 	struct mdss_overlay_private *mdp5_mdata = mfd_to_mdp5_data(mfd);
 
@@ -2320,5 +2464,13 @@
 			pdev->name);
 	}
 
-	return 0;
+	rc = mdss_mdp_overlay_splash_parse_dt(mfd);
+	if (rc && mfd->panel_info->cont_splash_enabled) {
+		pr_err("No rsvd mem found in DT for splash screen\n");
+	} else {
+		pr_debug("Mem reservation not reqd if cont splash diasbled\n");
+		rc = 0;
+	}
+
+	return rc;
 }
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 16ea7dc..8920fe1 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -481,16 +481,37 @@
 
 }
 
+void mdss_mdp_crop_rect(struct mdss_mdp_img_rect *src_rect,
+	struct mdss_mdp_img_rect *dst_rect,
+	const struct mdss_mdp_img_rect *sci_rect)
+{
+	struct mdss_mdp_img_rect res;
+	mdss_mdp_intersect_rect(&res, dst_rect, sci_rect);
+
+	if (res.w && res.h) {
+		if ((res.w != dst_rect->w) || (res.h != dst_rect->h)) {
+			src_rect->x = src_rect->x + (res.x - dst_rect->x);
+			src_rect->y = src_rect->y + (res.y - dst_rect->y);
+			src_rect->w = res.w;
+			src_rect->h = res.h;
+		}
+		*dst_rect = (struct mdss_mdp_img_rect)
+			{(res.x - sci_rect->x), (res.y - sci_rect->y),
+			res.w, res.h};
+	}
+}
+
 static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
 {
 	u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
 	u32 width, height;
 	u32 decimation;
+	struct mdss_mdp_img_rect sci, dst, src;
 
 	pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
-		   pipe->num, pipe->img_width, pipe->img_height,
-		   pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
-		   pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
+			pipe->num, pipe->img_width, pipe->img_height,
+			pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
+			pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
 
 	width = pipe->img_width;
 	height = pipe->img_height;
@@ -512,15 +533,23 @@
 		pr_debug("Image decimation h=%d v=%d\n",
 				pipe->horz_deci, pipe->vert_deci);
 
+	sci = pipe->mixer->ctl->roi;
+	dst = pipe->dst;
+	src = pipe->src;
+
+	mdss_mdp_crop_rect(&src, &dst, &sci);
+
+	src_size = (src.h << 16) | src.w;
+	src_xy = (src.y << 16) | src.x;
+	dst_size = (dst.h << 16) | dst.w;
+	dst_xy = (dst.y << 16) | dst.x;
+
 	img_size = (height << 16) | width;
-	src_size = (pipe->src.h << 16) | pipe->src.w;
-	src_xy = (pipe->src.y << 16) | pipe->src.x;
-	dst_size = (pipe->dst.h << 16) | pipe->dst.w;
-	dst_xy = (pipe->dst.y << 16) | pipe->dst.x;
+
 	ystride0 =  (pipe->src_planes.ystride[0]) |
-		    (pipe->src_planes.ystride[1] << 16);
+			(pipe->src_planes.ystride[1] << 16);
 	ystride1 =  (pipe->src_planes.ystride[2]) |
-		    (pipe->src_planes.ystride[3] << 16);
+			(pipe->src_planes.ystride[3] << 16);
 
 	if (pipe->overfetch_disable) {
 		img_size = src_size;
@@ -706,7 +735,8 @@
 	params_changed = (pipe->params_changed) ||
 			 ((pipe->type == MDSS_MDP_PIPE_TYPE_DMA) &&
 			 (pipe->mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
-			 && (ctl->mdata->mixer_switched));
+			 && (ctl->mdata->mixer_switched)) ||
+			 ctl->roi_changed;
 	if (src_data == NULL) {
 		mdss_mdp_pipe_solidfill_setup(pipe);
 		goto update_nobuf;
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index b65d894..1170d1e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -237,6 +237,20 @@
 	return NULL;
 }
 
+void mdss_mdp_intersect_rect(struct mdss_mdp_img_rect *res_rect,
+	const struct mdss_mdp_img_rect *dst_rect,
+	const struct mdss_mdp_img_rect *sci_rect)
+{
+	int l = max(dst_rect->x, sci_rect->x);
+	int t = max(dst_rect->y, sci_rect->y);
+	int r = min((dst_rect->x + dst_rect->w), (sci_rect->x + sci_rect->w));
+	int b = min((dst_rect->y + dst_rect->h), (sci_rect->y + sci_rect->h));
+
+	if (r < l || b < t)
+		*res_rect = (struct mdss_mdp_img_rect){0, 0, 0, 0};
+	else
+		*res_rect = (struct mdss_mdp_img_rect){l, t, (r-l), (b-t)};
+}
 int mdss_mdp_get_rau_strides(u32 w, u32 h,
 			       struct mdss_mdp_format_params *fmt,
 			       struct mdss_mdp_plane_sizes *ps)
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index d05ca66..d5b6ec7 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -112,6 +112,7 @@
  *				display state from boot loader to panel driver.
  *				The event handler will enable the panel and
  *				vote for the display clocks.
+ * @MDSS_EVENT_PANEL_UPDATE_FPS: Event to update the frame rate of the panel.
  * @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.
@@ -119,6 +120,7 @@
 				 - 0 clock disable
 				 - 1 clock enable
  * @MDSS_EVENT_DSI_CMDLIST_KOFF: kickoff sending dcs command from command list
+ * @MDSS_EVENT_ENABLE_PARTIAL_UPDATE: Event to update ROI of the panel.
  */
 enum mdss_intf_events {
 	MDSS_EVENT_RESET = 1,
@@ -132,9 +134,11 @@
 	MDSS_EVENT_CHECK_PARAMS,
 	MDSS_EVENT_CONT_SPLASH_BEGIN,
 	MDSS_EVENT_CONT_SPLASH_FINISH,
+	MDSS_EVENT_PANEL_UPDATE_FPS,
 	MDSS_EVENT_FB_REGISTERED,
 	MDSS_EVENT_PANEL_CLK_CTRL,
 	MDSS_EVENT_DSI_CMDLIST_KOFF,
+	MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
 };
 
 struct lcd_panel_info {
@@ -214,6 +218,11 @@
 	char hw_vsync_mode;
 };
 
+enum dynamic_fps_update {
+	DFPS_SUSPEND_RESUME_MODE,
+	DFPS_IMMEDIATE_CLK_UPDATE_MODE,
+};
+
 enum lvds_mode {
 	LVDS_SINGLE_CHANNEL_MODE,
 	LVDS_DUAL_CHANNEL_MODE,
@@ -264,13 +273,21 @@
 	u32 is_3d_panel;
 	u32 out_format;
 	u32 vic; /* video identification code */
+	u32 roi_x;
+	u32 roi_y;
+	u32 roi_w;
+	u32 roi_h;
 	int bklt_ctrl;	/* backlight ctrl */
 	int pwm_pmic_gpio;
 	int pwm_lpg_chan;
 	int pwm_period;
 	u32 mode_gpio_state;
+	bool dynamic_fps;
+	char dfps_update;
+	int new_fps;
 
 	u32 cont_splash_enabled;
+	u32 partial_update_enabled;
 	struct ion_handle *splash_ihdl;
 	u32 panel_power_on;
 
@@ -354,6 +371,20 @@
 			pinfo->lcdc.v_pulse_width;
 }
 
+/*
+ * mdss_panel_get_htotal() - return panel horizontal width
+ * @pinfo:	Pointer to panel info containing all panel information
+ *
+ * Returns the total width of the panel including any blanking regions
+ * which are not visible to user but used for calculations.
+ */
+static inline int mdss_panel_get_htotal(struct mdss_panel_info *pinfo)
+{
+	return pinfo->xres + pinfo->lcdc.h_back_porch +
+			pinfo->lcdc.h_front_porch +
+			pinfo->lcdc.h_pulse_width;
+}
+
 int mdss_register_panel(struct platform_device *pdev,
 	struct mdss_panel_data *pdata);
 
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index d24daab..f7ea557 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -106,13 +106,64 @@
 #define PREF_DIV_RATIO 27
 struct dsiphy_pll_divider_config pll_divider_config;
 
-int mdss_dsi_clk_div_config(u8 bpp, u8 lanes,
-			    u32 *expected_dsi_pclk)
+int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
+			    int frame_rate)
 {
 	u32 fb_divider, rate, vco;
 	u32 div_ratio = 0;
 	u32 pll_analog_posDiv = 1;
+	u32 h_period, v_period;
+	u32 dsi_pclk_rate;
+	u8 lanes = 0, bpp;
 	struct dsi_clk_mnd_table const *mnd_entry = mnd_table;
+
+	if (panel_info->mipi.data_lane3)
+		lanes += 1;
+	if (panel_info->mipi.data_lane2)
+		lanes += 1;
+	if (panel_info->mipi.data_lane1)
+		lanes += 1;
+	if (panel_info->mipi.data_lane0)
+		lanes += 1;
+
+	switch (panel_info->mipi.dst_format) {
+	case DSI_CMD_DST_FORMAT_RGB888:
+	case DSI_VIDEO_DST_FORMAT_RGB888:
+	case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE:
+		bpp = 3;
+		break;
+	case DSI_CMD_DST_FORMAT_RGB565:
+	case DSI_VIDEO_DST_FORMAT_RGB565:
+		bpp = 2;
+		break;
+	default:
+		bpp = 3;	/* Default format set to RGB888 */
+		break;
+	}
+
+	h_period = mdss_panel_get_htotal(panel_info);
+	v_period = mdss_panel_get_vtotal(panel_info);
+
+	if ((frame_rate !=
+	     panel_info->mipi.frame_rate) ||
+	    (!panel_info->clk_rate)) {
+		h_period += panel_info->lcdc.xres_pad;
+		v_period += panel_info->lcdc.yres_pad;
+
+		if (lanes > 0) {
+			panel_info->clk_rate =
+			((h_period * v_period *
+			  frame_rate * bpp * 8)
+			   / lanes);
+		} else {
+			pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
+			panel_info->clk_rate =
+				(h_period * v_period * frame_rate * bpp * 8);
+		}
+	}
+	pll_divider_config.clk_rate = panel_info->clk_rate;
+
+
 	if (pll_divider_config.clk_rate == 0)
 		pll_divider_config.clk_rate = 454000000;
 
@@ -176,9 +227,13 @@
 		dsi_pclk.n = mnd_entry->pclk_n;
 		dsi_pclk.d = mnd_entry->pclk_d;
 	}
-	*expected_dsi_pclk = (((pll_divider_config.clk_rate) * lanes)
+	dsi_pclk_rate = (((pll_divider_config.clk_rate) * lanes)
 				      / (8 * bpp));
 
+	if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
+		dsi_pclk_rate = 35000000;
+	panel_info->mipi.dsi_pclk_rate = dsi_pclk_rate;
+
 	return 0;
 }
 
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index baa9d6c..9b21dca 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -862,6 +862,7 @@
 	uint32_t wait_for_finish;
 	struct fb_var_screeninfo var;
 	struct mdp_buf_fence buf_fence;
+	struct mdp_rect roi;
 };
 
 struct mdp_page_protection {
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 1bb3b06..ed6d41b 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -98,7 +98,7 @@
 #define CELSIUS_TO_KELVIN(t)	((t)*10+2732)
 
 struct sensor_threshold {
-	int temp;
+	long temp;
 	enum thermal_trip_type trip;
 	int (*notify)(enum thermal_trip_type type, int temp, void *data);
 	void *data;
@@ -108,8 +108,8 @@
 struct sensor_info {
 	uint32_t sensor_id;
 	struct thermal_zone_device *tz;
-	int threshold_min;
-	int threshold_max;
+	long threshold_min;
+	long threshold_max;
 	int max_idx;
 	int min_idx;
 	struct list_head sensor_list;
@@ -190,7 +190,7 @@
 int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
 int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
 int thermal_sensor_trip(struct thermal_zone_device *tz,
-		enum thermal_trip_type trip, unsigned long temp);
+		enum thermal_trip_type trip, long temp);
 
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 6071e91..663bc05 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -134,6 +134,7 @@
 extern struct vm_struct *vmlist;
 extern __init void vm_area_add_early(struct vm_struct *vm);
 extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
+extern __init int vm_area_check_early(struct vm_struct *vm);
 
 #ifdef CONFIG_SMP
 # ifdef CONFIG_MMU
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 540fd2c..326e8bf 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -231,6 +231,7 @@
 struct msm_camera_i2c_reg_array {
 	uint16_t reg_addr;
 	uint16_t reg_data;
+	uint32_t delay;
 };
 
 struct msm_camera_i2c_reg_setting {
diff --git a/mm/memory.c b/mm/memory.c
index b6ab040..acc9aa6 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -58,6 +58,7 @@
 #include <linux/swapops.h>
 #include <linux/elf.h>
 #include <linux/gfp.h>
+#include <linux/bug.h>
 
 #include <asm/io.h>
 #include <asm/pgalloc.h>
@@ -705,6 +706,9 @@
 	if (vma->vm_file && vma->vm_file->f_op)
 		print_symbol(KERN_ALERT "vma->vm_file->f_op->mmap: %s\n",
 				(unsigned long)vma->vm_file->f_op->mmap);
+
+	BUG_ON(PANIC_CORRUPTION);
+
 	dump_stack();
 	add_taint(TAINT_BAD_PAGE);
 }
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 5065adb..a2ab2ab 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1116,7 +1116,31 @@
 	return mem;
 }
 EXPORT_SYMBOL(vm_map_ram);
+/**
+ * vm_area_check_early - check if vmap area is already mapped
+ * @vm: vm_struct to be checked
+ *
+ * This function is used to check if the vmap area has been
+ * mapped already. @vm->addr, @vm->size and @vm->flags should
+ * contain proper values.
+ *
+ */
+int __init vm_area_check_early(struct vm_struct *vm)
+{
+	struct vm_struct *tmp, **p;
 
+	BUG_ON(vmap_initialized);
+	for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
+		if (tmp->addr >= vm->addr) {
+			if (tmp->addr < vm->addr + vm->size)
+				return 1;
+		} else {
+			if (tmp->addr + tmp->size > vm->addr)
+				return 1;
+		}
+	}
+	return 0;
+}
 /**
  * vm_area_add_early - add vmap area early during boot
  * @vm: vm_struct to add
@@ -1392,15 +1416,26 @@
  */
 struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
 {
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
+				-1, GFP_KERNEL, __builtin_return_address(0));
+#else
 	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
 				-1, GFP_KERNEL, __builtin_return_address(0));
+#endif
+
 }
 
 struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
 				const void *caller)
 {
-	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+#ifdef CONFIG_ENABLE_VMALLOC_SAVING
+	return __get_vm_area_node(size, 1, flags, PAGE_OFFSET, VMALLOC_END,
 						-1, GFP_KERNEL, caller);
+#else
+	return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+				-1, GFP_KERNEL, __builtin_return_address(0));
+#endif
 }
 
 /**
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 9460ec0..d1ddfae 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -2003,7 +2003,7 @@
 	mutex_init(&cdc_mclk_mutex);
 
 	mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
-					"qcom,headset-jack-type-NO");
+					"qcom,headset-jack-type-NC");
 
 	ret = snd_soc_register_card(card);
 	if (ret == -EPROBE_DEFER)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index c4b44fe..d80ca19 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -35,8 +35,8 @@
 
 #define MIN_PLAYBACK_PERIOD_SIZE (128 * 2)
 #define MAX_PLAYBACK_PERIOD_SIZE (128 * 2 * 2 * 6)
-#define MIN_PLAYBACK_NUM_PERIODS (32)
-#define MAX_PLAYBACK_NUM_PERIODS (384)
+#define MIN_PLAYBACK_NUM_PERIODS (64)
+#define MAX_PLAYBACK_NUM_PERIODS (768)
 
 #define MIN_CAPTURE_PERIOD_SIZE (128 * 2 * 4)
 #define MAX_CAPTURE_PERIOD_SIZE (128 * 2 * 2 * 6 * 4)
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index bba4c14..27c74ce 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -36,7 +36,7 @@
 #define ADM_GET_PARAMETER_LENGTH  (4096 - APR_HDR_SIZE - 2 * sizeof(uint32_t))
 
 #define ULL_SUPPORTED_SAMPLE_RATE 48000
-
+#define ULL_MAX_SUPPORTED_CHANNEL 2
 enum {
 	ADM_RX_AUDPROC_CAL,
 	ADM_TX_AUDPROC_CAL,
@@ -1128,8 +1128,9 @@
 		if (perf_mode) {
 			open.topology_id = NULL_COPP_TOPOLOGY;
 			rate = ULL_SUPPORTED_SAMPLE_RATE;
+			if(channel_mode > ULL_MAX_SUPPORTED_CHANNEL)
+				channel_mode = ULL_MAX_SUPPORTED_CHANNEL;
 		}
-
 		open.dev_num_channel = channel_mode & 0x00FF;
 		open.bit_width = bits_per_sample;
 		WARN_ON(perf_mode && (rate != 48000));