Merge "msm: kgsl: Pass GPU HW version to GMU"
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
index c811c28..e46fd5c 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
@@ -88,7 +88,28 @@
 					controller. These pin configurations are installed in the pinctrl
 					device node. Refer to pinctrl-bindings.txt
 
+msm_ext_disp is a device which manages the interaction between external
+display interfaces, e.g. Display Port, and the audio subsystem.
+
+Optional properties:
+- qcom,ext-disp:		phandle for msm-ext-display module
+- compatible:			Must be "qcom,msm-ext-disp"
+
+[Optional child nodes]: These nodes are for devices which are
+dependent on msm_ext_disp. If msm_ext_disp is disabled then
+these devices will be disabled as well. Ex. Audio Codec device.
+
+- ext_disp_audio_codec: Node for Audio Codec.
+- compatible : "qcom,msm-ext-disp-audio-codec-rx";
+
 Example:
+	ext_disp: qcom,msm-ext-disp {
+		compatible = "qcom,msm-ext-disp";
+		ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+			compatible = "qcom,msm-ext-disp-audio-codec-rx";
+		};
+	};
+
 	sde_dp: qcom,dp_display@0{
 		cell-index = <0>;
 		compatible = "qcom,dp-display";
@@ -131,6 +152,7 @@
 			"ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent";
 
 		qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+		qcom,ext-disp = <&ext_disp>;
 
 		qcom,aux-cfg0-settings = [1c 00];
 		qcom,aux-cfg1-settings = [20 13 23 1d];
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index 3ad0986..641cc26 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -96,3 +96,7 @@
 					If ping pong split enabled, this time should not be higher
 					than two times the dsi link rate time.
 					If the property is not specified, then the default value is 14000 us.
+- qcom,dsi-phy-isolation-enabled:	A boolean property enables the phy isolation from dsi
+					controller. This must be enabled for debugging purpose
+					only with simulator panel. It should not be enabled for
+					normal DSI panels.
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
index 28a0920..0c63c7e 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
@@ -18,10 +18,9 @@
   Definition: Should be "qcom,cam-icp".
 
 - compat-hw-name
-
   Usage: required
   Value type: <string>
-  Definition: Should be "qcom,a5" or "qcom,ipe".
+  Definition: Should be "qcom,a5" or "qcom,ipe0" or "qcom,ipe1" or "qcom,bps".
 
 - num-a5
   Usage: required
@@ -63,7 +62,7 @@
 - compatible
   Usage: required
   Value type: <string>
-  Definition: Should be "qcom,cam-cdm-intf".
+  Definition: Should be "qcom,cam-a5" or "qcom,cam-ipe" or "qcom,cam-bps".
 
 - reg-names
   Usage: optional
@@ -128,9 +127,9 @@
   Definition: Name of firmware image.
 
 Examples:
-a5: qcom,a5@a10000 {
+a5: qcom,a5@ac00000 {
 	cell-index = <0>;
-	compatible = "qcom,cam_a5";
+	compatible = "qcom,cam-a5";
 	reg = <0xac00000 0x6000>,
 		<0xac10000 0x8000>,
 		<0xac18000 0x3000>;
@@ -169,7 +168,7 @@
 
 qcom,ipe0 {
 	cell-index = <0>;
-	compatible = "qcom,cam_ipe";
+	compatible = "qcom,cam-ipe";
 	regulator-names = "ipe0-vdd";
 	ipe0-vdd-supply = <&ipe_0_gdsc>;
 	clock-names = "ipe_0_ahb_clk",
@@ -189,7 +188,7 @@
 
 qcom,ipe1 {
 	cell-index = <1>;
-	compatible = "qcom,cam_ipe";
+	compatible = "qcom,cam-ipe";
 	regulator-names = "ipe1-vdd";
 	ipe1-vdd-supply = <&ipe_1_gdsc>;
 	clock-names = "ipe_1_ahb_clk",
@@ -209,7 +208,7 @@
 
 bps: qcom,bps {
 	cell-index = <0>;
-	compatible = "qcom,cam_bps";
+	compatible = "qcom,cam-bps";
 	regulator-names = "bps-vdd";
 	bps-vdd-supply = <&bps_gdsc>;
 	clock-names = "bps_ahb_clk",
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
index 2ed913c..72e2ab4 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
@@ -84,6 +84,11 @@
       - Scratch region: 0x02
       - IO region: 0x03
 
+- iova-granularity
+  Usage: optional
+  Value type: <u32>
+  Definition: Should specify IOVA granularity for shared memory region.
+
 Example:
 	qcom,cam_smmu@0 {
 		compatible = "qcom,msm-cam-smmu";
@@ -114,7 +119,8 @@
 				        iova-region-start = <0x7400000>;
 				        iova-region-len = <0x6400000>;
 					iova-region-id = <0x1>;
-				        status = "ok";
+					iova-granularity = <0x15>;
+					status = "ok";
 				};
 
 			        iova-mem-region-io {
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
index 6df71af..05fa6e4 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
@@ -178,6 +178,10 @@
   Definition: WD bark-timeout in seconds. The possible values are
 		16, 32, 64, 128. If not defined it defaults to 64.
 
+- qcom,sw-jeita-enable
+  Usage:      optional
+  Value type: bool
+  Definition: Boolean flag which when present enables sw compensation for jeita
 
 =============================================
 Second Level Nodes - SMB2 Charger Peripherals
diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
index 9b1b9ee..b0db996 100644
--- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
+++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
@@ -12,6 +12,7 @@
 
 Optional properties:
 - qcom,fastrpc-glink:	Flag to use glink instead of smd for IPC
+- qcom,rpc-latency-us:	FastRPC QoS latency vote
 
 Optional subnodes:
 - qcom,msm_fastrpc_compute_cb :	Child nodes representing the compute context
@@ -26,6 +27,7 @@
 	qcom,msm_fastrpc {
 		compatible = "qcom,msm-fastrpc-adsp";
 		qcom,fastrpc-glink;
+		qcom,rpc-latency-us = <2343>;
 
 		qcom,msm_fastrpc_compute_cb_1 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
diff --git a/Documentation/devicetree/bindings/thermal/regulator-cdev.txt b/Documentation/devicetree/bindings/thermal/regulator-cdev.txt
new file mode 100644
index 0000000..7c9abe2
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/regulator-cdev.txt
@@ -0,0 +1,38 @@
+Regulator cooling device.
+
+The regulator cooling device, will be used to place a voltage floor
+restriction on a rail.
+
+Properties:
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: shall be "qcom,regulator-cooling-device"
+
+- cdev-supply:
+	Usage: required
+	Value type: <phandle>
+	Definition: phandle to the regulator to which the cooling device will
+			place a floor mitigation.
+
+- regulator-levels:
+	Usage: required
+	Value type: <U32 array>
+	Definition: Array of regulator voltages the cooling device should
+			use to place a floor restriction. The voltages should
+			be specified in descending order.
+
+- #cooling-cells: Must be 2. Please refer to
+			<devicetree/bindings/thermal/thermal.txt> for more
+			details.
+
+Example:
+
+	mv_cdev: mx-cdev-lvl {
+		compatible = "qcom,regulator-cooling-device";
+		cdev-supply = <&regulator-cdev-supply>;
+		regulator-levels = <RPMH_REGULATOR_LEVEL_NOM
+			RPMH_REGULATOR_LEVEL_OFF>;
+		#cooling-cells = <2>;
+	};
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 88bd16c..23d4056 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -189,7 +189,6 @@
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_CONSOLE=y
-CONFIG_HVC_DCC=y
 CONFIG_HW_RANDOM=y
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi
index a93deb5..895cbc5 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi
@@ -46,6 +46,31 @@
 
 		qcom,mdss-dsi-display-timings {
 			timing@0{
+				qcom,mdss-dsi-panel-width = <540>;
+				qcom,mdss-dsi-panel-height = <1920>;
+				qcom,mdss-dsi-h-front-porch = <28>;
+				qcom,mdss-dsi-h-back-porch = <4>;
+				qcom,mdss-dsi-h-pulse-width = <4>;
+				qcom,mdss-dsi-h-sync-skew = <0>;
+				qcom,mdss-dsi-v-back-porch = <12>;
+				qcom,mdss-dsi-v-front-porch = <12>;
+				qcom,mdss-dsi-v-pulse-width = <2>;
+				qcom,mdss-dsi-h-left-border = <0>;
+				qcom,mdss-dsi-h-right-border = <0>;
+				qcom,mdss-dsi-v-top-border = <0>;
+				qcom,mdss-dsi-v-bottom-border = <0>;
+				qcom,mdss-dsi-panel-framerate = <120>;
+				qcom,mdss-dsi-on-command =
+					[/* exit sleep mode, wait 0ms */
+					05 01 00 00 00 00 01 29];
+					/* Set display on, wait 16ms */
+				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+				qcom,mdss-dsi-off-command =
+					[05 01 00 00 00 00 02 28 00
+					05 01 00 00 00 00 02 10 00];
+				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+			};
+			timing@1{
 				qcom,mdss-dsi-panel-width = <1280>;
 				qcom,mdss-dsi-panel-height = <1440>;
 				qcom,mdss-dsi-h-front-porch = <120>;
@@ -62,33 +87,33 @@
 				qcom,mdss-dsi-h-sync-pulse = <0>;
 				qcom,mdss-dsi-panel-framerate = <60>;
 				qcom,mdss-dsi-on-command =
-					[29 01 00 00 00 00 02 b0 03
-					05 01 00 00 0a 00 01 00
-					/* Soft reset, wait 10ms */
-					15 01 00 00 0a 00 02 3a 77
-					/* Set Pixel format (24 bpp) */
-					39 01 00 00 0a 00 05 2a 00 00 04 ff
-					/* Set Column address */
-					39 01 00 00 0a 00 05 2b 00 00 05 9f
-					/* Set page address */
-					15 01 00 00 0a 00 02 35 00
-					/* Set tear on */
-					39 01 00 00 0a 00 03 44 00 00
-					/* Set tear scan line */
-					15 01 00 00 0a 00 02 51 ff
-					/* write display brightness */
-					15 01 00 00 0a 00 02 53 24
-					 /* write control brightness */
-					15 01 00 00 0a 00 02 55 00
-					/* CABC brightness */
-					05 01 00 00 78 00 01 11
-					/* exit sleep mode, wait 120ms */
-					05 01 00 00 10 00 01 29];
-					/* Set display on, wait 16ms */
+					[/* exit sleep mode, wait 0ms */
+					05 01 00 00 00 00 01 29];
 				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
 				qcom,mdss-dsi-off-command =
-					[05 01 00 00 32 00 02 28 00
-					05 01 00 00 78 00 02 10 00];
+					[05 01 00 00 00 00 02 28 00
+					05 01 00 00 00 00 02 10 00];
+				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+			};
+			timing@2{
+				qcom,mdss-dsi-panel-width = <1080>;
+				qcom,mdss-dsi-panel-height = <3840>;
+				qcom,mdss-dsi-h-front-porch = <30>;
+				qcom,mdss-dsi-h-back-porch = <100>;
+				qcom,mdss-dsi-h-pulse-width = <4>;
+				qcom,mdss-dsi-h-sync-skew = <0>;
+				qcom,mdss-dsi-v-back-porch = <7>;
+				qcom,mdss-dsi-v-front-porch = <8>;
+				qcom,mdss-dsi-v-pulse-width = <1>;
+				qcom,mdss-dsi-h-sync-pulse = <0>;
+				qcom,mdss-dsi-panel-framerate = <40>;
+				qcom,mdss-dsi-on-command =
+					[/* exit sleep mode, wait 0ms */
+					05 01 00 00 00 00 01 29];
+				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+				qcom,mdss-dsi-off-command =
+					[05 01 00 00 00 00 02 28 00
+					05 01 00 00 00 00 02 10 00];
 				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
 			};
 		};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi
new file mode 100644
index 0000000..95dd07e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-gt3746a6-2900mah.dtsi
@@ -0,0 +1,81 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+qcom,gt3746a6_2900mah {
+	/* #GT3746A6_2900mAh_averaged_MasterSlave_May11th2017*/
+	qcom,max-voltage-uv = <4350000>;
+	qcom,fg-cc-cv-threshold-mv = <4340>;
+	qcom,fastchg-current-ma = <2900>;
+	qcom,batt-id-kohm = <121>;
+	qcom,battery-beta = <3435>;
+	qcom,battery-type = "GT3746A6_2900mah_averaged_masterslave_may11th2017";
+	qcom,checksum = <0xDF27>;
+	qcom,gui-version = "PMI8998GUI - 2.0.0.57";
+	qcom,fg-profile-data = [
+		 C9 1F 44 05
+		 A5 0A 27 06
+		 F0 1C 07 01
+		 49 F2 91 05
+		 C3 17 42 23
+		 69 45 E8 52
+		 58 00 00 00
+		 0E 00 00 00
+		 00 00 DF A2
+		 12 CD 0C C3
+		 19 00 08 00
+		 89 C2 A5 ED
+		 DF 05 1A 01
+		 C0 05 10 12
+		 03 CA C2 32
+		 32 06 09 20
+		 27 00 14 00
+		 69 20 CD 04
+		 F1 0A E3 05
+		 12 1D 59 01
+		 A3 ED D1 05
+		 95 18 27 23
+		 35 45 6D 53
+		 5F 00 00 00
+		 0E 00 00 00
+		 00 00 0A D5
+		 A6 B5 D0 D2
+		 14 00 00 00
+		 52 F2 A5 ED
+		 57 06 AA F2
+		 29 F4 A5 0B
+		 4D FD FA 1A
+		 AD 33 CC FF
+		 07 10 00 00
+		 27 0B 99 45
+		 14 00 40 00
+		 26 02 0A FA
+		 FF 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 00 00 00 00
+	];
+};
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 5d71f2d..5f23b91 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -652,6 +652,27 @@
 		reg = <0x1 SPMI_USID>;
 		#address-cells = <2>;
 		#size-cells = <0>;
+
+		pm660_haptics: qcom,haptics@c000 {
+			compatible = "qcom,qpnp-haptics";
+			reg = <0xc000 0x100>;
+			interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "hap-sc-irq", "hap-play-irq";
+			qcom,pmic-revid = <&pm660_revid>;
+			qcom,pmic-misc = <&pm660_misc>;
+			qcom,misc-clk-trim-error-reg = <0xf3>;
+			qcom,actuator-type = <0>;
+			qcom,play-mode = "direct";
+			qcom,vmax-mv = <3200>;
+			qcom,ilim-ma = <800>;
+			qcom,sc-dbc-cycles = <8>;
+			qcom,wave-play-rate-us = <6667>;
+			qcom,en-brake;
+			qcom,lra-high-z = "opt0";
+			qcom,lra-auto-res-mode = "qwd";
+			qcom,lra-res-cal-period = <4>;
+		};
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 12b469c..a8b826a 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -12,9 +12,10 @@
 
 #include <dt-bindings/spmi/spmi.h>
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/thermal/thermal.h>
 
 &spmi_bus {
-	qcom,pmi8998@2 {
+	pmi8998_lsid0: qcom,pmi8998@2 {
 		compatible = "qcom,spmi-pmic";
 		reg = <0x2 SPMI_USID>;
 		#address-cells = <2>;
@@ -335,7 +336,7 @@
 		};
 	};
 
-	qcom,pmi8998@3 {
+	pmi8998_lsid1: qcom,pmi8998@3 {
 		compatible ="qcom,spmi-pmic";
 		reg = <0x3 SPMI_USID>;
 		#address-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 3fa0ab3..f54cbdc 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -163,62 +163,62 @@
 					"CCI_I2C_CLK1";
 
 		i2c_freq_100Khz: qcom,i2c_standard_mode {
-			qcom,hw-thigh = <201>;
-			qcom,hw-tlow = <174>;
-			qcom,hw-tsu-sto = <204>;
-			qcom,hw-tsu-sta = <231>;
-			qcom,hw-thd-dat = <22>;
-			qcom,hw-thd-sta = <162>;
-			qcom,hw-tbuf = <227>;
-			qcom,hw-scl-stretch-en = <0>;
-			qcom,hw-trdhld = <6>;
-			qcom,hw-tsp = <3>;
-			qcom,cci-clk-src = <37500000>;
+			hw-thigh = <201>;
+			hw-tlow = <174>;
+			hw-tsu-sto = <204>;
+			hw-tsu-sta = <231>;
+			hw-thd-dat = <22>;
+			hw-thd-sta = <162>;
+			hw-tbuf = <227>;
+			hw-scl-stretch-en = <0>;
+			hw-trdhld = <6>;
+			hw-tsp = <3>;
+			cci-clk-src = <37500000>;
 			status = "ok";
 		};
 
 		i2c_freq_400Khz: qcom,i2c_fast_mode {
-			qcom,hw-thigh = <38>;
-			qcom,hw-tlow = <56>;
-			qcom,hw-tsu-sto = <40>;
-			qcom,hw-tsu-sta = <40>;
-			qcom,hw-thd-dat = <22>;
-			qcom,hw-thd-sta = <35>;
-			qcom,hw-tbuf = <62>;
-			qcom,hw-scl-stretch-en = <0>;
-			qcom,hw-trdhld = <6>;
-			qcom,hw-tsp = <3>;
-			qcom,cci-clk-src = <37500000>;
+			hw-thigh = <38>;
+			hw-tlow = <56>;
+			hw-tsu-sto = <40>;
+			hw-tsu-sta = <40>;
+			hw-thd-dat = <22>;
+			hw-thd-sta = <35>;
+			hw-tbuf = <62>;
+			hw-scl-stretch-en = <0>;
+			hw-trdhld = <6>;
+			hw-tsp = <3>;
+			cci-clk-src = <37500000>;
 			status = "ok";
 		};
 
 		i2c_freq_custom: qcom,i2c_custom_mode {
-			qcom,hw-thigh = <38>;
-			qcom,hw-tlow = <56>;
-			qcom,hw-tsu-sto = <40>;
-			qcom,hw-tsu-sta = <40>;
-			qcom,hw-thd-dat = <22>;
-			qcom,hw-thd-sta = <35>;
-			qcom,hw-tbuf = <62>;
-			qcom,hw-scl-stretch-en = <1>;
-			qcom,hw-trdhld = <6>;
-			qcom,hw-tsp = <3>;
-			qcom,cci-clk-src = <37500000>;
+			hw-thigh = <38>;
+			hw-tlow = <56>;
+			hw-tsu-sto = <40>;
+			hw-tsu-sta = <40>;
+			hw-thd-dat = <22>;
+			hw-thd-sta = <35>;
+			hw-tbuf = <62>;
+			hw-scl-stretch-en = <1>;
+			hw-trdhld = <6>;
+			hw-tsp = <3>;
+			cci-clk-src = <37500000>;
 			status = "ok";
 		};
 
 		i2c_freq_1Mhz: qcom,i2c_fast_plus_mode {
-			qcom,hw-thigh = <16>;
-			qcom,hw-tlow = <22>;
-			qcom,hw-tsu-sto = <17>;
-			qcom,hw-tsu-sta = <18>;
-			qcom,hw-thd-dat = <16>;
-			qcom,hw-thd-sta = <15>;
-			qcom,hw-tbuf = <24>;
-			qcom,hw-scl-stretch-en = <0>;
-			qcom,hw-trdhld = <3>;
-			qcom,hw-tsp = <3>;
-			qcom,cci-clk-src = <37500000>;
+			hw-thigh = <16>;
+			hw-tlow = <22>;
+			hw-tsu-sto = <17>;
+			hw-tsu-sta = <18>;
+			hw-thd-dat = <16>;
+			hw-thd-sta = <15>;
+			hw-tbuf = <24>;
+			hw-scl-stretch-en = <0>;
+			hw-trdhld = <3>;
+			hw-tsp = <3>;
+			cci-clk-src = <37500000>;
 			status = "ok";
 		};
 	};
@@ -795,7 +795,7 @@
 
 	cam_a5: qcom,a5@ac00000 {
 		cell-index = <0>;
-		compatible = "qcom,cam_a5";
+		compatible = "qcom,cam-a5";
 		reg = <0xac00000 0x6000>,
 			<0xac10000 0x8000>,
 			<0xac18000 0x3000>;
@@ -832,7 +832,7 @@
 
 	cam_ipe0: qcom,ipe0 {
 		cell-index = <0>;
-		compatible = "qcom,cam_ipe";
+		compatible = "qcom,cam-ipe";
 		regulator-names = "ipe0-vdd";
 		ipe0-vdd-supply = <&ipe_0_gdsc>;
 		clock-names = "ipe_0_ahb_clk",
@@ -853,7 +853,7 @@
 
 	cam_ipe1: qcom,ipe1 {
 		cell-index = <1>;
-		compatible = "qcom,cam_ipe";
+		compatible = "qcom,cam-ipe";
 		regulator-names = "ipe1-vdd";
 		ipe1-vdd-supply = <&ipe_1_gdsc>;
 		clock-names = "ipe_1_ahb_clk",
@@ -874,7 +874,7 @@
 
 	cam_bps: qcom,bps {
 		cell-index = <0>;
-		compatible = "qcom,cam_bps";
+		compatible = "qcom,cam-bps";
 		regulator-names = "bps-vdd";
 		bps-vdd-supply = <&bps_gdsc>;
 		clock-names = "bps_ahb_clk",
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 8fca29c..3a0e4b6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -11,6 +11,8 @@
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
 #include "sdm845-camera-sensor-cdp.dtsi"
 
 &vendor {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index b9e9c34..cac5bc0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -367,18 +367,18 @@
 	/delete-node/ rpmh-regulator-gfxlvl;
 	/delete-node/ rpmh-regulator-msslvl;
 	/delete-node/ rpmh-regulator-smpc3;
-	/delete-node/ ext_5v_boost;
 };
 
 &spmi_bus {
 	/delete-node/ qcom,pm8998@0;
 	/delete-node/ qcom,pm8998@1;
-	/delete-node/ qcom,pmi8998@2;
-	/delete-node/ qcom,pmi8998@3;
 	/delete-node/ qcom,pm8005@4;
 	/delete-node/ qcom,pm8005@5;
 };
 
+/delete-node/ &pmi8998_lsid0;
+/delete-node/ &pmi8998_lsid1;
+/delete-node/ &ext_5v_boost;
 
 #include "pm660.dtsi"
 #include "pm660l.dtsi"
@@ -388,6 +388,11 @@
 	/delete-node/ thermal-zones;
 };
 
+&lmh_dcvs1 {
+	/delete-property/ isens_vref-supply;
+	/delete-property/ isens-vref-settings;
+};
+
 &pm660l_wled {
 	qcom,led-strings-list = [01 02];
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi
new file mode 100644
index 0000000..f861ca3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi
@@ -0,0 +1,81 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm670-audio.dtsi"
+
+&msm_audio_ion {
+	iommus = <&apps_smmu 0x1821 0x0>;
+	qcom,smmu-sid-mask = /bits/ 64 <0xf>;
+};
+
+&qupv3_se8_spi {
+	status = "okay";
+};
+
+&pm660l_3 {
+	/delete-node/analog-codec;
+};
+
+&soc {
+	/delete-node/msm-sdw-codec@62ec1000;
+	/delete-node/sound;
+	/delete-node/cdc_pdm_pinctrl;
+	/delete-node/wsa_spkr_en1_pinctrl;
+	/delete-node/wsa_spkr_en2_pinctrl;
+	/delete-node/sdw_clk_data_pinctrl;
+};
+
+&msm_audio_ion {
+	iommus = <&apps_smmu 0x1821 0x0>;
+};
+
+&wcd9xxx_intc {
+	status = "okay";
+	qcom,gpio-connect = <&tlmm 54 0>;
+};
+
+&wdsp_mgr {
+	status = "okay";
+};
+
+&wdsp_glink {
+	status = "okay";
+};
+
+&slim_aud {
+	status = "okay";
+};
+
+&dai_slim {
+	status = "okay";
+};
+
+&wcd934x_cdc {
+	status = "okay";
+};
+
+&clock_audio_lnbb {
+	status = "okay";
+};
+
+&wcd_rst_gpio {
+	status = "okay";
+};
+
+&wcd9xxx_intc {
+	status = "okay";
+};
+
+&tavil_snd {
+	status = "okay";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
index 853e28b..ad15615 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
@@ -12,3 +12,4 @@
 
 #include "sdm845-cdp.dtsi"
 #include "sdm845-interposer-pm660.dtsi"
+#include "sdm845-interposer-sdm670-audio.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
index 9320b22b..c709770 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
@@ -12,6 +12,7 @@
 
 #include "sdm845-mtp.dtsi"
 #include "sdm845-interposer-pm660.dtsi"
+#include "sdm845-interposer-sdm670-audio.dtsi"
 
 &qupv3_se10_i2c {
 	/delete-node/ qcom,smb1355@8;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index 29d80a7..c3e8b60 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -11,6 +11,8 @@
  */
 
 #include <dt-bindings/gpio/gpio.h>
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
 #include "sdm845-camera-sensor-mtp.dtsi"
 #include "smb1355.dtsi"
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi
new file mode 100644
index 0000000..8dd75b69
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi
@@ -0,0 +1,51 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&pmi8998_gpios {
+	usb2_vbus_boost {
+		usb2_vbus_boost_default: usb2_vbus_boost_default {
+			pins = "gpio2";
+			function = "normal";
+			output-low;
+			power-source = <0>;
+		};
+	};
+
+	usb2_vbus_det {
+		usb2_vbus_det_default: usb2_vbus_det_default {
+			pins = "gpio8";
+			function = "normal";
+			input-enable;
+			bias-pull-down;
+			power-source = <1>;	/* VPH input supply */
+		};
+	};
+
+	usb2_id_det {
+		usb2_id_det_default: usb2_id_det_default {
+			pins = "gpio9";
+			function = "normal";
+			input-enable;
+			bias-pull-up;
+			power-source = <0>;
+		};
+	};
+
+	usb2_ext_5v_boost {
+		usb2_ext_5v_boost_default: usb2_ext_5v_boost_default {
+			pins = "gpio10";
+			function = "normal";
+			output-low;
+			power-source = <0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index f691740..3e27297 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -3011,43 +3011,3 @@
 		};
 	};
 };
-
-&pmi8998_gpios {
-	usb2_vbus_boost {
-		usb2_vbus_boost_default: usb2_vbus_boost_default {
-			pins = "gpio2";
-			function = "normal";
-			output-low;
-			power-source = <0>;
-		};
-	};
-
-	usb2_vbus_det {
-		usb2_vbus_det_default: usb2_vbus_det_default {
-			pins = "gpio8";
-			function = "normal";
-			input-enable;
-			bias-pull-down;
-			power-source = <1>;	/* VPH input supply */
-		};
-	};
-
-	usb2_id_det {
-		usb2_id_det_default: usb2_id_det_default {
-			pins = "gpio9";
-			function = "normal";
-			input-enable;
-			bias-pull-up;
-			power-source = <0>;
-		};
-	};
-
-	usb2_ext_5v_boost {
-		usb2_ext_5v_boost_default: usb2_ext_5v_boost_default {
-			pins = "gpio10";
-			function = "normal";
-			output-low;
-			power-source = <0>;
-		};
-	};
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index 6215771..c8698c28 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
@@ -51,7 +51,7 @@
 				reg = <2>;
 				label = "l3-pc";
 				qcom,psci-mode = <0x4>;
-				qcom,latency-us = <4562>;
+				qcom,latency-us = <3201>;
 				qcom,ss-power = <408>;
 				qcom,energy-overhead = <2421840>;
 				qcom,time-overhead = <5376>;
@@ -105,7 +105,7 @@
 					reg = <1>;
 					qcom,psci-cpu-mode = <0x2>;
 					qcom,spm-cpu-mode = "ret";
-					qcom,latency-us = <86>;
+					qcom,latency-us = <119>;
 					qcom,ss-power = <449>;
 					qcom,energy-overhead = <78456>;
 					qcom,time-overhead = <167>;
@@ -115,7 +115,7 @@
 					reg = <2>;
 					qcom,spm-cpu-mode = "pc";
 					qcom,psci-cpu-mode = <0x3>;
-					qcom,latency-us = <612>;
+					qcom,latency-us = <461>;
 					qcom,ss-power = <436>;
 					qcom,energy-overhead = <418225>;
 					qcom,time-overhead = <885>;
@@ -127,7 +127,7 @@
 					reg = <3>;
 					qcom,spm-cpu-mode = "rail-pc";
 					qcom,psci-cpu-mode = <0x4>;
-					qcom,latency-us = <700>;
+					qcom,latency-us = <531>;
 					qcom,ss-power = <400>;
 					qcom,energy-overhead = <428225>;
 					qcom,time-overhead = <1000>;
@@ -157,7 +157,7 @@
 					reg = <1>;
 					qcom,psci-cpu-mode = <0x2>;
 					qcom,spm-cpu-mode = "ret";
-					qcom,latency-us = <86>;
+					qcom,latency-us = <116>;
 					qcom,ss-power = <449>;
 					qcom,energy-overhead = <78456>;
 					qcom,time-overhead = <167>;
@@ -167,7 +167,7 @@
 					reg = <2>;
 					qcom,spm-cpu-mode = "pc";
 					qcom,psci-cpu-mode = <0x3>;
-					qcom,latency-us = <612>;
+					qcom,latency-us = <621>;
 					qcom,ss-power = <436>;
 					qcom,energy-overhead = <418225>;
 					qcom,time-overhead = <885>;
@@ -179,7 +179,7 @@
 					reg = <3>;
 					qcom,spm-cpu-mode = "rail-pc";
 					qcom,psci-cpu-mode = <0x4>;
-					qcom,latency-us = <700>;
+					qcom,latency-us = <1061>;
 					qcom,ss-power = <400>;
 					qcom,energy-overhead = <428225>;
 					qcom,time-overhead = <1000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
new file mode 100644
index 0000000..000d65e7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi
@@ -0,0 +1,39 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+#include "pmi8998.dtsi"
+
+&vendor {
+	ext_5v_boost: ext_5v_boost {
+		status = "disabled";
+		compatible = "regulator-fixed";
+		regulator-name = "ext_5v_boost";
+		gpio = <&pmi8998_gpios 10 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+
+		regulator-enable-ramp-delay = <1600>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usb2_ext_5v_boost_default>;
+	};
+};
+
+&pmi8998_charger {
+	smb2_vconn: qcom,smb2-vconn {
+		regulator-name = "smb2-vconn";
+	};
+};
+
+&usb0 {
+	extcon = <&pmi8998_pdphy>, <&pmi8998_pdphy>, <&eud>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
index b11c912..361fa2f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi
@@ -30,33 +30,31 @@
 	};
 };
 
-&wcd934x_cdc {
-	wcd_pinctrl@5 {
-		us_euro_sw_wcd_active {
-			mux {
-				pins = "gpio1";
-			};
-
-			config {
-				pins = "gpio1";
-				/delete-property/ output-high;
-				bias-high-impedance;
-			};
-		};
-
-		us_euro_sw_wcd_sleep {
-			mux {
-				pins = "gpio1";
-			};
-
-			config {
-				pins = "gpio1";
-				/delete-property/ output-low;
-				bias-high-impedance;
-			};
-		};
+&us_euro_sw_wcd_active {
+	mux {
+		pins = "gpio1";
 	};
 
+	config {
+		pins = "gpio1";
+		/delete-property/ output-high;
+		bias-high-impedance;
+	};
+};
+
+&us_euro_sw_wcd_sleep {
+	mux {
+		pins = "gpio1";
+	};
+
+	config {
+		pins = "gpio1";
+		/delete-property/ output-low;
+		bias-high-impedance;
+	};
+};
+
+&wcd934x_cdc {
 	swr_master {
 		wsa881x@20170211 {
 			compatible = "qcom,wsa881x";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index c0afb74..6122eee 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
 #include "smb1355.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 
@@ -37,8 +39,7 @@
 
 	qrd_batterydata: qcom,battery-data {
 		qcom,batt-id-range-pct = <15>;
-		#include "fg-gen3-batterydata-itech-3000mah.dtsi"
-		#include "fg-gen3-batterydata-ascent-3450mah.dtsi"
+		#include "fg-gen3-batterydata-gt3746a6-2900mah.dtsi"
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 8350d90..55fe84b4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -792,6 +792,14 @@
 			regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
 			regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
 		};
+
+		mx_cdev: mx-cdev-lvl {
+			compatible = "qcom,regulator-cooling-device";
+			regulator-cdev-supply = <&pm8998_s6_level>;
+			regulator-levels = <RPMH_REGULATOR_LEVEL_NOM
+					RPMH_REGULATOR_LEVEL_OFF>;
+			#cooling-cells = <2>;
+		};
 	};
 
 	rpmh-regulator-smpa7 {
@@ -923,13 +931,6 @@
 			regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
 			regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
 		};
-
-		mx_cdev: regulator-cdev {
-			compatible = "qcom,rpmh-reg-cdev";
-			mboxes = <&qmp_aop 0>;
-			qcom,reg-resource-name = "mx";
-			#cooling-cells = <2>;
-		};
 	};
 
 	rpmh-regulator-ldoa5 {
@@ -1439,22 +1440,4 @@
 			qcom,init-voltage = <600000>;
 		};
 	};
-
-	ext_5v_boost: ext_5v_boost {
-		status = "disabled";
-		compatible = "regulator-fixed";
-		regulator-name = "ext_5v_boost";
-		gpio = <&pmi8998_gpios 10 GPIO_ACTIVE_HIGH>;
-		enable-active-high;
-
-		regulator-enable-ramp-delay = <1600>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&usb2_ext_5v_boost_default>;
-	};
-};
-
-&pmi8998_charger {
-	smb2_vconn: qcom,smb2-vconn {
-		regulator-name = "smb2-vconn";
-	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
index 6991b17..e7fd8a0 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
@@ -11,6 +11,8 @@
  */
 
 #include <dt-bindings/spmi/spmi.h>
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
 
 &ufsphy_mem {
 	compatible = "qcom,ufs-phy-qrbtc-sdm845";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 21aedbf..f33e400 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -369,6 +369,14 @@
 		label = "wb_display";
 	};
 
+	ext_disp: qcom,msm-ext-disp {
+		compatible = "qcom,msm-ext-disp";
+
+		ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+			compatible = "qcom,msm-ext-disp-audio-codec-rx";
+		};
+	};
+
 	sde_dp: qcom,dp_display@0{
 		cell-index = <0>;
 		compatible = "qcom,dp-display";
@@ -410,6 +418,7 @@
 			"crypto_clk", "pixel_clk_rcg", "pixel_parent";
 
 		qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+		qcom,ext-disp = <&ext_disp>;
 
 		qcom,aux-cfg0-settings = [20 00];
 		qcom,aux-cfg1-settings = [24 13 23 1d];
@@ -639,11 +648,23 @@
 	qcom,mdss-dsi-t-clk-pre = <0x2d>;
 	qcom,mdss-dsi-display-timings {
 		timing@0{
+			qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09
+				09 06 03 04 00];
+			qcom,display-topology = <2 0 2>;
+			qcom,default-topology-index = <0>;
+		};
+		timing@1{
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
 				07 05 03 04 00];
 			qcom,display-topology = <2 0 2>,
 						<1 0 2>;
 			qcom,default-topology-index = <0>;
 		};
+		timing@2{
+			qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
+				06 04 03 04 00];
+			qcom,display-topology = <2 0 2>;
+			qcom,default-topology-index = <0>;
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 0618f92..121565e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -14,11 +14,9 @@
 	mdss_mdp: qcom,mdss_mdp@ae00000 {
 		compatible = "qcom,sde-kms";
 		reg = <0x0ae00000 0x81d40>,
-		      <0x0aeb0000 0x2008>,
-		      <0x0aeac000 0xf0>;
+		      <0x0aeb0000 0x2008>;
 		reg-names = "mdp_phys",
-			"vbif_phys",
-			"regdma_phys";
+			"vbif_phys";
 
 		clocks =
 			<&clock_gcc GCC_DISP_AHB_CLK>,
@@ -181,9 +179,6 @@
 		/* offsets are relative to "mdp_phys + qcom,sde-off */
 		qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>;
 
-		qcom,sde-reg-dma-off = <0>;
-		qcom,sde-reg-dma-version = <0x1>;
-		qcom,sde-reg-dma-trigger-off = <0x119c>;
 
 		qcom,sde-sspp-vig-blocks {
 			qcom,sde-vig-csc-off = <0x1a00>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi
index a03148d..efb337d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sim.dtsi
@@ -10,6 +10,9 @@
  * GNU General Public License for more details.
  */
 
+#include "sdm845-pmic-overlay.dtsi"
+#include "sdm845-pinctrl-overlay.dtsi"
+
 &pmi8998_charger {
 	qcom,suspend-input;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index 40c677f..f721025 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -36,7 +36,7 @@
 		qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
 		qcom,num-gsi-evt-buffs = <0x3>;
 		qcom,use-pdc-interrupts;
-		extcon = <&pmi8998_pdphy>, <&pmi8998_pdphy>, <&eud>;
+		extcon = <0>, <0>, <&eud>;
 
 		clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>,
 			 <&clock_gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
new file mode 100644
index 0000000..13b5bfd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	cam_csiphy0: qcom,csiphy@ac65000 {
+		cell-index = <0>;
+		compatible = "qcom,csiphy-v1.0", "qcom,csiphy";
+		reg = <0x0ac65000 0x1000>;
+		reg-names = "csiphy";
+		reg-cam-base = <0x65000>;
+		interrupts = <0 477 0>;
+		interrupt-names = "csiphy";
+		regulator-names = "gdscr";
+		gdscr-supply = <&titan_top_gdsc>;
+		csi-vdd-voltage = <1200000>;
+		mipi-csi-vdd-supply = <&pm8998_l26>;
+		mipi-dsi-vdd-supply = <&pm8998_l1>;
+		clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+			<&clock_camcc CAM_CC_CSIPHY0_CLK>,
+			<&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>,
+			<&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>;
+		clock-names = "camnoc_axi_clk",
+			"soc_ahb_clk",
+			"slow_ahb_src_clk",
+			"cpas_ahb_clk",
+			"cphy_rx_clk_src",
+			"csiphy0_clk",
+			"csi0phytimer_clk_src",
+			"csi0phytimer_clk";
+		clock-cntl-level = "turbo";
+		clock-rates =
+			<0 0 0 0 384000000 0 269333333 0>;
+		status = "ok";
+	};
+
+	cam_csiphy1: qcom,csiphy@ac66000{
+		cell-index = <1>;
+		compatible = "qcom,csiphy-v1.0", "qcom,csiphy";
+		reg = <0xac66000 0x1000>;
+		reg-names = "csiphy";
+		reg-cam-base = <0x66000>;
+		interrupts = <0 478 0>;
+		interrupt-names = "csiphy";
+		regulator-names = "gdscr";
+		gdscr-supply = <&titan_top_gdsc>;
+		csi-vdd-voltage = <1200000>;
+		mipi-csi-vdd-supply = <&pm8998_l26>;
+		mipi-dsi-vdd-supply = <&pm8998_l1>;
+		clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+			<&clock_camcc CAM_CC_CSIPHY1_CLK>,
+			<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>,
+			<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>;
+		clock-names = "camnoc_axi_clk",
+			"soc_ahb_clk",
+			"slow_ahb_src_clk",
+			"cpas_ahb_clk",
+			"cphy_rx_clk_src",
+			"csiphy1_clk",
+			"csi1phytimer_clk_src",
+			"csi1phytimer_clk";
+		clock-cntl-level = "turbo";
+		clock-rates =
+			<0 0 0 0 384000000 0 269333333 0>;
+
+		status = "ok";
+	};
+
+	cam_csiphy2: qcom,csiphy@ac67000 {
+		cell-index = <2>;
+		compatible = "qcom,csiphy-v1.0", "qcom,csiphy";
+		reg = <0xac67000 0x1000>;
+		reg-names = "csiphy";
+		reg-cam-base = <0x67000>;
+		interrupts = <0 479 0>;
+		interrupt-names = "csiphy";
+		regulator-names = "gdscr";
+		gdscr-supply = <&titan_top_gdsc>;
+		csi-vdd-voltage = <1200000>;
+		mipi-csi-vdd-supply = <&pm8998_l26>;
+		mipi-dsi-vdd-supply = <&pm8998_l1>;
+		clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+			<&clock_camcc CAM_CC_CSIPHY2_CLK>,
+			<&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>,
+			<&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>;
+		clock-names = "camnoc_axi_clk",
+			"soc_ahb_clk",
+			"slow_ahb_src_clk",
+			"cpas_ahb_clk",
+			"cphy_rx_clk_src",
+			"csiphy2_clk",
+			"csi2phytimer_clk_src",
+			"csi2phytimer_clk";
+		clock-cntl-level = "turbo";
+		clock-rates =
+			<0 0 0 0 384000000 0 269333333 0>;
+		status = "ok";
+	};
+
+	cam_csiphy3: qcom,csiphy@ac68000 {
+		cell-index = <3>;
+		compatible = "qcom,csiphy-v1.0", "qcom,csiphy";
+		reg = <0xac67000 0x1000>;
+		reg-names = "csiphy";
+		reg-cam-base = <0x68000>;
+		interrupts = <0 448 0>;
+		interrupt-names = "csiphy";
+		regulator-names = "gdscr";
+		gdscr-supply = <&titan_top_gdsc>;
+		csi-vdd-voltage = <1200000>;
+		mipi-csi-vdd-supply = <&pm8998_l26>;
+		mipi-dsi-vdd-supply = <&pm8998_l1>;
+		clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
+			<&clock_camcc CAM_CC_CSIPHY3_CLK>,
+			<&clock_camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>,
+			<&clock_camcc CAM_CC_CSI3PHYTIMER_CLK>;
+		clock-names = "camnoc_axi_clk",
+			"soc_ahb_clk",
+			"slow_ahb_src_clk",
+			"cpas_ahb_clk",
+			"cphy_rx_clk_src",
+			"csiphy3_clk",
+			"csi3phytimer_clk_src",
+			"csi3phytimer_clk";
+		clock-cntl-level = "turbo";
+		clock-rates =
+			<0 0 0 0 384000000 0 269333333 0>;
+		status = "ok";
+	};
+
+	qcom,cam_smmu {
+		compatible = "qcom,msm-cam-smmu";
+		status = "ok";
+
+		msm_cam_smmu_ife {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x808 0x0>,
+				<&apps_smmu 0x810 0x8>,
+				<&apps_smmu 0xc08 0x0>,
+				<&apps_smmu 0xc10 0x8>;
+			label = "ife";
+			ife_iova_mem_map: iova-mem-map {
+				/* IO region is approximately 3.4 GB */
+				iova-mem-region-io {
+					iova-region-name = "io";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0xd8c00000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
+
+		msm_cam_icp_fw {
+			compatible = "qcom,msm-cam-smmu-fw-dev";
+			label="icp";
+			memory-region = <&pil_camera_mem>;
+		};
+
+		msm_cam_smmu_icp {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x107A 0x2>,
+				<&apps_smmu 0x1020 0x8>,
+				<&apps_smmu 0x1040 0x8>,
+				<&apps_smmu 0x1030 0x0>,
+				<&apps_smmu 0x1050 0x0>;
+			label = "icp";
+			icp_iova_mem_map: iova-mem-map {
+				iova-mem-region-firmware {
+					/* Firmware region is 5MB */
+					iova-region-name = "firmware";
+					iova-region-start = <0x0>;
+					iova-region-len = <0x500000>;
+					iova-region-id = <0x0>;
+					status = "ok";
+				};
+
+				iova-mem-region-shared {
+					/* Shared region is 100MB long */
+					iova-region-name = "shared";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0x6400000>;
+					iova-region-id = <0x1>;
+					iova-granularity = <0x15>;
+					status = "ok";
+				};
+
+				iova-mem-region-io {
+					/* IO region is approximately 3.3 GB */
+					iova-region-name = "io";
+					iova-region-start = <0xd800000>;
+					iova-region-len = <0xd2800000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
+
+		msm_cam_smmu_cpas_cdm {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x1000 0x0>;
+			label = "cpas-cdm0";
+			cpas_cdm_iova_mem_map: iova-mem-map {
+				iova-mem-region-io {
+					/* IO region is approximately 3.4 GB */
+					iova-region-name = "io";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0xd8c00000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
+
+		msm_cam_smmu_secure {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x1001 0x0>;
+			label = "cam-secure";
+			cam_secure_iova_mem_map: iova-mem-map {
+				/* Secure IO region is approximately 3.4 GB */
+				iova-mem-region-io {
+					iova-region-name = "io";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0xd8c00000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
+	};
+
+	qcom,cam-cpas@ac40000 {
+		cell-index = <0>;
+		compatible = "qcom,cam-cpas";
+		label = "cpas";
+		arch-compat = "cpas_top";
+		status = "ok";
+		reg-names = "cam_cpas_top", "cam_camnoc";
+		reg = <0xac40000 0x1000>,
+			<0xac42000 0x5000>;
+		reg-cam-base = <0x40000 0x42000>;
+		interrupt-names = "cpas_camnoc";
+		interrupts = <0 459 0>;
+		regulator-names = "camss-vdd";
+		camss-vdd-supply = <&titan_top_gdsc>;
+		clock-names = "gcc_ahb_clk",
+			"gcc_axi_clk",
+			"soc_ahb_clk",
+			"slow_ahb_clk_src",
+			"cpas_ahb_clk",
+			"camnoc_axi_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>;
+		src-clock-name = "slow_ahb_clk_src";
+		clock-rates = <0 0 0 0 0 0>,
+			<0 0 0 19200000 0 0>,
+			<0 0 0 80000000 0 0>,
+			<0 0 0 80000000 0 0>,
+			<0 0 0 80000000 0 0>,
+			<0 0 0 80000000 0 0>,
+			<0 0 0 80000000 0 0>;
+		clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs",
+			"svs_l1", "nominal", "turbo";
+		qcom,msm-bus,name = "cam_ahb";
+		qcom,msm-bus,num-cases = <7>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<MSM_BUS_MASTER_AMPSS_M0
+			MSM_BUS_SLAVE_CAMERA_CFG 0 0>,
+			<MSM_BUS_MASTER_AMPSS_M0
+			MSM_BUS_SLAVE_CAMERA_CFG 0 153000>,
+			<MSM_BUS_MASTER_AMPSS_M0
+			MSM_BUS_SLAVE_CAMERA_CFG 0 153000>,
+			<MSM_BUS_MASTER_AMPSS_M0
+			MSM_BUS_SLAVE_CAMERA_CFG 0 300000>,
+			<MSM_BUS_MASTER_AMPSS_M0
+			MSM_BUS_SLAVE_CAMERA_CFG 0 300000>,
+			<MSM_BUS_MASTER_AMPSS_M0
+			MSM_BUS_SLAVE_CAMERA_CFG 0 600000>,
+			<MSM_BUS_MASTER_AMPSS_M0
+			MSM_BUS_SLAVE_CAMERA_CFG 0 600000>;
+		vdd-corners = <RPMH_REGULATOR_LEVEL_OFF
+			RPMH_REGULATOR_LEVEL_RETENTION
+			RPMH_REGULATOR_LEVEL_MIN_SVS
+			RPMH_REGULATOR_LEVEL_LOW_SVS
+			RPMH_REGULATOR_LEVEL_SVS
+			RPMH_REGULATOR_LEVEL_SVS_L1
+			RPMH_REGULATOR_LEVEL_NOM
+			RPMH_REGULATOR_LEVEL_NOM_L1
+			RPMH_REGULATOR_LEVEL_NOM_L2
+			RPMH_REGULATOR_LEVEL_TURBO
+			RPMH_REGULATOR_LEVEL_TURBO_L1>;
+		vdd-corner-ahb-mapping = "suspend", "suspend",
+			"minsvs", "lowsvs", "svs", "svs_l1",
+			"nominal", "nominal", "nominal",
+			"turbo", "turbo";
+		client-id-based;
+		client-names =
+			"csiphy0", "csiphy1", "csiphy2", "cci0",
+			"csid0", "csid1", "csid2",
+			"ife0", "ife1", "ife2", "ipe0",
+			"ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0",
+			"icp0", "jpeg-dma0", "jpeg-enc0", "fd0";
+		client-axi-port-names =
+			"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
+			"cam_hf_1", "cam_hf_2", "cam_hf_2",
+			"cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1",
+			"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1",
+			"cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1";
+		client-bus-camnoc-based;
+		qcom,axi-port-list {
+			qcom,axi-port1 {
+				qcom,axi-port-name = "cam_hf_1";
+				qcom,axi-port-mnoc {
+					qcom,msm-bus,name = "cam_hf_1_mnoc";
+					qcom,msm-bus-vector-dyn-vote;
+					qcom,msm-bus,num-cases = <2>;
+					qcom,msm-bus,num-paths = <1>;
+					qcom,msm-bus,vectors-KBps =
+					<MSM_BUS_MASTER_CAMNOC_HF0
+					MSM_BUS_SLAVE_EBI_CH0 0 0>,
+					<MSM_BUS_MASTER_CAMNOC_HF0
+					MSM_BUS_SLAVE_EBI_CH0 0 0>;
+				};
+				qcom,axi-port-camnoc {
+					qcom,msm-bus,name = "cam_hf_1_camnoc";
+					qcom,msm-bus-vector-dyn-vote;
+					qcom,msm-bus,num-cases = <2>;
+					qcom,msm-bus,num-paths = <1>;
+					qcom,msm-bus,vectors-KBps =
+					<MSM_BUS_MASTER_CAMNOC_HF0_UNCOMP
+					MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>,
+					<MSM_BUS_MASTER_CAMNOC_HF0_UNCOMP
+					MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>;
+				};
+			};
+			qcom,axi-port2 {
+				qcom,axi-port-name = "cam_hf_2";
+				qcom,axi-port-mnoc {
+					qcom,msm-bus,name = "cam_hf_2_mnoc";
+					qcom,msm-bus-vector-dyn-vote;
+					qcom,msm-bus,num-cases = <2>;
+					qcom,msm-bus,num-paths = <1>;
+					qcom,msm-bus,vectors-KBps =
+					<MSM_BUS_MASTER_CAMNOC_HF1
+					MSM_BUS_SLAVE_EBI_CH0 0 0>,
+					<MSM_BUS_MASTER_CAMNOC_HF1
+					MSM_BUS_SLAVE_EBI_CH0 0 0>;
+				};
+				qcom,axi-port-camnoc {
+					qcom,msm-bus,name = "cam_hf_2_camnoc";
+					qcom,msm-bus-vector-dyn-vote;
+					qcom,msm-bus,num-cases = <2>;
+					qcom,msm-bus,num-paths = <1>;
+					qcom,msm-bus,vectors-KBps =
+					<MSM_BUS_MASTER_CAMNOC_HF1_UNCOMP
+					MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>,
+					<MSM_BUS_MASTER_CAMNOC_HF1_UNCOMP
+					MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>;
+				};
+			};
+			qcom,axi-port3 {
+				qcom,axi-port-name = "cam_sf_1";
+				qcom,axi-port-mnoc {
+					qcom,msm-bus,name = "cam_sf_1_mnoc";
+					qcom,msm-bus-vector-dyn-vote;
+					qcom,msm-bus,num-cases = <2>;
+					qcom,msm-bus,num-paths = <1>;
+					qcom,msm-bus,vectors-KBps =
+					<MSM_BUS_MASTER_CAMNOC_SF
+					MSM_BUS_SLAVE_EBI_CH0 0 0>,
+					<MSM_BUS_MASTER_CAMNOC_SF
+					MSM_BUS_SLAVE_EBI_CH0 0 0>;
+				};
+				qcom,axi-port-camnoc {
+					qcom,msm-bus,name = "cam_sf_1_camnoc";
+					qcom,msm-bus-vector-dyn-vote;
+					qcom,msm-bus,num-cases = <2>;
+					qcom,msm-bus,num-paths = <1>;
+					qcom,msm-bus,vectors-KBps =
+					<MSM_BUS_MASTER_CAMNOC_SF_UNCOMP
+					MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>,
+					<MSM_BUS_MASTER_CAMNOC_SF_UNCOMP
+					MSM_BUS_SLAVE_CAMNOC_UNCOMP 0 0>;
+				};
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 761efea..131d932 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -11,6 +11,7 @@
  */
 
 #include "sdm845.dtsi"
+#include "sdm845-v2-camera.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM845 V2";
@@ -95,7 +96,7 @@
 					<828000  828000  828000  828000  828000
 					 828000  828000  828000  828000  828000
 					 828000  828000  828000  828000  828000
-					 884000  952000  952000>;
+					 884000 1000000 1000000>;
 
 				qcom,cpr-voltage-floor =
 					<568000  568000  568000  568000  568000
@@ -164,37 +165,69 @@
 			apc0_l3_vreg: regulator {
 				regulator-name = "apc0_l3_corner";
 				regulator-min-microvolt = <1>;
-				regulator-max-microvolt = <14>;
+				regulator-max-microvolt = <15>;
 
 				qcom,cpr-fuse-corners = <4>;
 				qcom,cpr-fuse-combos = <16>;
 				qcom,cpr-speed-bins = <2>;
-				qcom,cpr-speed-bin-corners = <14 14>;
-				qcom,cpr-corners = <14>;
+				qcom,cpr-speed-bin-corners = <14 15>;
+				qcom,cpr-corners =
+					/* Speed bin 0 */
+					<14 14 14 14 14 14 14 14>,
+					/* Speed bin 1 */
+					<15 15 15 15 15 15 15 15>;
 
-				qcom,cpr-corner-fmax-map = <4 8 11 14>;
+				qcom,cpr-corner-fmax-map =
+					/* Speed bin 0 */
+					<4 8 11 14>,
+					/* Speed bin 1 */
+					<4 8 11 15>;
 
 				qcom,cpr-voltage-ceiling =
+					/* Speed bin 0 */
 					<828000  828000  828000  828000  828000
 					 828000  828000  828000  828000  828000
-					 828000  884000  884000  952000>;
+					 828000  884000  884000 1000000>,
+					/* Speed bin 1 */
+					<828000  828000  828000  828000  828000
+					 828000  828000  828000  828000  828000
+					 828000  884000  884000 1000000
+					1000000>;
 
 				qcom,cpr-voltage-floor =
+					/* Speed bin 0 */
 					<568000  568000  568000  568000  568000
 					 568000  568000  568000  568000  568000
-					 568000  568000  568000  568000>;
+					 568000  568000  568000  568000>,
+					/* Speed bin 1 */
+					<568000  568000  568000  568000  568000
+					 568000  568000  568000  568000  568000
+					 568000  568000  568000  568000
+					 568000>;
 
 				qcom,cpr-floor-to-ceiling-max-range =
+					/* Speed bin 0 */
 					<32000  32000  32000  32000  32000
 					 32000  32000  32000  32000  32000
-					 32000  32000  32000  40000>;
+					 32000  32000  32000  40000>,
+					/* Speed bin 1 */
+					<32000  32000  32000  32000  32000
+					 32000  32000  32000  32000  32000
+					 32000  32000  32000  40000  40000>;
 
 				qcom,corner-frequencies =
+					/* Speed bin 0 */
 					<300000000  403200000  480000000
 					 576000000  652800000  748800000
 					 844800000  940800000 1036800000
 					1132800000 1209600000 1305600000
-					1401600000 1478400000>;
+					1401600000 1478400000>,
+					/* Speed bin 1 */
+					<300000000  403200000  480000000
+					 576000000  652800000  748800000
+					 844800000  940800000 1036800000
+					1132800000 1209600000 1305600000
+					1401600000 1497600000 1593600000>;
 
 				qcom,cpr-ro-scaling-factor =
 					<2857 3056 2828 2952 2699 2796 2447
@@ -451,6 +484,23 @@
 		<  1401600000 0x40340c49 0x00003a3a 0x2 13 >,
 		<  1478400000 0x403c0d4d 0x00003e3e 0x2 14 >;
 
+	qcom,l3-speedbin1-v0 =
+		<   300000000 0x000c000f 0x00002020 0x1 1 >,
+		<   403200000 0x500c0115 0x00002020 0x1 2 >,
+		<   480000000 0x50140219 0x00002020 0x1 3 >,
+		<   576000000 0x5014031e 0x00002020 0x1 4 >,
+		<   652800000 0x401c0422 0x00002020 0x1 5 >,
+		<   748800000 0x401c0527 0x00002020 0x1 6 >,
+		<   844800000 0x4024062c 0x00002323 0x2 7 >,
+		<   940800000 0x40240731 0x00002727 0x2 8 >,
+		<  1036800000 0x40240836 0x00002b2b 0x2 9 >,
+		<  1132800000 0x402c093b 0x00002f2f 0x2 10 >,
+		<  1209600000 0x402c0a3f 0x00003232 0x2 11 >,
+		<  1305600000 0x40340b44 0x00003636 0x2 12 >,
+		<  1401600000 0x40340c49 0x00003a3a 0x2 13 >,
+		<  1497600000 0x403c0d4e 0x00003e3e 0x2 14 >,
+		<  1593600000 0x403c0e53 0x00004242 0x2 15 >;
+
 	qcom,pwrcl-speedbin0-v0 =
 		<   300000000 0x000c000f 0x00002020 0x1 1 >,
 		<   403200000 0x500c0115 0x00002020 0x1 2 >,
@@ -534,6 +584,7 @@
 		<  2707200000 0x40541e8d 0x00007171 0x2 31 >;
 
 	qcom,l3-memacc-level-vc-bin0 = <8 13>;
+	qcom,l3-memacc-level-vc-bin1 = <8 13>;
 
 	qcom,pwrcl-memacc-level-vc-bin0 = <12 16>;
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index fe29336..8105588 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -515,12 +515,17 @@
 		#size-cells = <2>;
 		ranges;
 
-		removed_region1: removed_region1@85700000 {
+		hyp_region: hyp_region@85700000 {
 			no-map;
-			reg = <0 0x85700000 0 0x800000>;
+			reg = <0 0x85700000 0 0x600000>;
 		};
 
-		removed_region2: removed_region2@85fc0000 {
+		xbl_region: xbl_region@85e00000 {
+			no-map;
+			reg = <0 0x85e00000 0 0x100000>;
+		};
+
+		removed_region: removed_region@85fc0000 {
 			no-map;
 			reg = <0 0x85fc0000 0 0x2f40000>;
 		};
@@ -531,64 +536,70 @@
 			reg = <0 0x8ab00000 0 0x500000>;
 		};
 
-		pil_modem_mem: modem_region@8b000000 {
+		pil_ipa_fw_mem: pil_ipa_fw_region@8b000000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x8b000000 0 0x7300000>;
+			reg = <0 0x8b000000 0 0x10000>;
 		};
 
-		pil_video_mem: pil_video_region@92300000 {
+		pil_ipa_gsi_mem: pil_ipa_gsi_region@8b010000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x92300000 0 0x500000>;
+			reg = <0 0x8b010000 0 0x5000>;
 		};
 
-		pil_cdsp_mem: cdsp_regions@92800000 {
+		pil_gpu_mem: pil_gpu_region@8b015000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x92800000 0 0x800000>;
+			reg = <0 0x8b015000 0 0x1000>;
 		};
 
-		pil_adsp_mem: pil_adsp_region@93000000 {
+		pil_adsp_mem: pil_adsp_region@8b100000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x93000000 0 0x1a00000>;
+			reg = <0 0x8b100000 0 0x1a00000>;
 		};
 
-		pil_mba_mem: pil_mba_region@0x94a00000 {
-			compatible = "removed-dma-pool";
-			no-map;
-			reg = <0 0x94a00000 0 0x200000>;
+		wlan_fw_region: wlan_fw_region@8cb00000 {
+			compatible = "shared-dma-pool";
+			reg = <0 0x8cb00000 0 0x100000>;
 		};
 
-		pil_slpi_mem: pil_slpi_region@94c00000 {
+		pil_modem_mem: modem_region@8cc00000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x94c00000 0 0x1400000>;
+			reg = <0 0x8cc00000 0 0x7600000>;
 		};
 
-		pil_ipa_fw_mem: pil_ipa_fw_region@96000000 {
+		pil_video_mem: pil_video_region@94200000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x96000000 0 0x10000>;
+			reg = <0 0x94200000 0 0x500000>;
 		};
 
-		pil_ipa_gsi_mem: pil_ipa_gsi_region@96010000 {
+		pil_cdsp_mem: cdsp_regions@94700000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x96010000 0 0x5000>;
+			reg = <0 0x94700000 0 0x800000>;
 		};
 
-		pil_gpu_mem: pil_gpu_region@96015000 {
+		pil_mba_mem: pil_mba_region@0x94f00000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x96015000 0 0x1000>;
+			reg = <0 0x94f00000 0 0x200000>;
 		};
 
-		pil_spss_mem: spss_region@96100000 {
+		pil_slpi_mem: pil_slpi_region@95100000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x96100000 0 0x100000>;
+			reg = <0 0x95100000 0 0x1400000>;
+		};
+
+
+		pil_spss_mem: spss_region@96500000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x96500000 0 0x100000>;
 		};
 
 		adsp_mem: adsp_region {
@@ -602,7 +613,7 @@
 		qseecom_mem: qseecom_region {
 			compatible = "shared-dma-pool";
 			alloc-ranges = <0 0x00000000 0 0xffffffff>;
-			reusable;
+			no-map;
 			alignment = <0 0x400000>;
 			size = <0 0x1400000>;
 		};
@@ -1980,6 +1991,7 @@
 
 	qcom,msm_fastrpc {
 		compatible = "qcom,msm-fastrpc-compute";
+		qcom,rpc-latency-us = <611>;
 
 		qcom,msm_fastrpc_compute_cb1 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
@@ -3657,6 +3669,8 @@
 		interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
 		qcom,affinity = <1>;
 		#thermal-sensor-cells = <0>;
+		isens_vref-supply = <&pm8998_l1_ao>;
+		isens-vref-settings = <880000 880000 20000>;
 	};
 
 	wil6210: qcom,wil6210 {
@@ -3791,7 +3805,6 @@
 };
 
 #include "pm8998.dtsi"
-#include "pmi8998.dtsi"
 #include "pm8005.dtsi"
 #include "sdm845-regulator.dtsi"
 #include "sdm845-coresight.dtsi"
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 5437417..1b5eac8 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -323,7 +323,7 @@
 CONFIG_THERMAL_TSENS=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
 CONFIG_QTI_VIRTUAL_SENSOR=y
-CONFIG_QTI_REG_COOLING_DEVICE=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
 CONFIG_QTI_QMI_COOLING_DEVICE=y
 CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 6d41d516..e2c6474 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -329,6 +329,7 @@
 CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
 CONFIG_QTI_VIRTUAL_SENSOR=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
 CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index a1c5710..b3130e1 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -334,8 +334,9 @@
 CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
 CONFIG_QTI_VIRTUAL_SENSOR=y
-CONFIG_QTI_REG_COOLING_DEVICE=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
 CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_WCD9XXX_CODEC_CORE=y
@@ -584,6 +585,7 @@
 CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
 CONFIG_SECURITY=y
 CONFIG_HARDENED_USERCOPY=y
+CONFIG_FORTIFY_SOURCE=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
 CONFIG_CRYPTO_CTR=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 0940b48..1394fc2 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -341,8 +341,9 @@
 CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
 CONFIG_QTI_VIRTUAL_SENSOR=y
-CONFIG_QTI_REG_COOLING_DEVICE=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
 CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_WCD9XXX_CODEC_CORE=y
@@ -654,6 +655,7 @@
 CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
 CONFIG_SECURITY=y
 CONFIG_HARDENED_USERCOPY=y
+CONFIG_FORTIFY_SOURCE=y
 CONFIG_SECURITY_SELINUX=y
 CONFIG_SECURITY_SMACK=y
 CONFIG_CRYPTO_CTR=y
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index e4ee2a7..309648f 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -118,9 +118,6 @@
 		return;
 	}
 
-	if (dai->id == BTFM_FM_SLIM_TX)
-		goto out;
-
 	/* Search for dai->id matched port handler */
 	for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) &&
 		(ch->id != BTFM_SLIM_NUM_CODEC_DAIS) &&
@@ -134,7 +131,6 @@
 	}
 
 	btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan);
-out:
 	btfm_slim_hw_deinit(btfmslim);
 }
 
@@ -205,61 +201,6 @@
 	return ret;
 }
 
-static int btfm_slim_dai_hw_free(struct snd_pcm_substream *substream,
-	struct snd_soc_dai *dai)
-{
-	int ret = -EINVAL, i;
-	struct btfmslim *btfmslim = dai->dev->platform_data;
-	struct btfmslim_ch *ch;
-	uint8_t rxport, grp = false, nchan = 1;
-
-	BTFMSLIM_DBG("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
-		dai->id, dai->rate);
-
-	switch (dai->id) {
-	case BTFM_FM_SLIM_TX:
-		grp = true; nchan = 2;
-		ch = btfmslim->tx_chs;
-		rxport = 0;
-		break;
-	case BTFM_BT_SCO_SLIM_TX:
-		ch = btfmslim->tx_chs;
-		rxport = 0;
-		break;
-	case BTFM_BT_SCO_A2DP_SLIM_RX:
-	case BTFM_BT_SPLIT_A2DP_SLIM_RX:
-		ch = btfmslim->rx_chs;
-		rxport = 1;
-		break;
-	case BTFM_SLIM_NUM_CODEC_DAIS:
-	default:
-		BTFMSLIM_ERR("dai->id is invalid:%d", dai->id);
-		goto out;
-	}
-
-	if (dai->id != BTFM_FM_SLIM_TX) {
-		ret = 0;
-		goto out;
-	}
-
-	/* Search for dai->id matched port handler */
-	for (i = 0; (i < BTFM_SLIM_NUM_CODEC_DAIS) &&
-		(ch->id != BTFM_SLIM_NUM_CODEC_DAIS) &&
-		(ch->id != dai->id); ch++, i++)
-		;
-
-	if ((ch->port == BTFM_SLIM_PGD_PORT_LAST) ||
-		(ch->id == BTFM_SLIM_NUM_CODEC_DAIS)) {
-		BTFMSLIM_ERR("ch is invalid!!");
-		goto out;
-	}
-
-	btfm_slim_disable_ch(btfmslim, ch, rxport, grp, nchan);
-
-out:
-	return ret;
-}
-
 /* This function will be called once during boot up */
 static int btfm_slim_dai_set_channel_map(struct snd_soc_dai *dai,
 				unsigned int tx_num, unsigned int *tx_slot,
@@ -405,7 +346,6 @@
 	.shutdown = btfm_slim_dai_shutdown,
 	.hw_params = btfm_slim_dai_hw_params,
 	.prepare = btfm_slim_dai_prepare,
-	.hw_free = btfm_slim_dai_hw_free,
 	.set_channel_map = btfm_slim_dai_set_channel_map,
 	.get_channel_map = btfm_slim_dai_get_channel_map,
 };
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index 0c4e0b3..f0a6d9e 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -82,7 +82,7 @@
 	uint8_t rxport, uint8_t enable)
 {
 	int ret = 0;
-	uint8_t reg_val = 0;
+	uint8_t reg_val = 0, en;
 	uint8_t port_bit = 0;
 	uint16_t reg;
 
@@ -120,6 +120,18 @@
 			BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
 			goto error;
 		}
+	} else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
+		/* SCO Tx */
+		reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
+		reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
+		BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
+				reg_val, reg);
+		ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
+		if (ret) {
+			BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+					ret, reg);
+			goto error;
+		}
 	}
 
 	/* Enable Tx port hw auto recovery for underrun or overrun error */
@@ -137,15 +149,21 @@
 	reg = CHRK_SB_PGD_PORT_TX_CFGN(port_num);
 
 enable_disable_rxport:
-	if (enable) {
-		if (is_fm_port(port_num))
-			reg_val = CHRK_SB_PGD_PORT_ENABLE |
-					CHRK_SB_PGD_PORT_WM_L3;
-		else
-			reg_val = CHRK_SB_PGD_PORT_ENABLE |
-					CHRK_SB_PGD_PORT_WM_LB;
-	} else
-		reg_val = CHRK_SB_PGD_PORT_DISABLE;
+	if (enable)
+		en = CHRK_SB_PGD_PORT_ENABLE;
+	else
+		en = CHRK_SB_PGD_PORT_DISABLE;
+
+	if (is_fm_port(port_num))
+		reg_val = en | CHRK_SB_PGD_PORT_WM_L8;
+	else if (port_num == CHRK_SB_PGD_PORT_TX_SCO)
+		reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_L1 : en;
+	else
+		reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_LB : en;
+
+	if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO)
+		BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x",
+				reg_val, reg);
 
 	ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
 	if (ret)
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.h b/drivers/bluetooth/btfm_slim_wcn3990.h
index 6bbdb6b..b2723ff 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.h
+++ b/drivers/bluetooth/btfm_slim_wcn3990.h
@@ -68,6 +68,7 @@
 #define CHRK_SB_PGD_PORT_WM_L1			(0x1 << 1)
 #define CHRK_SB_PGD_PORT_WM_L2			(0x2 << 1)
 #define CHRK_SB_PGD_PORT_WM_L3			(0x3 << 1)
+#define CHRK_SB_PGD_PORT_WM_L8			(0x8 << 1)
 #define CHRK_SB_PGD_PORT_WM_LB			(0xB << 1)
 
 #define CHRK_SB_PGD_PORT_RX_NUM			16
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 2ede69e..6c7c92a 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -45,7 +45,7 @@
 #include "adsprpc_compat.h"
 #include "adsprpc_shared.h"
 #include <linux/debugfs.h>
-
+#include <linux/pm_qos.h>
 #define TZ_PIL_PROTECT_MEM_SUBSYS_ID 0x0C
 #define TZ_PIL_CLEAR_PROTECT_MEM_SUBSYS_ID 0x0D
 #define TZ_PIL_AUTH_QDSP6_PROC 1
@@ -73,6 +73,7 @@
 #define PERF_KEYS "count:flush:map:copy:glink:getargs:putargs:invalidate:invoke"
 #define FASTRPC_STATIC_HANDLE_LISTENER (3)
 #define FASTRPC_STATIC_HANDLE_MAX (20)
+#define FASTRPC_LATENCY_CTRL_ENB  (1)
 
 #define PERF_END (void)0
 
@@ -235,6 +236,7 @@
 	spinlock_t hlock;
 	struct ion_client *client;
 	struct device *dev;
+	unsigned int latency;
 };
 
 struct fastrpc_mmap {
@@ -288,6 +290,8 @@
 	struct fastrpc_apps *apps;
 	struct fastrpc_perf perf;
 	struct dentry *debugfs_file;
+	struct pm_qos_request pm_qos_req;
+	int qos_request;
 };
 
 static struct fastrpc_apps gfa;
@@ -1923,6 +1927,8 @@
 	struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data;
 
 	if (fl) {
+		if (fl->qos_request && pm_qos_request_active(&fl->pm_qos_req))
+			pm_qos_remove_request(&fl->pm_qos_req);
 		if (fl->debugfs_file != NULL)
 			debugfs_remove(fl->debugfs_file);
 		fastrpc_file_free(fl);
@@ -2227,6 +2233,7 @@
 	if (debugfs_file != NULL)
 		fl->debugfs_file = debugfs_file;
 	memset(&fl->perf, 0, sizeof(fl->perf));
+	fl->qos_request = 0;
 	filp->private_data = fl;
 	spin_lock(&me->hlock);
 	hlist_add_head(&fl->hn, &me->drivers);
@@ -2262,6 +2269,41 @@
 	return err;
 }
 
+static int fastrpc_internal_control(struct fastrpc_file *fl,
+					struct fastrpc_ioctl_control *cp)
+{
+	int err = 0;
+	int latency;
+
+	VERIFY(err, !IS_ERR_OR_NULL(fl) && !IS_ERR_OR_NULL(fl->apps));
+	if (err)
+		goto bail;
+	VERIFY(err, !IS_ERR_OR_NULL(cp));
+	if (err)
+		goto bail;
+
+	switch (cp->req) {
+	case FASTRPC_CONTROL_LATENCY:
+		latency = cp->lp.enable == FASTRPC_LATENCY_CTRL_ENB ?
+			fl->apps->latency : PM_QOS_DEFAULT_VALUE;
+		VERIFY(err, latency != 0);
+		if (err)
+			goto bail;
+		if (!fl->qos_request) {
+			pm_qos_add_request(&fl->pm_qos_req,
+				PM_QOS_CPU_DMA_LATENCY, latency);
+			fl->qos_request = 1;
+		} else
+			pm_qos_update_request(&fl->pm_qos_req, latency);
+		break;
+	default:
+		err = -ENOTTY;
+		break;
+	}
+bail:
+	return err;
+}
+
 static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num,
 				 unsigned long ioctl_param)
 {
@@ -2271,6 +2313,7 @@
 		struct fastrpc_ioctl_munmap munmap;
 		struct fastrpc_ioctl_init_attrs init;
 		struct fastrpc_ioctl_perf perf;
+		struct fastrpc_ioctl_control cp;
 	} p;
 	void *param = (char *)ioctl_param;
 	struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data;
@@ -2370,6 +2413,15 @@
 		if (err)
 			goto bail;
 		break;
+	case FASTRPC_IOCTL_CONTROL:
+		VERIFY(err, 0 == copy_from_user(&p.cp, (void __user *)param,
+				sizeof(p.cp)));
+		if (err)
+			goto bail;
+		VERIFY(err, 0 == (err = fastrpc_internal_control(fl, &p.cp)));
+		if (err)
+			goto bail;
+		break;
 	case FASTRPC_IOCTL_GETINFO:
 	    VERIFY(err, 0 == copy_from_user(&info, param, sizeof(info)));
 		if (err)
@@ -2565,6 +2617,10 @@
 		return 0;
 	}
 
+	err = of_property_read_u32(dev->of_node, "qcom,rpc-latency-us",
+		&me->latency);
+	if (err)
+		me->latency = 0;
 	VERIFY(err, !of_platform_populate(pdev->dev.of_node,
 					  fastrpc_match_table,
 					  NULL, &pdev->dev));
diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c
index 078b4d9..21ad3f9 100644
--- a/drivers/char/adsprpc_compat.c
+++ b/drivers/char/adsprpc_compat.c
@@ -11,7 +11,6 @@
  * GNU General Public License for more details.
  *
  */
-
 #include <linux/compat.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
@@ -38,6 +37,8 @@
 		_IOWR('R', 10, struct compat_fastrpc_ioctl_init_attrs)
 #define COMPAT_FASTRPC_IOCTL_INVOKE_CRC \
 		_IOWR('R', 11, struct compat_fastrpc_ioctl_invoke_crc)
+#define COMPAT_FASTRPC_IOCTL_CONTROL \
+		_IOWR('R', 12, struct compat_fastrpc_ioctl_control)
 
 struct compat_remote_buf {
 	compat_uptr_t pv;	/* buffer pointer */
@@ -108,6 +109,19 @@
 	compat_uptr_t keys;
 };
 
+#define FASTRPC_CONTROL_LATENCY   (1)
+struct compat_fastrpc_ctrl_latency {
+	compat_uint_t enable;	/* latency control enable */
+	compat_uint_t level;	/* level of control */
+};
+
+struct compat_fastrpc_ioctl_control {
+	compat_uint_t req;
+	union {
+		struct compat_fastrpc_ctrl_latency lp;
+	};
+};
+
 static int compat_get_fastrpc_ioctl_invoke(
 			struct compat_fastrpc_ioctl_invoke_crc __user *inv32,
 			struct fastrpc_ioctl_invoke_crc __user **inva,
@@ -236,6 +250,25 @@
 	return err;
 }
 
+static int compat_get_fastrpc_ioctl_control(
+			struct compat_fastrpc_ioctl_control __user *ctrl32,
+			struct fastrpc_ioctl_control __user *ctrl)
+{
+	compat_uptr_t p;
+	int err;
+
+	err = get_user(p, &ctrl32->req);
+	err |= put_user(p, &ctrl->req);
+	if (p == FASTRPC_CONTROL_LATENCY) {
+		err |= get_user(p, &ctrl32->lp.enable);
+		err |= put_user(p, &ctrl->lp.enable);
+		err |= get_user(p, &ctrl32->lp.level);
+		err |= put_user(p, &ctrl->lp.level);
+	}
+
+	return err;
+}
+
 static int compat_get_fastrpc_ioctl_init(
 			struct compat_fastrpc_ioctl_init_attrs __user *init32,
 			struct fastrpc_ioctl_init_attrs __user *init,
@@ -385,6 +418,24 @@
 	case FASTRPC_IOCTL_SETMODE:
 		return filp->f_op->unlocked_ioctl(filp, cmd,
 						(unsigned long)compat_ptr(arg));
+	case COMPAT_FASTRPC_IOCTL_CONTROL:
+	{
+		struct compat_fastrpc_ioctl_control __user *ctrl32;
+		struct fastrpc_ioctl_control __user *ctrl;
+
+		ctrl32 = compat_ptr(arg);
+		VERIFY(err, NULL != (ctrl = compat_alloc_user_space(
+							sizeof(*ctrl))));
+		if (err)
+			return -EFAULT;
+		VERIFY(err, 0 == compat_get_fastrpc_ioctl_control(ctrl32,
+							ctrl));
+		if (err)
+			return err;
+		err = filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_CONTROL,
+							(unsigned long)ctrl);
+		return err;
+	}
 	case COMPAT_FASTRPC_IOCTL_GETPERF:
 	{
 		struct compat_fastrpc_ioctl_perf __user *perf32;
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index 0441451..9f964d2 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -28,6 +28,7 @@
 #define FASTRPC_IOCTL_GETPERF	_IOWR('R', 9, struct fastrpc_ioctl_perf)
 #define FASTRPC_IOCTL_INIT_ATTRS _IOWR('R', 10, struct fastrpc_ioctl_init_attrs)
 #define FASTRPC_IOCTL_INVOKE_CRC _IOWR('R', 11, struct fastrpc_ioctl_invoke_crc)
+#define FASTRPC_IOCTL_CONTROL   _IOWR('R', 12, struct fastrpc_ioctl_control)
 
 #define FASTRPC_GLINK_GUID "fastrpcglink-apps-dsp"
 #define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp"
@@ -205,6 +206,19 @@
 	uintptr_t __user keys;
 };
 
+#define FASTRPC_CONTROL_LATENCY   (1)
+struct fastrpc_ctrl_latency {
+	uint32_t enable;	//!latency control enable
+	uint32_t level;		//!level of control
+};
+
+struct fastrpc_ioctl_control {
+	uint32_t req;
+	union {
+		struct fastrpc_ctrl_latency lp;
+	};
+};
+
 struct smq_null_invoke {
 	uint64_t ctx;			/* invoke caller context */
 	uint32_t handle;	    /* handle to invoke */
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index 4158e65..f93aba1 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -66,6 +66,7 @@
 #define PERFCL_EFUSE_MASK		0x7
 
 #define ENABLE_REG			0x0
+#define ENABLE_OSM			BIT(0)
 #define FREQ_REG			0x110
 #define VOLT_REG			0x114
 #define OVERRIDE_REG			0x118
@@ -2629,7 +2630,7 @@
 	}
 
 	/* Check if OSM has been enabled already by trustzone.  */
-	if (readl_relaxed(l3_clk.vbases[OSM_BASE] + ENABLE_REG)) {
+	if (readl_relaxed(l3_clk.vbases[OSM_BASE] + ENABLE_REG) & ENABLE_OSM) {
 		dev_info(&pdev->dev, "OSM has been initialized and enabled by TZ software\n");
 		osm_tz_enabled = true;
 	}
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index 4f50f9a..1e98e08 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -274,7 +274,7 @@
 	F(414000000, P_CRC_DIV,  1, 0, 0),
 	F(520000000, P_CRC_DIV,  1, 0, 0),
 	F(596000000, P_CRC_DIV,  1, 0, 0),
-	F(670000000, P_CRC_DIV,  1, 0, 0),
+	F(675000000, P_CRC_DIV,  1, 0, 0),
 	F(710000000, P_CRC_DIV,  1, 0, 0),
 	{ }
 };
@@ -554,14 +554,14 @@
 	[GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
 	[GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr,
 	[GPU_CC_PLL_TEST_CLK] = &gpu_cc_pll_test_clk.clkr,
+	[GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
+	[GPU_CC_PLL1] = NULL,
 };
 
 static struct clk_regmap *gpu_cc_gfx_sdm845_clocks[] = {
-	[GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
 	[GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr,
 	[GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr,
 	[GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr,
-	[GPU_CC_PLL1] = NULL,
 };
 
 static const struct qcom_reset_map gpu_cc_sdm845_resets[] = {
@@ -612,8 +612,9 @@
 
 static void gpu_cc_sdm845_fixup_sdm845v2(struct regmap *regmap)
 {
-	clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
 	gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr;
+	clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+
 	gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm845_v2;
 	gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 500000000;
 }
@@ -701,15 +702,6 @@
 		return PTR_ERR(regmap);
 	}
 
-	/* Get MX voltage regulator for GPU PLL graphic clock. */
-	vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx");
-	if (IS_ERR(vdd_mx.regulator[0])) {
-		if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
-			dev_err(&pdev->dev,
-				"Unable to get vdd_mx regulator\n");
-		return PTR_ERR(vdd_mx.regulator[0]);
-	}
-
 	/* GFX voltage regulators for GFX3D  graphic clock. */
 	vdd_gfx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx");
 	if (IS_ERR(vdd_gfx.regulator[0])) {
@@ -779,6 +771,15 @@
 		return PTR_ERR(vdd_cx.regulator[0]);
 	}
 
+	/* Get MX voltage regulator for GPU PLL graphic clock. */
+	vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx");
+	if (IS_ERR(vdd_mx.regulator[0])) {
+		if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
+			dev_err(&pdev->dev,
+				"Unable to get vdd_mx regulator\n");
+		return PTR_ERR(vdd_mx.regulator[0]);
+	}
+
 	ret = gpu_cc_sdm845_fixup(pdev, regmap);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to do GPU CC clock fixup\n");
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 9f126b3..2cf303e 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1792,6 +1792,12 @@
 			mutex_unlock(&hash_access_lock);
 			return err;
 		}
+		if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+			pr_err("Invalid sha_ctxt.diglen %d\n",
+					handle->sha_ctxt.diglen);
+			mutex_unlock(&hash_access_lock);
+			return -EINVAL;
+		}
 		qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
 		memcpy(&qcedev_areq.sha_op_req.digest[0],
 				&handle->sha_ctxt.digest[0],
@@ -1828,6 +1834,12 @@
 			mutex_unlock(&hash_access_lock);
 			return err;
 		}
+		if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+			pr_err("Invalid sha_ctxt.diglen %d\n",
+					handle->sha_ctxt.diglen);
+			mutex_unlock(&hash_access_lock);
+			return -EINVAL;
+		}
 		qcedev_areq.sha_op_req.diglen =	handle->sha_ctxt.diglen;
 		memcpy(&qcedev_areq.sha_op_req.digest[0],
 				&handle->sha_ctxt.digest[0],
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 55c484e..31e5b76 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -13,6 +13,7 @@
 	select SND_SOC_HDMI_CODEC if SND_SOC
 	select SYNC_FILE
 	select HDCP_QSEECOM
+	select MSM_EXT_DISPLAY
 	default y
 	help
 	  DRM/KMS driver for MSM/snapdragon.
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b625996..4015832 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -14,6 +14,8 @@
 	dp/dp_panel.o \
 	dp/dp_link.o \
 	dp/dp_ctrl.o \
+	dp/dp_audio.o \
+	dp/dp_debug.o \
 	dp/dp_display.o \
 	dp/dp_drm.o \
 	dp/dp_hdcp2p2.o \
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
new file mode 100644
index 0000000..c263115
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -0,0 +1,794 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
+
+#include <linux/of_platform.h>
+#include <linux/msm_ext_display.h>
+
+#include <drm/drm_dp_helper.h>
+
+#include "dp_catalog.h"
+#include "dp_audio.h"
+#include "dp_panel.h"
+
+#define HEADER_BYTE_2_BIT	 0
+#define PARITY_BYTE_2_BIT	 8
+#define HEADER_BYTE_1_BIT	16
+#define PARITY_BYTE_1_BIT	24
+#define HEADER_BYTE_3_BIT	16
+#define PARITY_BYTE_3_BIT	24
+
+struct dp_audio_private {
+	struct platform_device *ext_pdev;
+	struct platform_device *pdev;
+	struct dp_catalog_audio *catalog;
+	struct msm_ext_disp_init_data ext_audio_data;
+	struct dp_panel *panel;
+
+	bool ack_enabled;
+	bool session_on;
+	bool engine_on;
+
+	u32 channels;
+
+	struct completion hpd_comp;
+
+	struct dp_audio dp_audio;
+};
+
+static u8 dp_audio_get_g0_value(u8 data)
+{
+	u8 c[4];
+	u8 g[4];
+	u8 ret_data = 0;
+	u8 i;
+
+	for (i = 0; i < 4; i++)
+		c[i] = (data >> i) & 0x01;
+
+	g[0] = c[3];
+	g[1] = c[0] ^ c[3];
+	g[2] = c[1];
+	g[3] = c[2];
+
+	for (i = 0; i < 4; i++)
+		ret_data = ((g[i] & 0x01) << i) | ret_data;
+
+	return ret_data;
+}
+
+static u8 dp_audio_get_g1_value(u8 data)
+{
+	u8 c[4];
+	u8 g[4];
+	u8 ret_data = 0;
+	u8 i;
+
+	for (i = 0; i < 4; i++)
+		c[i] = (data >> i) & 0x01;
+
+	g[0] = c[0] ^ c[3];
+	g[1] = c[0] ^ c[1] ^ c[3];
+	g[2] = c[1] ^ c[2];
+	g[3] = c[2] ^ c[3];
+
+	for (i = 0; i < 4; i++)
+		ret_data = ((g[i] & 0x01) << i) | ret_data;
+
+	return ret_data;
+}
+
+static u8 dp_audio_calculate_parity(u32 data)
+{
+	u8 x0 = 0;
+	u8 x1 = 0;
+	u8 ci = 0;
+	u8 iData = 0;
+	u8 i = 0;
+	u8 parity_byte;
+	u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
+
+	for (i = 0; i < num_byte; i++) {
+		iData = (data >> i*4) & 0xF;
+
+		ci = iData ^ x1;
+		x1 = x0 ^ dp_audio_get_g1_value(ci);
+		x0 = dp_audio_get_g0_value(ci);
+	}
+
+	parity_byte = x1 | (x0 << 4);
+
+	return parity_byte;
+}
+
+static u32 dp_audio_get_header(struct dp_catalog_audio *catalog,
+		enum dp_catalog_audio_sdp_type sdp,
+		enum dp_catalog_audio_header_type header)
+{
+	catalog->sdp_type = sdp;
+	catalog->sdp_header = header;
+	catalog->get_header(catalog);
+
+	return catalog->data;
+}
+
+static void dp_audio_set_header(struct dp_catalog_audio *catalog,
+		u32 data,
+		enum dp_catalog_audio_sdp_type sdp,
+		enum dp_catalog_audio_header_type header)
+{
+	catalog->sdp_type = sdp;
+	catalog->sdp_header = header;
+	catalog->data = data;
+	catalog->set_header(catalog);
+}
+
+static void dp_audio_stream_sdp(struct dp_audio_private *audio)
+{
+	struct dp_catalog_audio *catalog = audio->catalog;
+	u32 value, new_value;
+	u8 parity_byte;
+
+	/* Config header and parity byte 1 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
+
+	new_value = 0x02;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_1_BIT)
+			| (parity_byte << PARITY_BYTE_1_BIT));
+	pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
+
+	/* Config header and parity byte 2 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
+	new_value = value;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_2_BIT)
+			| (parity_byte << PARITY_BYTE_2_BIT));
+	pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
+
+	/* Config header and parity byte 3 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
+
+	new_value = audio->channels - 1;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_3_BIT)
+			| (parity_byte << PARITY_BYTE_3_BIT));
+	pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+		value, parity_byte);
+
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
+{
+	struct dp_catalog_audio *catalog = audio->catalog;
+	u32 value, new_value;
+	u8 parity_byte;
+
+	/* Config header and parity byte 1 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
+
+	new_value = 0x1;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_1_BIT)
+			| (parity_byte << PARITY_BYTE_1_BIT));
+	pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+		value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
+
+	/* Config header and parity byte 2 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
+
+	new_value = 0x17;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_2_BIT)
+			| (parity_byte << PARITY_BYTE_2_BIT));
+	pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
+
+	/* Config header and parity byte 3 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
+
+	new_value = (0x0 | (0x11 << 2));
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_3_BIT)
+			| (parity_byte << PARITY_BYTE_3_BIT));
+	pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
+{
+	struct dp_catalog_audio *catalog = audio->catalog;
+	u32 value, new_value;
+	u8 parity_byte;
+
+	/* Config header and parity byte 1 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
+
+	new_value = 0x84;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_1_BIT)
+			| (parity_byte << PARITY_BYTE_1_BIT));
+	pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
+
+	/* Config header and parity byte 2 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
+
+	new_value = 0x1b;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_2_BIT)
+			| (parity_byte << PARITY_BYTE_2_BIT));
+	pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
+
+	/* Config header and parity byte 3 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
+
+	new_value = (0x0 | (0x11 << 2));
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_3_BIT)
+			| (parity_byte << PARITY_BYTE_3_BIT));
+	pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+			new_value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
+{
+	struct dp_catalog_audio *catalog = audio->catalog;
+	u32 value, new_value;
+	u8 parity_byte;
+
+	/* Config header and parity byte 1 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
+
+	new_value = 0x05;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_1_BIT)
+			| (parity_byte << PARITY_BYTE_1_BIT));
+	pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
+
+	/* Config header and parity byte 2 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
+
+	new_value = 0x0F;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_2_BIT)
+			| (parity_byte << PARITY_BYTE_2_BIT));
+	pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
+
+	/* Config header and parity byte 3 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
+
+	new_value = 0x0;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_3_BIT)
+			| (parity_byte << PARITY_BYTE_3_BIT));
+	pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
+}
+
+static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
+{
+	struct dp_catalog_audio *catalog = audio->catalog;
+	u32 value, new_value;
+	u8 parity_byte;
+
+	/* Config header and parity byte 1 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
+
+	new_value = 0x06;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_1_BIT)
+			| (parity_byte << PARITY_BYTE_1_BIT));
+	pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
+
+	/* Config header and parity byte 2 */
+	value = dp_audio_get_header(catalog,
+			DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
+
+	new_value = 0x0F;
+	parity_byte = dp_audio_calculate_parity(new_value);
+	value |= ((new_value << HEADER_BYTE_2_BIT)
+			| (parity_byte << PARITY_BYTE_2_BIT));
+	pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+			value, parity_byte);
+	dp_audio_set_header(catalog, value,
+		DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
+}
+
+static void dp_audio_setup_sdp(struct dp_audio_private *audio)
+{
+	audio->catalog->config_sdp(audio->catalog);
+
+	dp_audio_stream_sdp(audio);
+	dp_audio_timestamp_sdp(audio);
+	dp_audio_infoframe_sdp(audio);
+	dp_audio_copy_management_sdp(audio);
+	dp_audio_isrc_sdp(audio);
+}
+
+static void dp_audio_setup_acr(struct dp_audio_private *audio)
+{
+	u32 select = 0;
+	struct dp_catalog_audio *catalog = audio->catalog;
+
+	switch (audio->dp_audio.bw_code) {
+	case DP_LINK_BW_1_62:
+		select = 0;
+		break;
+	case DP_LINK_BW_2_7:
+		select = 1;
+		break;
+	case DP_LINK_BW_5_4:
+		select = 2;
+		break;
+	case DP_LINK_RATE_810:
+		select = 3;
+		break;
+	default:
+		pr_debug("Unknown link rate\n");
+		select = 0;
+		break;
+	}
+
+	catalog->data = select;
+	catalog->config_acr(catalog);
+}
+
+static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio)
+{
+	struct dp_catalog_audio *catalog = audio->catalog;
+	u32 safe_to_exit_level = 0;
+
+	switch (audio->dp_audio.lane_count) {
+	case 1:
+		safe_to_exit_level = 14;
+		break;
+	case 2:
+		safe_to_exit_level = 8;
+		break;
+	case 4:
+		safe_to_exit_level = 5;
+		break;
+	default:
+		pr_debug("setting the default safe_to_exit_level = %u\n",
+				safe_to_exit_level);
+		safe_to_exit_level = 14;
+		break;
+	}
+
+	catalog->data = safe_to_exit_level;
+	catalog->safe_to_exit_level(catalog);
+}
+
+static void dp_audio_enable(struct dp_audio_private *audio, bool enable)
+{
+	struct dp_catalog_audio *catalog = audio->catalog;
+
+	catalog->data = enable;
+	catalog->enable(catalog);
+
+	audio->engine_on = enable;
+}
+
+static struct dp_audio_private *get_audio_get_data(struct platform_device *pdev)
+{
+	struct msm_ext_disp_data *ext_data;
+	struct dp_audio *dp_audio;
+
+	if (!pdev) {
+		pr_err("invalid input\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	ext_data = platform_get_drvdata(pdev);
+	if (!ext_data) {
+		pr_err("invalid ext disp data\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	dp_audio = ext_data->intf_data;
+	if (!ext_data) {
+		pr_err("invalid intf data\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return container_of(dp_audio, struct dp_audio_private, dp_audio);
+}
+
+static int dp_audio_info_setup(struct platform_device *pdev,
+	struct msm_ext_disp_audio_setup_params *params)
+{
+	int rc = 0;
+	struct dp_audio_private *audio;
+
+	audio = get_audio_get_data(pdev);
+	if (IS_ERR(audio)) {
+		rc = PTR_ERR(audio);
+		goto end;
+	}
+
+	audio->channels = params->num_of_channels;
+
+	dp_audio_setup_sdp(audio);
+	dp_audio_setup_acr(audio);
+	dp_audio_safe_to_exit_level(audio);
+	dp_audio_enable(audio, true);
+end:
+	return rc;
+}
+
+static int dp_audio_get_edid_blk(struct platform_device *pdev,
+		struct msm_ext_disp_audio_edid_blk *blk)
+{
+	int rc = 0;
+	struct dp_audio_private *audio;
+	struct sde_edid_ctrl *edid;
+
+	audio = get_audio_get_data(pdev);
+	if (IS_ERR(audio)) {
+		rc = PTR_ERR(audio);
+		goto end;
+	}
+
+	if (!audio->panel || !audio->panel->edid_ctrl) {
+		pr_err("invalid panel data\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	edid = audio->panel->edid_ctrl;
+
+	blk->audio_data_blk = edid->audio_data_block;
+	blk->audio_data_blk_size = edid->adb_size;
+
+	blk->spk_alloc_data_blk = edid->spkr_alloc_data_block;
+	blk->spk_alloc_data_blk_size = edid->sadb_size;
+end:
+	return rc;
+}
+
+static int dp_audio_get_cable_status(struct platform_device *pdev, u32 vote)
+{
+	int rc = 0;
+	struct dp_audio_private *audio;
+
+	audio = get_audio_get_data(pdev);
+	if (IS_ERR(audio)) {
+		rc = PTR_ERR(audio);
+		goto end;
+	}
+
+	if (!audio->panel) {
+		pr_err("invalid panel data\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	return audio->session_on;
+end:
+	return rc;
+}
+
+static int dp_audio_get_intf_id(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct dp_audio_private *audio;
+
+	audio = get_audio_get_data(pdev);
+	if (IS_ERR(audio)) {
+		rc = PTR_ERR(audio);
+		goto end;
+	}
+
+	return EXT_DISPLAY_TYPE_DP;
+end:
+	return rc;
+}
+
+static void dp_audio_teardown_done(struct platform_device *pdev)
+{
+	struct dp_audio_private *audio;
+
+	audio = get_audio_get_data(pdev);
+	if (IS_ERR(audio))
+		return;
+
+	if (!audio->panel) {
+		pr_err("invalid panel data\n");
+		return;
+	}
+
+	dp_audio_enable(audio, false);
+
+	complete_all(&audio->hpd_comp);
+
+	pr_debug("audio engine disabled\n");
+}
+
+static int dp_audio_ack_done(struct platform_device *pdev, u32 ack)
+{
+	int rc = 0, ack_hpd;
+	struct dp_audio_private *audio;
+
+	audio = get_audio_get_data(pdev);
+	if (IS_ERR(audio)) {
+		rc = PTR_ERR(audio);
+		goto end;
+	}
+
+	if (ack & AUDIO_ACK_SET_ENABLE) {
+		audio->ack_enabled = ack & AUDIO_ACK_ENABLE ?
+			true : false;
+
+		pr_debug("audio ack feature %s\n",
+			audio->ack_enabled ? "enabled" : "disabled");
+		goto end;
+	}
+
+	if (!audio->ack_enabled)
+		goto end;
+
+	ack_hpd = ack & AUDIO_ACK_CONNECT;
+
+	pr_debug("acknowledging audio (%d)\n", ack_hpd);
+
+	if (!audio->engine_on)
+		complete_all(&audio->hpd_comp);
+end:
+	return rc;
+}
+
+static int dp_audio_init_ext_disp(struct dp_audio_private *audio)
+{
+	int rc = 0;
+	struct device_node *pd = NULL;
+	const char *phandle = "qcom,ext-disp";
+	struct msm_ext_disp_init_data *ext;
+	struct msm_ext_disp_audio_codec_ops *ops;
+
+	ext = &audio->ext_audio_data;
+	ops = &ext->codec_ops;
+
+	ext->type = EXT_DISPLAY_TYPE_DP;
+	ext->pdev = audio->pdev;
+	ext->intf_data = &audio->dp_audio;
+
+	ops->audio_info_setup   = dp_audio_info_setup;
+	ops->get_audio_edid_blk = dp_audio_get_edid_blk;
+	ops->cable_status       = dp_audio_get_cable_status;
+	ops->get_intf_id        = dp_audio_get_intf_id;
+	ops->teardown_done      = dp_audio_teardown_done;
+	ops->acknowledge        = dp_audio_ack_done;
+
+	if (!audio->pdev->dev.of_node) {
+		pr_err("cannot find audio dev.of_node\n");
+		rc = -ENODEV;
+		goto end;
+	}
+
+	pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0);
+	if (!pd) {
+		pr_err("cannot parse %s handle\n", phandle);
+		rc = -ENODEV;
+		goto end;
+	}
+
+	audio->ext_pdev = of_find_device_by_node(pd);
+	if (!audio->ext_pdev) {
+		pr_err("cannot find %s pdev\n", phandle);
+		rc = -ENODEV;
+		goto end;
+	}
+
+	rc = msm_ext_disp_register_intf(audio->ext_pdev, ext);
+	if (rc)
+		pr_err("failed to register disp\n");
+end:
+	if (pd)
+		of_node_put(pd);
+
+	return rc;
+}
+
+static int dp_audio_on(struct dp_audio *dp_audio)
+{
+	int rc = 0;
+	struct dp_audio_private *audio;
+	struct msm_ext_disp_init_data *ext;
+
+	if (!dp_audio) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+
+	ext = &audio->ext_audio_data;
+
+	audio->session_on = true;
+
+	rc = ext->intf_ops.audio_config(audio->ext_pdev,
+			EXT_DISPLAY_TYPE_DP,
+			EXT_DISPLAY_CABLE_CONNECT);
+	if (rc) {
+		pr_err("failed to config audio, err=%d\n", rc);
+		goto end;
+	}
+
+	rc = ext->intf_ops.audio_notify(audio->ext_pdev,
+			EXT_DISPLAY_TYPE_DP,
+			EXT_DISPLAY_CABLE_CONNECT);
+	if (rc) {
+		pr_err("failed to notify audio, err=%d\n", rc);
+		goto end;
+	}
+
+	reinit_completion(&audio->hpd_comp);
+	rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
+	if (!rc) {
+		pr_err("timeout\n");
+		rc = -ETIMEDOUT;
+		goto end;
+	}
+
+	pr_debug("success\n");
+end:
+	return rc;
+}
+
+static int dp_audio_off(struct dp_audio *dp_audio)
+{
+	int rc = 0;
+	struct dp_audio_private *audio;
+	struct msm_ext_disp_init_data *ext;
+
+	if (!dp_audio) {
+		pr_err("invalid input\n");
+		return -EINVAL;
+	}
+
+	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+	ext = &audio->ext_audio_data;
+
+	rc = ext->intf_ops.audio_notify(audio->ext_pdev,
+			EXT_DISPLAY_TYPE_DP,
+			EXT_DISPLAY_CABLE_DISCONNECT);
+	if (rc) {
+		pr_err("failed to notify audio, err=%d\n", rc);
+		goto end;
+	}
+
+	reinit_completion(&audio->hpd_comp);
+	rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5);
+	if (!rc) {
+		pr_err("timeout\n");
+		rc = -ETIMEDOUT;
+		goto end;
+	}
+
+	pr_debug("success\n");
+end:
+	rc = ext->intf_ops.audio_config(audio->ext_pdev,
+			EXT_DISPLAY_TYPE_DP,
+			EXT_DISPLAY_CABLE_DISCONNECT);
+	if (rc)
+		pr_err("failed to config audio, err=%d\n", rc);
+
+	audio->session_on = false;
+	audio->engine_on  = false;
+
+	return rc;
+}
+
+struct dp_audio *dp_audio_get(struct platform_device *pdev,
+			struct dp_panel *panel,
+			struct dp_catalog_audio *catalog)
+{
+	int rc = 0;
+	struct dp_audio_private *audio;
+	struct dp_audio *dp_audio;
+
+	if (!pdev || !panel || !catalog) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
+	if (!audio) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	init_completion(&audio->hpd_comp);
+
+	audio->pdev = pdev;
+	audio->panel = panel;
+	audio->catalog = catalog;
+
+	dp_audio = &audio->dp_audio;
+
+	dp_audio->on  = dp_audio_on;
+	dp_audio->off = dp_audio_off;
+
+	rc = dp_audio_init_ext_disp(audio);
+	if (rc)
+		goto error;
+
+	catalog->init(catalog);
+
+	return dp_audio;
+error:
+	return ERR_PTR(rc);
+}
+
+void dp_audio_put(struct dp_audio *dp_audio)
+{
+	struct dp_audio_private *audio;
+
+	if (!dp_audio)
+		return;
+
+	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
+
+	kzfree(audio);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h
new file mode 100644
index 0000000..d6e6b74
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_audio.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _DP_AUDIO_H_
+#define _DP_AUDIO_H_
+
+#include <linux/platform_device.h>
+
+#include "dp_panel.h"
+#include "dp_catalog.h"
+
+/**
+ * struct dp_audio
+ * @lane_count: number of lanes configured in current session
+ * @bw_code: link rate's bandwidth code for current session
+ */
+struct dp_audio {
+	u32 lane_count;
+	u32 bw_code;
+
+	/**
+	 * on()
+	 *
+	 * Enables the audio by notifying the user module.
+	 *
+	 * @dp_audio: an instance of struct dp_audio.
+	 *
+	 * Returns the error code in case of failure, 0 in success case.
+	 */
+	int (*on)(struct dp_audio *dp_audio);
+
+	/**
+	 * off()
+	 *
+	 * Disables the audio by notifying the user module.
+	 *
+	 * @dp_audio: an instance of struct dp_audio.
+	 *
+	 * Returns the error code in case of failure, 0 in success case.
+	 */
+	int (*off)(struct dp_audio *dp_audio);
+};
+
+/**
+ * dp_audio_get()
+ *
+ * Creates and instance of dp audio.
+ *
+ * @pdev: caller's platform device instance.
+ * @panel: an instance of dp_panel module.
+ * @catalog: an instance of dp_catalog_audio module.
+ *
+ * Returns the error code in case of failure, otherwize
+ * an instance of newly created dp_module.
+ */
+struct dp_audio *dp_audio_get(struct platform_device *pdev,
+			struct dp_panel *panel,
+			struct dp_catalog_audio *catalog);
+
+/**
+ * dp_audio_put()
+ *
+ * Cleans the dp_audio instance.
+ *
+ * @dp_audio: an instance of dp_audio.
+ */
+void dp_audio_put(struct dp_audio *dp_audio);
+#endif /* _DP_AUDIO_H_ */
+
+
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 95a7dc4..ec5b3000 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -59,9 +59,12 @@
 	{0xFF, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
 };
 
+/* audio related catalog functions */
 struct dp_catalog_private {
 	struct device *dev;
 	struct dp_io *io;
+
+	u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
 	struct dp_catalog dp_catalog;
 };
 
@@ -700,40 +703,190 @@
 end:
 	return 0;
 }
- /* audio related catalog functions */
-static int dp_catalog_audio_acr_ctrl(struct dp_catalog_audio *audio)
+
+static void dp_catalog_audio_init(struct dp_catalog_audio *audio)
 {
-	return 0;
+	struct dp_catalog_private *catalog;
+	static u32 sdp_map[][DP_AUDIO_SDP_HEADER_MAX] = {
+		{
+			MMSS_DP_AUDIO_STREAM_0,
+			MMSS_DP_AUDIO_STREAM_1,
+			MMSS_DP_AUDIO_STREAM_1,
+		},
+		{
+			MMSS_DP_AUDIO_TIMESTAMP_0,
+			MMSS_DP_AUDIO_TIMESTAMP_1,
+			MMSS_DP_AUDIO_TIMESTAMP_1,
+		},
+		{
+			MMSS_DP_AUDIO_INFOFRAME_0,
+			MMSS_DP_AUDIO_INFOFRAME_1,
+			MMSS_DP_AUDIO_INFOFRAME_1,
+		},
+		{
+			MMSS_DP_AUDIO_COPYMANAGEMENT_0,
+			MMSS_DP_AUDIO_COPYMANAGEMENT_1,
+			MMSS_DP_AUDIO_COPYMANAGEMENT_1,
+		},
+		{
+			MMSS_DP_AUDIO_ISRC_0,
+			MMSS_DP_AUDIO_ISRC_1,
+			MMSS_DP_AUDIO_ISRC_1,
+		},
+	};
+
+	if (!audio)
+		return;
+
+	dp_catalog_get_priv(audio);
+
+	catalog->audio_map = sdp_map;
 }
 
-static int dp_catalog_audio_stream_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio)
 {
-	return 0;
+	struct dp_catalog_private *catalog;
+	void __iomem *base;
+	u32 sdp_cfg = 0;
+	u32 sdp_cfg2 = 0;
+
+	if (!audio)
+		return;
+
+	dp_catalog_get_priv(audio);
+	base = catalog->io->ctrl_io.base;
+
+	/* AUDIO_TIMESTAMP_SDP_EN */
+	sdp_cfg |= BIT(1);
+	/* AUDIO_STREAM_SDP_EN */
+	sdp_cfg |= BIT(2);
+	/* AUDIO_COPY_MANAGEMENT_SDP_EN */
+	sdp_cfg |= BIT(5);
+	/* AUDIO_ISRC_SDP_EN  */
+	sdp_cfg |= BIT(6);
+	/* AUDIO_INFOFRAME_SDP_EN  */
+	sdp_cfg |= BIT(20);
+
+	pr_debug("sdp_cfg = 0x%x\n", sdp_cfg);
+	dp_write(base + MMSS_DP_SDP_CFG, sdp_cfg);
+
+	sdp_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
+	/* IFRM_REGSRC -> Do not use reg values */
+	sdp_cfg2 &= ~BIT(0);
+	/* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */
+	sdp_cfg2 &= ~BIT(1);
+
+	pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2);
+	dp_write(base + MMSS_DP_SDP_CFG2, sdp_cfg2);
 }
 
-static int dp_catalog_audio_timestamp_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio)
 {
-	return 0;
+	struct dp_catalog_private *catalog;
+	u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
+	void __iomem *base;
+	enum dp_catalog_audio_sdp_type sdp;
+	enum dp_catalog_audio_header_type header;
+
+	if (!audio)
+		return;
+
+	dp_catalog_get_priv(audio);
+
+	base    = catalog->io->ctrl_io.base;
+	sdp_map = catalog->audio_map;
+	sdp     = audio->sdp_type;
+	header  = audio->sdp_header;
+
+	audio->data = dp_read(base + sdp_map[sdp][header]);
 }
 
-static int dp_catalog_audio_infoframe_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio)
 {
-	return 0;
+	struct dp_catalog_private *catalog;
+	u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
+	void __iomem *base;
+	enum dp_catalog_audio_sdp_type sdp;
+	enum dp_catalog_audio_header_type header;
+	u32 data;
+
+	if (!audio)
+		return;
+
+	dp_catalog_get_priv(audio);
+
+	base    = catalog->io->ctrl_io.base;
+	sdp_map = catalog->audio_map;
+	sdp     = audio->sdp_type;
+	header  = audio->sdp_header;
+	data    = audio->data;
+
+	dp_write(base + sdp_map[sdp][header], data);
 }
 
-static int dp_catalog_audio_copy_mgmt_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio)
 {
-	return 0;
+	struct dp_catalog_private *catalog;
+	void __iomem *base;
+	u32 acr_ctrl, select;
+
+	dp_catalog_get_priv(audio);
+
+	select = audio->data;
+	base   = catalog->io->ctrl_io.base;
+
+	acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14);
+
+	pr_debug("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl);
+
+	dp_write(base + MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
 }
 
-static int dp_catalog_audio_isrc_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_safe_to_exit_level(struct dp_catalog_audio *audio)
 {
-	return 0;
+	struct dp_catalog_private *catalog;
+	void __iomem *base;
+	u32 mainlink_levels, safe_to_exit_level;
+
+	dp_catalog_get_priv(audio);
+
+	base   = catalog->io->ctrl_io.base;
+	safe_to_exit_level = audio->data;
+
+	mainlink_levels = dp_read(base + DP_MAINLINK_LEVELS);
+	mainlink_levels &= 0xFE0;
+	mainlink_levels |= safe_to_exit_level;
+
+	pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
+			mainlink_levels, safe_to_exit_level);
+
+	dp_write(base + DP_MAINLINK_LEVELS, mainlink_levels);
 }
 
-static int dp_catalog_audio_setup_sdp(struct dp_catalog_audio *audio)
+static void dp_catalog_audio_enable(struct dp_catalog_audio *audio)
 {
-	return 0;
+	struct dp_catalog_private *catalog;
+	void __iomem *base;
+	bool enable;
+	u32 audio_ctrl;
+
+	dp_catalog_get_priv(audio);
+
+	base   = catalog->io->ctrl_io.base;
+	enable = !!audio->data;
+
+	audio_ctrl = dp_read(base + MMSS_DP_AUDIO_CFG);
+
+	if (enable)
+		audio_ctrl |= BIT(0);
+	else
+		audio_ctrl &= ~BIT(0);
+
+	pr_debug("dp_audio_cfg = 0x%x\n", audio_ctrl);
+	dp_write(base + MMSS_DP_AUDIO_CFG, audio_ctrl);
+
+	/* make sure audio engine is disabled */
+	wmb();
 }
 
 struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
@@ -771,13 +924,13 @@
 		.read_hdcp_status     = dp_catalog_ctrl_read_hdcp_status,
 	};
 	struct dp_catalog_audio audio = {
-		.acr_ctrl      = dp_catalog_audio_acr_ctrl,
-		.stream_sdp    = dp_catalog_audio_stream_sdp,
-		.timestamp_sdp = dp_catalog_audio_timestamp_sdp,
-		.infoframe_sdp = dp_catalog_audio_infoframe_sdp,
-		.copy_mgmt_sdp = dp_catalog_audio_copy_mgmt_sdp,
-		.isrc_sdp      = dp_catalog_audio_isrc_sdp,
-		.setup_sdp     = dp_catalog_audio_setup_sdp,
+		.init       = dp_catalog_audio_init,
+		.config_acr = dp_catalog_audio_config_acr,
+		.enable     = dp_catalog_audio_enable,
+		.config_sdp = dp_catalog_audio_config_sdp,
+		.set_header = dp_catalog_audio_set_header,
+		.get_header = dp_catalog_audio_get_header,
+		.safe_to_exit_level = dp_catalog_audio_safe_to_exit_level,
 	};
 	struct dp_catalog_panel panel = {
 		.timing_cfg = dp_catalog_panel_timing_cfg,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 7fde025..06b7b08 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -77,16 +77,34 @@
 	u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
 };
 
+enum dp_catalog_audio_sdp_type {
+	DP_AUDIO_SDP_STREAM,
+	DP_AUDIO_SDP_TIMESTAMP,
+	DP_AUDIO_SDP_INFOFRAME,
+	DP_AUDIO_SDP_COPYMANAGEMENT,
+	DP_AUDIO_SDP_ISRC,
+	DP_AUDIO_SDP_MAX,
+};
+
+enum dp_catalog_audio_header_type {
+	DP_AUDIO_SDP_HEADER_1,
+	DP_AUDIO_SDP_HEADER_2,
+	DP_AUDIO_SDP_HEADER_3,
+	DP_AUDIO_SDP_HEADER_MAX,
+};
+
 struct dp_catalog_audio {
+	enum dp_catalog_audio_sdp_type sdp_type;
+	enum dp_catalog_audio_header_type sdp_header;
 	u32 data;
 
-	int (*acr_ctrl)(struct dp_catalog_audio *audio);
-	int (*stream_sdp)(struct dp_catalog_audio *audio);
-	int (*timestamp_sdp)(struct dp_catalog_audio *audio);
-	int (*infoframe_sdp)(struct dp_catalog_audio *audio);
-	int (*copy_mgmt_sdp)(struct dp_catalog_audio *audio);
-	int (*isrc_sdp)(struct dp_catalog_audio *audio);
-	int (*setup_sdp)(struct dp_catalog_audio *audio);
+	void (*init)(struct dp_catalog_audio *audio);
+	void (*enable)(struct dp_catalog_audio *audio);
+	void (*config_acr)(struct dp_catalog_audio *audio);
+	void (*config_sdp)(struct dp_catalog_audio *audio);
+	void (*set_header)(struct dp_catalog_audio *audio);
+	void (*get_header)(struct dp_catalog_audio *audio);
+	void (*safe_to_exit_level)(struct dp_catalog_audio *audio);
 };
 
 struct dp_catalog_panel {
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
new file mode 100644
index 0000000..82e34df
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
+
+#include <linux/debugfs.h>
+
+#include "dp_parser.h"
+#include "dp_power.h"
+#include "dp_catalog.h"
+#include "dp_aux.h"
+#include "dp_ctrl.h"
+#include "dp_debug.h"
+#include "drm_connector.h"
+#include "dp_display.h"
+
+#define DEBUG_NAME "drm_dp"
+
+struct dp_debug_private {
+	struct dentry *root;
+
+	struct dp_usbpd *usbpd;
+	struct dp_link *link;
+	struct dp_panel *panel;
+	struct drm_connector **connector;
+	struct device *dev;
+
+	struct dp_debug dp_debug;
+};
+
+static ssize_t dp_debug_write_hpd(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	size_t len = 0;
+	int hpd;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	/* Leave room for termination char */
+	len = min_t(size_t, count, SZ_8 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		goto end;
+
+	buf[len] = '\0';
+
+	if (kstrtoint(buf, 10, &hpd) != 0)
+		goto end;
+
+	debug->usbpd->connect(debug->usbpd, hpd);
+end:
+	return -len;
+}
+
+static ssize_t dp_debug_write_edid_modes(struct file *file,
+		const char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_32];
+	size_t len = 0;
+	int hdisplay = 0, vdisplay = 0, vrefresh = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		goto end;
+
+	/* Leave room for termination char */
+	len = min_t(size_t, count, SZ_32 - 1);
+	if (copy_from_user(buf, user_buff, len))
+		goto clear;
+
+	buf[len] = '\0';
+
+	if (sscanf(buf, "%d %d %d", &hdisplay, &vdisplay, &vrefresh) != 3)
+		goto clear;
+
+	if (!hdisplay || !vdisplay || !vrefresh)
+		goto clear;
+
+	debug->dp_debug.debug_en = true;
+	debug->dp_debug.hdisplay = hdisplay;
+	debug->dp_debug.vdisplay = vdisplay;
+	debug->dp_debug.vrefresh = vrefresh;
+	goto end;
+clear:
+	pr_debug("clearing debug modes\n");
+	debug->dp_debug.debug_en = false;
+end:
+	return len;
+}
+
+static ssize_t dp_debug_read_connected(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	u32 len = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	len += snprintf(buf, SZ_8, "%d\n", debug->usbpd->hpd_high);
+
+	if (copy_to_user(user_buff, buf, len))
+		return -EFAULT;
+
+	*ppos += len;
+	return len;
+}
+
+static ssize_t dp_debug_read_edid_modes(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char *buf;
+	u32 len = 0;
+	int rc = 0;
+	struct drm_connector *connector;
+	struct drm_display_mode *mode;
+
+	if (!debug) {
+		pr_err("invalid data\n");
+		rc = -ENODEV;
+		goto error;
+	}
+
+	connector = *debug->connector;
+
+	if (!connector) {
+		pr_err("connector is NULL\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (*ppos)
+		goto error;
+
+	buf = kzalloc(SZ_4K, GFP_KERNEL);
+	if (!buf) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	list_for_each_entry(mode, &connector->modes, head) {
+		len += snprintf(buf + len, SZ_4K - len,
+		"%s %d %d %d %d %d %d %d %d %d 0x%x\n",
+		mode->name, mode->vrefresh, mode->hdisplay,
+		mode->hsync_start, mode->hsync_end, mode->htotal,
+		mode->vdisplay, mode->vsync_start, mode->vsync_end,
+		mode->vtotal, mode->flags);
+	}
+
+	if (copy_to_user(user_buff, buf, len)) {
+		kfree(buf);
+		rc = -EFAULT;
+		goto error;
+	}
+
+	*ppos += len;
+	kfree(buf);
+
+	return len;
+error:
+	return rc;
+}
+
+static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len)
+{
+	if (rc >= *max_size) {
+		pr_err("buffer overflow\n");
+		return -EINVAL;
+	}
+	*len += rc;
+	*max_size = SZ_4K - *len;
+
+	return 0;
+}
+
+static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
+		size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char *buf;
+	u32 len = 0, rc = 0;
+	u64 lclk = 0;
+	u32 max_size = SZ_4K;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	buf = kzalloc(SZ_4K, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\tdp_panel\n\t\tmax_pclk_khz = %d\n",
+		debug->panel->max_pclk_khz);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\tdrm_dp_link\n\t\trate = %u\n",
+		debug->panel->link_info.rate);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tnum_lanes = %u\n",
+		debug->panel->link_info.num_lanes);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tcapabilities = %lu\n",
+		debug->panel->link_info.capabilities);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\tdp_panel_info:\n\t\tactive = %dx%d\n",
+		debug->panel->pinfo.h_active,
+		debug->panel->pinfo.v_active);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tback_porch = %dx%d\n",
+		debug->panel->pinfo.h_back_porch,
+		debug->panel->pinfo.v_back_porch);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tfront_porch = %dx%d\n",
+		debug->panel->pinfo.h_front_porch,
+		debug->panel->pinfo.v_front_porch);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tsync_width = %dx%d\n",
+		debug->panel->pinfo.h_sync_width,
+		debug->panel->pinfo.v_sync_width);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tactive_low = %dx%d\n",
+		debug->panel->pinfo.h_active_low,
+		debug->panel->pinfo.v_active_low);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\th_skew = %d\n",
+		debug->panel->pinfo.h_skew);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\trefresh rate = %d\n",
+		debug->panel->pinfo.refresh_rate);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tpixel clock khz = %d\n",
+		debug->panel->pinfo.pixel_clk_khz);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tbpp = %d\n",
+		debug->panel->pinfo.bpp);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	/* Link Information */
+	rc = snprintf(buf + len, max_size,
+		"\tdp_link:\n\t\ttest_requested = %d\n",
+		debug->link->test_requested);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tlane_count = %d\n", debug->link->lane_count);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tbw_code = %d\n", debug->link->bw_code);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	lclk = drm_dp_bw_code_to_link_rate(debug->link->bw_code) * 1000;
+	rc = snprintf(buf + len, max_size,
+		"\t\tlclk = %lld\n", lclk);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tv_level = %d\n", debug->link->v_level);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	rc = snprintf(buf + len, max_size,
+		"\t\tp_level = %d\n", debug->link->p_level);
+	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
+		goto error;
+
+	if (copy_to_user(user_buff, buf, len))
+		goto error;
+
+	*ppos += len;
+
+	kfree(buf);
+	return len;
+error:
+	kfree(buf);
+	return -EINVAL;
+}
+
+static const struct file_operations dp_debug_fops = {
+	.open = simple_open,
+	.read = dp_debug_read_info,
+};
+
+static const struct file_operations edid_modes_fops = {
+	.open = simple_open,
+	.read = dp_debug_read_edid_modes,
+	.write = dp_debug_write_edid_modes,
+};
+
+static const struct file_operations hpd_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_hpd,
+};
+
+static const struct file_operations connected_fops = {
+	.open = simple_open,
+	.read = dp_debug_read_connected,
+};
+
+static int dp_debug_init(struct dp_debug *dp_debug)
+{
+	int rc = 0;
+	struct dp_debug_private *debug = container_of(dp_debug,
+		struct dp_debug_private, dp_debug);
+	struct dentry *dir, *file, *edid_modes;
+	struct dentry *hpd, *connected;
+	struct dentry *root = debug->root;
+
+	dir = debugfs_create_dir(DEBUG_NAME, NULL);
+	if (IS_ERR_OR_NULL(dir)) {
+		rc = PTR_ERR(dir);
+		pr_err("[%s] debugfs create dir failed, rc = %d\n",
+		       DEBUG_NAME, rc);
+		goto error;
+	}
+
+	file = debugfs_create_file("dp_debug", 0444, dir,
+				debug, &dp_debug_fops);
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs create file failed, rc=%d\n",
+		       DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	edid_modes = debugfs_create_file("edid_modes", 0644, dir,
+					debug, &edid_modes_fops);
+	if (IS_ERR_OR_NULL(edid_modes)) {
+		rc = PTR_ERR(edid_modes);
+		pr_err("[%s] debugfs create edid_modes failed, rc=%d\n",
+		       DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	hpd = debugfs_create_file("hpd", 0644, dir,
+					debug, &hpd_fops);
+	if (IS_ERR_OR_NULL(hpd)) {
+		rc = PTR_ERR(hpd);
+		pr_err("[%s] debugfs hpd failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	connected = debugfs_create_file("connected", 0444, dir,
+					debug, &connected_fops);
+	if (IS_ERR_OR_NULL(connected)) {
+		rc = PTR_ERR(connected);
+		pr_err("[%s] debugfs connected failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	root = dir;
+	return rc;
+error_remove_dir:
+	debugfs_remove(dir);
+error:
+	return rc;
+}
+
+struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
+			struct dp_usbpd *usbpd, struct dp_link *link,
+			struct drm_connector **connector)
+{
+	int rc = 0;
+	struct dp_debug_private *debug;
+	struct dp_debug *dp_debug;
+
+	if (!dev || !panel || !usbpd || !link) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL);
+	if (!debug) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	debug->dp_debug.debug_en = false;
+	debug->usbpd = usbpd;
+	debug->link = link;
+	debug->panel = panel;
+	debug->dev = dev;
+	debug->connector = connector;
+
+	dp_debug = &debug->dp_debug;
+	dp_debug->vdisplay = 0;
+	dp_debug->hdisplay = 0;
+	dp_debug->vrefresh = 0;
+
+	dp_debug_init(dp_debug);
+
+	return dp_debug;
+error:
+	return ERR_PTR(rc);
+}
+
+static int dp_debug_deinit(struct dp_debug *dp_debug)
+{
+	struct dp_debug_private *debug;
+
+	if (!dp_debug)
+		return -EINVAL;
+
+	debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
+
+	debugfs_remove(debug->root);
+
+	return 0;
+}
+
+void dp_debug_put(struct dp_debug *dp_debug)
+{
+	struct dp_debug_private *debug;
+
+	if (!dp_debug)
+		return;
+
+	debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
+
+	dp_debug_deinit(dp_debug);
+
+	kzfree(debug);
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h
new file mode 100644
index 0000000..7fd5330
--- /dev/null
+++ b/drivers/gpu/drm/msm/dp/dp_debug.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _DP_DEBUG_H_
+#define _DP_DEBUG_H_
+
+#include "dp_panel.h"
+#include "dp_link.h"
+#include "dp_usbpd.h"
+
+/**
+ * struct dp_debug
+ * @debug_en: specifies whether debug mode enabled
+ * @vdisplay: used to filter out vdisplay value
+ * @hdisplay: used to filter out hdisplay value
+ * @vrefresh: used to filter out vrefresh value
+ */
+struct dp_debug {
+	bool debug_en;
+	int vdisplay;
+	int hdisplay;
+	int vrefresh;
+};
+
+/**
+ * dp_debug_get() - configure and get the DisplayPlot debug module data
+ *
+ * @dev: device instance of the caller
+ * @panel: instance of panel module
+ * @usbpd: instance of usbpd module
+ * @link: instance of link module
+ * @connector: double pointer to display connector
+ * return: pointer to allocated debug module data
+ *
+ * This function sets up the debug module and provides a way
+ * for debugfs input to be communicated with existing modules
+ */
+struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
+			struct dp_usbpd *usbpd, struct dp_link *link,
+			struct drm_connector **connector);
+/**
+ * dp_debug_put()
+ *
+ * Cleans up dp_debug instance
+ *
+ * @dp_debug: instance of dp_debug
+ */
+void dp_debug_put(struct dp_debug *dp_debug);
+#endif /* _DP_DEBUG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index b4dafe4..4dcf3b4 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -31,8 +31,10 @@
 #include "dp_link.h"
 #include "dp_panel.h"
 #include "dp_ctrl.h"
+#include "dp_audio.h"
 #include "dp_display.h"
 #include "sde_hdcp.h"
+#include "dp_debug.h"
 
 static struct dp_display *g_dp_display;
 
@@ -59,6 +61,7 @@
 	bool core_initialized;
 	bool power_on;
 	bool hpd_irq_on;
+	bool audio_supported;
 
 	struct platform_device *pdev;
 	struct dentry *root;
@@ -72,6 +75,9 @@
 	struct dp_link    *link;
 	struct dp_panel   *panel;
 	struct dp_ctrl    *ctrl;
+	struct dp_audio   *audio;
+	struct dp_debug   *debug;
+
 	struct dp_hdcp hdcp;
 
 	struct dp_usbpd_cb usbpd_cb;
@@ -120,80 +126,6 @@
 	return IRQ_HANDLED;
 }
 
-static ssize_t debugfs_dp_info_read(struct file *file, char __user *buff,
-		size_t count, loff_t *ppos)
-{
-	struct dp_display_private *dp = file->private_data;
-	char *buf;
-	u32 len = 0;
-
-	if (!dp)
-		return -ENODEV;
-
-	if (*ppos)
-		return 0;
-
-	buf = kzalloc(SZ_4K, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	len += snprintf(buf + len, (SZ_4K - len), "name = %s\n", dp->name);
-	len += snprintf(buf + len, (SZ_4K - len),
-			"\tResolution = %dx%d\n",
-			dp->panel->pinfo.h_active,
-			dp->panel->pinfo.v_active);
-
-	if (copy_to_user(buff, buf, len)) {
-		kfree(buf);
-		return -EFAULT;
-	}
-
-	*ppos += len;
-
-	kfree(buf);
-	return len;
-}
-
-static const struct file_operations dp_debug_fops = {
-	.open = simple_open,
-	.read = debugfs_dp_info_read,
-};
-
-static int dp_display_debugfs_init(struct dp_display_private *dp)
-{
-	int rc = 0;
-	struct dentry *dir, *file;
-
-	dir = debugfs_create_dir(dp->name, NULL);
-	if (IS_ERR_OR_NULL(dir)) {
-		rc = PTR_ERR(dir);
-		pr_err("[%s] debugfs create dir failed, rc = %d\n",
-		       dp->name, rc);
-		goto error;
-	}
-
-	file = debugfs_create_file("dp_debug", 0444, dir, dp, &dp_debug_fops);
-	if (IS_ERR_OR_NULL(file)) {
-		rc = PTR_ERR(file);
-		pr_err("[%s] debugfs create file failed, rc=%d\n",
-		       dp->name, rc);
-		goto error_remove_dir;
-	}
-
-	dp->root = dir;
-	return rc;
-error_remove_dir:
-	debugfs_remove(dir);
-error:
-	return rc;
-}
-
-static int dp_display_debugfs_deinit(struct dp_display_private *dp)
-{
-	debugfs_remove(dp->root);
-	return 0;
-}
-
 static void dp_display_hdcp_cb_work(struct work_struct *work)
 {
 	struct dp_display_private *dp;
@@ -429,12 +361,6 @@
 	dp->dp_display.drm_dev = drm;
 	priv = drm->dev_private;
 
-	rc = dp_display_debugfs_init(dp);
-	if (rc) {
-		pr_err("[%s]Debugfs init failed, rc=%d\n", dp->name, rc);
-		goto end;
-	}
-
 	rc = dp->parser->parse(dp->parser);
 	if (rc) {
 		pr_err("device tree parsing failed\n");
@@ -488,7 +414,6 @@
 	(void)dp->power->power_client_deinit(dp->power);
 	(void)dp->panel->sde_edid_deregister(dp->panel);
 	(void)dp->aux->drm_aux_deregister(dp->aux);
-	(void)dp_display_debugfs_deinit(dp);
 	dp_display_deinitialize_hdcp(dp);
 }
 
@@ -501,11 +426,16 @@
 {
 	int rc = 0;
 	u32 max_pclk_from_edid = 0;
+	struct edid *edid;
 
 	rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
 	if (rc)
 		return rc;
 
+	edid = dp->panel->edid_ctrl->edid;
+
+	dp->audio_supported = drm_detect_monitor_audio(edid);
+
 	max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);
 
 	dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
@@ -565,6 +495,9 @@
 		dp->hdcp.ops->off(dp->hdcp.data);
 	}
 
+	if (dp->audio_supported)
+		dp->audio->off(dp->audio);
+
 	dp->dp_display.is_connected = false;
 	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
 
@@ -620,6 +553,9 @@
 	/* cancel any pending request */
 	dp->ctrl->abort(dp->ctrl);
 
+	if (dp->audio_supported)
+		dp->audio->off(dp->audio);
+
 	dp->dp_display.is_connected = false;
 	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
 
@@ -760,6 +696,20 @@
 		pr_err("failed to initialize ctrl, rc = %d\n", rc);
 		goto err;
 	}
+
+	dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio);
+	if (IS_ERR(dp->audio)) {
+		rc = PTR_ERR(dp->audio);
+		pr_err("failed to initialize audio, rc = %d\n", rc);
+	}
+
+	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
+				dp->link, &dp->dp_display.connector);
+	if (IS_ERR(dp->debug)) {
+		rc = PTR_ERR(dp->debug);
+		pr_err("failed to initialize debug, rc = %d\n", rc);
+		goto err;
+	}
 err:
 	return rc;
 }
@@ -821,6 +771,12 @@
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+	if (dp->audio_supported) {
+		dp->audio->bw_code = dp->link->bw_code;
+		dp->audio->lane_count = dp->link->lane_count;
+		dp->audio->on(dp->audio);
+	}
+
 	complete_all(&dp->notification_comp);
 
 	dp_display_update_hdcp_info(dp);
@@ -916,6 +872,20 @@
 	return 0;
 }
 
+static struct dp_debug *dp_get_debug(struct dp_display *dp_display)
+{
+	struct dp_display_private *dp;
+
+	if (!dp_display) {
+		pr_err("invalid input\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+	return dp->debug;
+}
+
 static int dp_display_unprepare(struct dp_display *dp)
 {
 	return 0;
@@ -979,6 +949,7 @@
 	g_dp_display->prepare       = dp_display_prepare;
 	g_dp_display->unprepare     = dp_display_unprepare;
 	g_dp_display->request_irq   = dp_request_irq;
+	g_dp_display->get_debug     = dp_get_debug;
 
 	rc = component_add(&pdev->dev, &dp_display_comp_ops);
 	if (rc)
@@ -1010,6 +981,7 @@
 
 static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
 {
+	dp_audio_put(dp->audio);
 	dp_ctrl_put(dp->ctrl);
 	dp_link_put(dp->link);
 	dp_panel_put(dp->panel);
@@ -1018,6 +990,7 @@
 	dp_catalog_put(dp->catalog);
 	dp_parser_put(dp->parser);
 	dp_usbpd_put(dp->usbpd);
+	dp_debug_put(dp->debug);
 }
 
 static int dp_display_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 3caa277..5943629 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -45,6 +45,7 @@
 	int (*prepare)(struct dp_display *dp_display);
 	int (*unprepare)(struct dp_display *dp_display);
 	int (*request_irq)(struct dp_display *dp_display);
+	struct dp_debug *(*get_debug)(struct dp_display *dp_display);
 };
 
 int dp_display_get_num_of_displays(void);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index c388048..802f295 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -22,6 +22,7 @@
 #include "msm_kms.h"
 #include "sde_connector.h"
 #include "dp_drm.h"
+#include "dp_debug.h"
 
 #define to_dp_bridge(x)     container_of((x), struct dp_bridge, base)
 
@@ -456,6 +457,7 @@
 		void *display)
 {
 	struct dp_display *dp_disp;
+	struct dp_debug *debug;
 
 	if (!mode || !display) {
 		pr_err("invalid params\n");
@@ -463,9 +465,20 @@
 	}
 
 	dp_disp = display;
+	debug = dp_disp->get_debug(dp_disp);
 
-	if (mode->clock > dp_disp->max_pclk_khz)
-		return MODE_BAD;
-	else
-		return MODE_OK;
+	if (debug->debug_en) {
+		if (mode->hdisplay == debug->hdisplay &&
+				mode->vdisplay == debug->vdisplay &&
+				mode->vrefresh == debug->vrefresh &&
+				mode->clock <= dp_disp->max_pclk_khz)
+			return MODE_OK;
+		else
+			return MODE_ERROR;
+	} else {
+		if (mode->clock > dp_disp->max_pclk_khz)
+			return MODE_BAD;
+		else
+			return MODE_OK;
+	}
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index 7bc1433..df43267 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -73,6 +73,8 @@
 	struct dp_usbpd dp_usbpd;
 	enum dp_usbpd_alt_mode alt_mode;
 	u32 dp_usbpd_config;
+
+	bool forced_disconnect;
 };
 
 static const char *dp_usbpd_pin_name(u8 pin)
@@ -342,6 +344,9 @@
 		dp_usbpd_send_event(pd, DP_USBPD_EVT_STATUS);
 		break;
 	case USBPD_SVDM_ATTENTION:
+		if (pd->forced_disconnect)
+			break;
+
 		pd->vdo = *vdos;
 		dp_usbpd_get_status(pd);
 
@@ -378,12 +383,38 @@
 	}
 }
 
+static int dp_usbpd_connect(struct dp_usbpd *dp_usbpd, bool hpd)
+{
+	int rc = 0;
+	struct dp_usbpd_private *pd;
+
+	if (!dp_usbpd) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
+
+	dp_usbpd->hpd_high = hpd;
+	pd->forced_disconnect = !hpd;
+
+	if (hpd)
+		pd->dp_cb->configure(pd->dev);
+	else
+		pd->dp_cb->disconnect(pd->dev);
+
+error:
+	return rc;
+}
+
 struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb)
 {
 	int rc = 0;
 	const char *pd_phandle = "qcom,dp-usbpd-detection";
 	struct usbpd *pd = NULL;
 	struct dp_usbpd_private *usbpd;
+	struct dp_usbpd *dp_usbpd;
 	struct usbpd_svid_handler svid_handler = {
 		.svid		= USB_C_DP_SID,
 		.vdm_received	= NULL,
@@ -423,7 +454,11 @@
 		kfree(usbpd);
 		goto error;
 	}
-	return &usbpd->dp_usbpd;
+
+	dp_usbpd = &usbpd->dp_usbpd;
+	dp_usbpd->connect = dp_usbpd_connect;
+
+	return dp_usbpd;
 error:
 	return ERR_PTR(rc);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h
index 67f380a..2682e98 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.h
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h
@@ -48,6 +48,8 @@
  * @hpd_high: Hot Plug Detect signal is high.
  * @hpd_irq: Change in the status since last message
  * @alt_mode_cfg_done: bool to specify alt mode status
+ * @debug_en: bool to specify debug mode
+ * @connect: simulate disconnect or connect for debug mode
  */
 struct dp_usbpd {
 	enum dp_usbpd_port port;
@@ -60,6 +62,9 @@
 	bool hpd_high;
 	bool hpd_irq;
 	bool alt_mode_cfg_done;
+	bool debug_en;
+
+	int (*connect)(struct dp_usbpd *dp_usbpd, bool hpd);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 5e76ce7..e9dabb1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -108,14 +108,15 @@
  * @ctrl:        Pointer to DSI controller hw object.
  * @version:     DSI controller version.
  * @index:       DSI controller instance ID.
+ * @phy_isolation_enabled:       DSI controller works isolated from phy.
  *
  * This function setups the catalog information in the dsi_ctrl_hw object.
  *
  * return: error code for failure and 0 for success.
  */
 int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
-			   enum dsi_ctrl_version version,
-			   u32 index)
+		   enum dsi_ctrl_version version, u32 index,
+		   bool phy_isolation_enabled)
 {
 	int rc = 0;
 
@@ -135,8 +136,11 @@
 
 	switch (version) {
 	case DSI_CTRL_VERSION_1_4:
+		dsi_catalog_cmn_init(ctrl, version);
+		break;
 	case DSI_CTRL_VERSION_2_0:
 	case DSI_CTRL_VERSION_2_2:
+		ctrl->phy_isolation_enabled = phy_isolation_enabled;
 		dsi_catalog_cmn_init(ctrl, version);
 		break;
 	default:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index e8a6ab4..e8d594c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -23,14 +23,15 @@
  * @ctrl:        Pointer to DSI controller hw object.
  * @version:     DSI controller version.
  * @index:       DSI controller instance ID.
+ * @phy_isolation_enabled:       DSI controller works isolated from phy.
  *
  * This function setups the catalog information in the dsi_ctrl_hw object.
  *
  * return: error code for failure and 0 for success.
  */
 int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
-			   enum dsi_ctrl_version version,
-			   u32 index);
+		   enum dsi_ctrl_version version, u32 index,
+		   bool phy_isolation_enabled);
 
 /**
  * dsi_catalog_phy_setup() - return catalog info for dsi phy hardware
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 96136ba..dcde566 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1262,13 +1262,41 @@
 	return 0;
 }
 
+static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl,
+				  struct device_node *of_node)
+{
+	u32 index = 0;
+	int rc = 0;
+
+	if (!dsi_ctrl || !of_node) {
+		pr_err("invalid dsi_ctrl:%d or of_node:%d\n",
+					dsi_ctrl != NULL, of_node != NULL);
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(of_node, "cell-index", &index);
+	if (rc) {
+		pr_debug("cell index not set, default to 0\n");
+		index = 0;
+	}
+
+	dsi_ctrl->cell_index = index;
+	dsi_ctrl->name = of_get_property(of_node, "label", NULL);
+	if (!dsi_ctrl->name)
+		dsi_ctrl->name = DSI_CTRL_DEFAULT_LABEL;
+
+	dsi_ctrl->phy_isolation_enabled = of_property_read_bool(of_node,
+				    "qcom,dsi-phy-isolation-enabled");
+
+	return 0;
+}
+
 static int dsi_ctrl_dev_probe(struct platform_device *pdev)
 {
 	struct dsi_ctrl *dsi_ctrl;
 	struct dsi_ctrl_list_item *item;
 	const struct of_device_id *id;
 	enum dsi_ctrl_version version;
-	u32 index = 0;
 	int rc = 0;
 
 	id = of_match_node(msm_dsi_of_match, pdev->dev.of_node);
@@ -1285,22 +1313,18 @@
 	if (!dsi_ctrl)
 		return -ENOMEM;
 
-	rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index);
-	if (rc) {
-		pr_debug("cell index not set, default to 0\n");
-		index = 0;
-	}
-
-	dsi_ctrl->cell_index = index;
 	dsi_ctrl->version = version;
 	dsi_ctrl->irq_info.irq_num = -1;
 	dsi_ctrl->irq_info.irq_stat_mask = 0x0;
 
 	spin_lock_init(&dsi_ctrl->irq_info.irq_lock);
 
-	dsi_ctrl->name = of_get_property(pdev->dev.of_node, "label", NULL);
-	if (!dsi_ctrl->name)
-		dsi_ctrl->name = DSI_CTRL_DEFAULT_LABEL;
+	rc = dsi_ctrl_dts_parse(dsi_ctrl, pdev->dev.of_node);
+	if (rc) {
+		pr_err("ctrl:%d dts parse failed, rc = %d\n",
+						dsi_ctrl->cell_index, rc);
+		goto fail;
+	}
 
 	rc = dsi_ctrl_init_regmap(pdev, dsi_ctrl);
 	if (rc) {
@@ -1321,7 +1345,7 @@
 	}
 
 	rc = dsi_catalog_ctrl_setup(&dsi_ctrl->hw, dsi_ctrl->version,
-				    dsi_ctrl->cell_index);
+		    dsi_ctrl->cell_index, dsi_ctrl->phy_isolation_enabled);
 	if (rc) {
 		pr_err("Catalog does not support version (%d)\n",
 		       dsi_ctrl->version);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index dff5b02..f10c7a6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -190,6 +190,8 @@
  * @debugfs_root:        Root for debugfs entries.
  * @misr_enable:         Frame MISR enable/disable
  * @misr_cache:          Cached Frame MISR value
+ * @phy_isolation_enabled:    A boolean property allows to isolate the phy from
+ *                          dsi controller and run only dsi controller.
  */
 struct dsi_ctrl {
 	struct platform_device *pdev;
@@ -232,6 +234,7 @@
 	bool misr_enable;
 	u32 misr_cache;
 
+	bool phy_isolation_enabled;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 2130144..57f9bcd 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -711,6 +711,8 @@
  *                          controller.
  * @supported_interrupts:   Number of supported interrupts.
  * @supported_errors:       Number of supported errors.
+ * @phy_isolation_enabled:    A boolean property allows to isolate the phy from
+ *                          dsi controller and run only dsi controller.
  */
 struct dsi_ctrl_hw {
 	void __iomem *base;
@@ -728,6 +730,8 @@
 	/* capabilities */
 	u32 supported_interrupts;
 	u64 supported_errors;
+
+	bool phy_isolation_enabled;
 };
 
 #endif /* _DSI_CTRL_HW_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index c85d9f4..3fec296 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -90,6 +90,8 @@
 
 	DSI_W32(ctrl, DSI_CTRL, reg_value);
 
+	if (ctrl->phy_isolation_enabled)
+		DSI_W32(ctrl, DSI_DEBUG_CTRL, BIT(28));
 	pr_debug("[DSI_%d]Host configuration complete\n", ctrl->index);
 }
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
index 34e9e72..f8f7e13 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
@@ -184,6 +184,7 @@
 #define DSI_DESKEW_CTRL                            (0x02BC)
 #define DSI_DESKEW_DELAY_CTRL                      (0x02C0)
 #define DSI_DESKEW_SW_TRIGGER                      (0x02C4)
+#define DSI_DEBUG_CTRL                             (0x02C8)
 #define DSI_SECURE_DISPLAY_STATUS                  (0x02CC)
 #define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR     (0x02D0)
 #define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR       (0x02D4)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 547a3e5..04dd6a5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -3939,7 +3939,7 @@
 			pr_err("[%s] failed to switch DSI panel mode, rc=%d\n",
 				   display->name, rc);
 
-		goto error_disable_panel;
+		goto error;
 	}
 
 	if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 5a48aae..017dbfb 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -26,6 +26,7 @@
 	struct drm_device *dev;
 	struct drm_atomic_state *state;
 	uint32_t crtc_mask;
+	bool nonblock;
 	struct kthread_work commit_work;
 };
 
@@ -62,7 +63,8 @@
 static void commit_destroy(struct msm_commit *c)
 {
 	end_atomic(c->dev->dev_private, c->crtc_mask);
-	kfree(c);
+	if (c->nonblock)
+		kfree(c);
 }
 
 static void msm_atomic_wait_for_commit_done(
@@ -310,13 +312,6 @@
 		if (msm_is_mode_seamless(&crtc->state->mode))
 			continue;
 
-		/**
-		 * On DMS switch, wait for ping pong done to ensure the current
-		 * frame transfer is complete.
-		 */
-		if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode))
-			kms->funcs->wait_for_tx_complete(kms, crtc);
-
 		funcs = crtc->helper_private;
 
 		if (crtc->state->enable) {
@@ -456,7 +451,8 @@
 	SDE_ATRACE_END("complete_commit");
 }
 
-static struct msm_commit *commit_init(struct drm_atomic_state *state)
+static struct msm_commit *commit_init(struct drm_atomic_state *state,
+		bool nonblock)
 {
 	struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
 
@@ -465,6 +461,7 @@
 
 	c->dev = state->dev;
 	c->state = state;
+	c->nonblock = nonblock;
 
 	kthread_init_work(&c->commit_work, _msm_drm_commit_work_cb);
 
@@ -509,6 +506,11 @@
 			break;
 	}
 
+	if (!ret && !commit->nonblock) {
+		kthread_flush_work(&commit->commit_work);
+		kfree(commit);
+	}
+
 	return ret;
 }
 
@@ -542,7 +544,7 @@
 		return ret;
 	}
 
-	c = commit_init(state);
+	c = commit_init(state, nonblock);
 	if (!c) {
 		ret = -ENOMEM;
 		goto error;
@@ -610,20 +612,13 @@
 	 * current layout.
 	 */
 
-	if (nonblock) {
-		ret = msm_atomic_commit_dispatch(dev, state, c);
-		if (ret) {
-			DRM_ERROR("%s: atomic commit failed\n", __func__);
-			drm_atomic_state_free(state);
-			commit_destroy(c);
-			goto error;
-		}
-		SDE_ATRACE_END("atomic_commit");
-		return 0;
+	ret = msm_atomic_commit_dispatch(dev, state, c);
+	if (ret) {
+		DRM_ERROR("%s: atomic commit failed\n", __func__);
+		drm_atomic_state_free(state);
+		commit_destroy(c);
+		goto error;
 	}
-
-	complete_commit(c);
-
 	SDE_ATRACE_END("atomic_commit");
 	return 0;
 
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 2f665a4..c6943de 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -216,10 +216,12 @@
  * enum msm_event_wait - type of HW events to wait for
  * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
  * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel
+ * @MSM_ENC_VBLANK - wait for the HW VBLANK event (for driver-internal waiters)
  */
 enum msm_event_wait {
 	MSM_ENC_COMMIT_DONE = 0,
 	MSM_ENC_TX_COMPLETE,
+	MSM_ENC_VBLANK,
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 8d727fe..c695dda 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -31,11 +31,14 @@
 #define BO_PINNED   0x2000
 
 static struct msm_gem_submit *submit_create(struct drm_device *dev,
-		struct msm_gpu *gpu, int nr_bos, int nr_cmds)
+		struct msm_gpu *gpu, uint32_t nr_bos, uint32_t nr_cmds)
 {
 	struct msm_gem_submit *submit;
-	int sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) +
-			(nr_cmds * sizeof(*submit->cmd));
+	uint64_t sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) +
+		(nr_cmds * sizeof(submit->cmd[0]));
+
+	if (sz > SIZE_MAX)
+		return NULL;
 
 	submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
 	if (!submit)
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 3af8278..447a6c3 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -365,12 +365,60 @@
 	return c_conn->ops.get_info(info, c_conn->display);
 }
 
+static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
+{
+	struct drm_connector *connector;
+	void *display;
+	int (*set_power)(struct drm_connector *, int, void *);
+	int mode, rc = 0;
+
+	if (!c_conn)
+		return -EINVAL;
+	connector = &c_conn->base;
+
+	switch (c_conn->dpms_mode) {
+	case DRM_MODE_DPMS_ON:
+		mode = c_conn->lp_mode;
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+		mode = SDE_MODE_DPMS_STANDBY;
+		break;
+	case DRM_MODE_DPMS_SUSPEND:
+		mode = SDE_MODE_DPMS_SUSPEND;
+		break;
+	case DRM_MODE_DPMS_OFF:
+		mode = SDE_MODE_DPMS_OFF;
+		break;
+	default:
+		mode = c_conn->lp_mode;
+		SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
+				connector->base.id, mode);
+		break;
+	}
+
+	SDE_EVT32(connector->base.id, c_conn->dpms_mode, c_conn->lp_mode, mode);
+	SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
+			c_conn->dpms_mode, c_conn->lp_mode, mode);
+
+	if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
+		display = c_conn->display;
+		set_power = c_conn->ops.set_power;
+
+		mutex_unlock(&c_conn->lock);
+		rc = set_power(connector, mode, display);
+		mutex_lock(&c_conn->lock);
+	}
+	c_conn->last_panel_power_mode = mode;
+
+	return rc;
+}
+
 int sde_connector_pre_kickoff(struct drm_connector *connector)
 {
 	struct sde_connector *c_conn;
 	struct sde_connector_state *c_state;
 	struct msm_display_kickoff_params params;
-	int rc;
+	int idx, rc;
 
 	if (!connector) {
 		SDE_ERROR("invalid argument\n");
@@ -385,6 +433,22 @@
 		return -EINVAL;
 	}
 
+	while ((idx = msm_property_pop_dirty(&c_conn->property_info,
+					&c_state->property_state)) >= 0) {
+		switch (idx) {
+		case CONNECTOR_PROP_LP:
+			mutex_lock(&c_conn->lock);
+			c_conn->lp_mode = sde_connector_get_property(
+					connector->state, CONNECTOR_PROP_LP);
+			_sde_connector_update_power_locked(c_conn);
+			mutex_unlock(&c_conn->lock);
+			break;
+		default:
+			/* nothing to do for most properties */
+			break;
+		}
+	}
+
 	if (!c_conn->ops.pre_kickoff)
 		return 0;
 
@@ -687,56 +751,6 @@
 	return 0;
 }
 
-static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
-{
-	struct drm_connector *connector;
-	void *display;
-	int (*set_power)(struct drm_connector *, int, void *);
-	int mode, rc = 0;
-
-	if (!c_conn)
-		return -EINVAL;
-	connector = &c_conn->base;
-
-	mode = c_conn->lp_mode;
-	if (c_conn->dpms_mode != DRM_MODE_DPMS_ON)
-		mode = SDE_MODE_DPMS_OFF;
-	switch (c_conn->dpms_mode) {
-	case DRM_MODE_DPMS_ON:
-		mode = c_conn->lp_mode;
-		break;
-	case DRM_MODE_DPMS_STANDBY:
-		mode = SDE_MODE_DPMS_STANDBY;
-		break;
-	case DRM_MODE_DPMS_SUSPEND:
-		mode = SDE_MODE_DPMS_SUSPEND;
-		break;
-	case DRM_MODE_DPMS_OFF:
-		mode = SDE_MODE_DPMS_OFF;
-		break;
-	default:
-		mode = c_conn->lp_mode;
-		SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
-				connector->base.id, mode);
-		break;
-	}
-
-	SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
-			c_conn->dpms_mode, c_conn->lp_mode, mode);
-
-	if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
-		display = c_conn->display;
-		set_power = c_conn->ops.set_power;
-
-		mutex_unlock(&c_conn->lock);
-		rc = set_power(connector, mode, display);
-		mutex_lock(&c_conn->lock);
-	}
-	c_conn->last_panel_power_mode = mode;
-
-	return rc;
-}
-
 static int sde_connector_atomic_set_property(struct drm_connector *connector,
 		struct drm_connector_state *state,
 		struct drm_property *property,
@@ -795,12 +809,6 @@
 				SDE_ERROR("prep fb failed, %d\n", rc);
 		}
 		break;
-	case CONNECTOR_PROP_LP:
-		mutex_lock(&c_conn->lock);
-		c_conn->lp_mode = val;
-		_sde_connector_update_power_locked(c_conn);
-		mutex_unlock(&c_conn->lock);
-		break;
 	default:
 		break;
 	}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 935dc12..0f08296 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -34,6 +34,7 @@
 #include "sde_color_processing.h"
 #include "sde_encoder.h"
 #include "sde_connector.h"
+#include "sde_vbif.h"
 #include "sde_power_handle.h"
 #include "sde_core_perf.h"
 #include "sde_trace.h"
@@ -65,7 +66,7 @@
 };
 
 /* default input fence timeout, in ms */
-#define SDE_CRTC_INPUT_FENCE_TIMEOUT    2000
+#define SDE_CRTC_INPUT_FENCE_TIMEOUT    10000
 
 /*
  * The default input fence timeout is 2 seconds while max allowed
@@ -180,7 +181,9 @@
  */
 static void _sde_crtc_rp_free_unused(struct sde_crtc_respool *rp)
 {
+	mutex_lock(rp->rp_lock);
 	_sde_crtc_rp_reclaim(rp, false);
+	mutex_unlock(rp->rp_lock);
 }
 
 /**
@@ -190,7 +193,10 @@
  */
 static void _sde_crtc_rp_destroy(struct sde_crtc_respool *rp)
 {
+	mutex_lock(rp->rp_lock);
+	list_del_init(&rp->rp_list);
 	_sde_crtc_rp_reclaim(rp, true);
+	mutex_unlock(rp->rp_lock);
 }
 
 /**
@@ -229,7 +235,7 @@
 	struct sde_crtc_res *res, *dup_res;
 	struct drm_crtc *crtc;
 
-	if (!rp || !dup_rp) {
+	if (!rp || !dup_rp || !rp->rp_head) {
 		SDE_ERROR("invalid resource pool\n");
 		return;
 	}
@@ -242,13 +248,16 @@
 
 	SDE_DEBUG("crtc%d.%u duplicate\n", crtc->base.id, rp->sequence_id);
 
+	mutex_lock(rp->rp_lock);
 	dup_rp->sequence_id = rp->sequence_id + 1;
 	INIT_LIST_HEAD(&dup_rp->res_list);
 	dup_rp->ops = rp->ops;
 	list_for_each_entry(res, &rp->res_list, list) {
 		dup_res = kzalloc(sizeof(struct sde_crtc_res), GFP_KERNEL);
-		if (!dup_res)
+		if (!dup_res) {
+			mutex_unlock(rp->rp_lock);
 			return;
+		}
 		INIT_LIST_HEAD(&dup_res->list);
 		atomic_set(&dup_res->refcount, 0);
 		dup_res->type = res->type;
@@ -264,28 +273,43 @@
 		if (dup_res->ops.get)
 			dup_res->ops.get(dup_res->val, 0, -1);
 	}
+
+	dup_rp->rp_lock = rp->rp_lock;
+	dup_rp->rp_head = rp->rp_head;
+	INIT_LIST_HEAD(&dup_rp->rp_list);
+	list_add_tail(&dup_rp->rp_list, rp->rp_head);
+	mutex_unlock(rp->rp_lock);
 }
 
 /**
  * _sde_crtc_rp_reset - reset resource pool after allocation
  * @rp: Pointer to original resource pool
+ * @rp_lock: Pointer to serialization resource pool lock
+ * @rp_head: Pointer to crtc resource pool head
  * return: None
  */
-static void _sde_crtc_rp_reset(struct sde_crtc_respool *rp)
+static void _sde_crtc_rp_reset(struct sde_crtc_respool *rp,
+		struct mutex *rp_lock, struct list_head *rp_head)
 {
-	if (!rp) {
+	if (!rp || !rp_lock || !rp_head) {
 		SDE_ERROR("invalid resource pool\n");
 		return;
 	}
 
+	mutex_lock(rp_lock);
+	rp->rp_lock = rp_lock;
+	rp->rp_head = rp_head;
+	INIT_LIST_HEAD(&rp->rp_list);
 	rp->sequence_id = 0;
 	INIT_LIST_HEAD(&rp->res_list);
 	rp->ops.get = _sde_crtc_hw_blk_get;
 	rp->ops.put = _sde_crtc_hw_blk_put;
+	list_add_tail(&rp->rp_list, rp->rp_head);
+	mutex_unlock(rp_lock);
 }
 
 /**
- * _sde_crtc_rp_add - add given resource to resource pool
+ * _sde_crtc_rp_add_no_lock - add given resource to resource pool without lock
  * @rp: Pointer to original resource pool
  * @type: Resource type
  * @tag: Search tag for given resource
@@ -293,8 +317,8 @@
  * @ops: Resource callback operations
  * return: 0 if success; error code otherwise
  */
-static int _sde_crtc_rp_add(struct sde_crtc_respool *rp, u32 type, u64 tag,
-		void *val, struct sde_crtc_res_ops *ops)
+static int _sde_crtc_rp_add_no_lock(struct sde_crtc_respool *rp, u32 type,
+		u64 tag, void *val, struct sde_crtc_res_ops *ops)
 {
 	struct sde_crtc_res *res;
 	struct drm_crtc *crtc;
@@ -335,6 +359,31 @@
 }
 
 /**
+ * _sde_crtc_rp_add - add given resource to resource pool
+ * @rp: Pointer to original resource pool
+ * @type: Resource type
+ * @tag: Search tag for given resource
+ * @val: Resource handle
+ * @ops: Resource callback operations
+ * return: 0 if success; error code otherwise
+ */
+static int _sde_crtc_rp_add(struct sde_crtc_respool *rp, u32 type, u64 tag,
+		void *val, struct sde_crtc_res_ops *ops)
+{
+	int rc;
+
+	if (!rp) {
+		SDE_ERROR("invalid resource pool\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(rp->rp_lock);
+	rc = _sde_crtc_rp_add_no_lock(rp, type, tag, val, ops);
+	mutex_unlock(rp->rp_lock);
+	return rc;
+}
+
+/**
  * _sde_crtc_rp_get - lookup the resource from given resource pool and obtain
  *	if available; otherwise, obtain resource from global pool
  * @rp: Pointer to original resource pool
@@ -344,6 +393,7 @@
  */
 static void *_sde_crtc_rp_get(struct sde_crtc_respool *rp, u32 type, u64 tag)
 {
+	struct sde_crtc_respool *old_rp;
 	struct sde_crtc_res *res;
 	void *val = NULL;
 	int rc;
@@ -360,6 +410,7 @@
 		return NULL;
 	}
 
+	mutex_lock(rp->rp_lock);
 	list_for_each_entry(res, &rp->res_list, list) {
 		if (res->type != type || res->tag != tag)
 			continue;
@@ -369,6 +420,7 @@
 				atomic_read(&res->refcount));
 		atomic_inc(&res->refcount);
 		res->flags &= ~SDE_CRTC_RES_FLAG_FREE;
+		mutex_unlock(rp->rp_lock);
 		return res->val;
 	}
 	list_for_each_entry(res, &rp->res_list, list) {
@@ -381,16 +433,63 @@
 		atomic_inc(&res->refcount);
 		res->tag = tag;
 		res->flags &= ~SDE_CRTC_RES_FLAG_FREE;
+		mutex_unlock(rp->rp_lock);
 		return res->val;
 	}
+	/* not in this rp, try to grab from global pool */
 	if (rp->ops.get)
 		val = rp->ops.get(NULL, type, -1);
+	if (!IS_ERR_OR_NULL(val))
+		goto add_res;
+	/*
+	 * Search older resource pools for hw blk with matching type,
+	 * necessary when resource is being used by this object,
+	 * but in previous states not yet cleaned up.
+	 *
+	 * This enables searching of all resources currently owned
+	 * by this crtc even though the resource might not be used
+	 * in the current atomic state. This allows those resources
+	 * to be re-acquired by the new atomic state immediately
+	 * without waiting for the resources to be fully released.
+	 */
+	else if (IS_ERR_OR_NULL(val) && (type < SDE_HW_BLK_MAX)) {
+		list_for_each_entry(old_rp, rp->rp_head, rp_list) {
+			if (old_rp == rp)
+				continue;
+
+			list_for_each_entry(res, &old_rp->res_list, list) {
+				if (res->type != type)
+					continue;
+				SDE_DEBUG(
+					"crtc%d.%u found res:0x%x//%pK/ in crtc%d.%d\n",
+						crtc->base.id,
+						rp->sequence_id,
+						res->type, res->val,
+						crtc->base.id,
+						old_rp->sequence_id);
+				SDE_EVT32_VERBOSE(crtc->base.id,
+						rp->sequence_id,
+						res->type, res->val,
+						crtc->base.id,
+						old_rp->sequence_id);
+				if (res->ops.get)
+					res->ops.get(res->val, 0, -1);
+				val = res->val;
+				break;
+			}
+
+			if (!IS_ERR_OR_NULL(val))
+				break;
+		}
+	}
 	if (IS_ERR_OR_NULL(val)) {
 		SDE_DEBUG("crtc%d.%u failed to get res:0x%x//\n",
 				crtc->base.id, rp->sequence_id, type);
+		mutex_unlock(rp->rp_lock);
 		return NULL;
 	}
-	rc = _sde_crtc_rp_add(rp, type, tag, val, &rp->ops);
+add_res:
+	rc = _sde_crtc_rp_add_no_lock(rp, type, tag, val, &rp->ops);
 	if (rc) {
 		SDE_ERROR("crtc%d.%u failed to add res:0x%x/0x%llx\n",
 				crtc->base.id, rp->sequence_id, type, tag);
@@ -398,6 +497,7 @@
 			rp->ops.put(val);
 		val = NULL;
 	}
+	mutex_unlock(rp->rp_lock);
 	return val;
 }
 
@@ -424,6 +524,7 @@
 		return;
 	}
 
+	mutex_lock(rp->rp_lock);
 	list_for_each_entry_safe(res, next, &rp->res_list, list) {
 		if (res->type != type || res->tag != tag)
 			continue;
@@ -440,10 +541,12 @@
 		else if (atomic_dec_return(&res->refcount) == 0)
 			res->flags |= SDE_CRTC_RES_FLAG_FREE;
 
+		mutex_unlock(rp->rp_lock);
 		return;
 	}
 	SDE_ERROR("crtc%d.%u not found res:0x%x/0x%llx\n",
 			crtc->base.id, rp->sequence_id, type, tag);
+	mutex_unlock(rp->rp_lock);
 }
 
 int sde_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag,
@@ -1220,7 +1323,8 @@
 				state->src_w >> 16, state->src_h >> 16,
 				state->crtc_x, state->crtc_y,
 				state->crtc_w, state->crtc_h,
-				cstate->sbuf_cfg.rot_op_mode);
+				flush_tmp ? cstate->sbuf_cfg.rot_op_mode :
+				SDE_CTL_ROT_OP_MODE_OFFLINE);
 
 		stage_idx = zpos_cnt[pstate->stage]++;
 		stage_cfg->stage[pstate->stage][stage_idx] =
@@ -2119,6 +2223,7 @@
 
 void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
 {
+	struct drm_plane *plane;
 	struct drm_encoder *encoder;
 	struct drm_device *dev;
 	struct sde_crtc *sde_crtc;
@@ -2189,6 +2294,12 @@
 	}
 	sde_crtc->play_count++;
 
+	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE)
+		drm_atomic_crtc_for_each_plane(plane, crtc)
+			sde_plane_kickoff(plane);
+
+	sde_vbif_clear_errors(sde_kms);
+
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 		if (encoder->crtc != crtc)
 			continue;
@@ -2196,19 +2307,20 @@
 		sde_encoder_kickoff(encoder);
 	}
 
-	reinit_completion(&sde_crtc->frame_done_comp);
-
 end:
+	reinit_completion(&sde_crtc->frame_done_comp);
 	SDE_ATRACE_END("crtc_commit");
 	return;
 }
 
 /**
- * _sde_crtc_vblank_enable_nolock - update power resource and vblank request
+ * _sde_crtc_vblank_enable_no_lock - update power resource and vblank request
  * @sde_crtc: Pointer to sde crtc structure
  * @enable: Whether to enable/disable vblanks
+ *
+ * @Return: error code
  */
-static void _sde_crtc_vblank_enable_nolock(
+static int _sde_crtc_vblank_enable_no_lock(
 		struct sde_crtc *sde_crtc, bool enable)
 {
 	struct drm_device *dev;
@@ -2217,7 +2329,7 @@
 
 	if (!sde_crtc) {
 		SDE_ERROR("invalid crtc\n");
-		return;
+		return -EINVAL;
 	}
 
 	crtc = &sde_crtc->base;
@@ -2231,13 +2343,16 @@
 		ret = _sde_crtc_power_enable(sde_crtc, true);
 		mutex_lock(&sde_crtc->crtc_lock);
 		if (ret)
-			return;
+			return ret;
 
 		list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
 			if (enc->crtc != crtc)
 				continue;
 
-			SDE_EVT32(DRMID(crtc), DRMID(enc), enable);
+			SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable,
+					sde_crtc->enabled,
+					sde_crtc->suspend,
+					sde_crtc->vblank_requested);
 
 			sde_encoder_register_vblank_callback(enc,
 					sde_crtc_vblank_cb, (void *)crtc);
@@ -2247,7 +2362,10 @@
 			if (enc->crtc != crtc)
 				continue;
 
-			SDE_EVT32(DRMID(crtc), DRMID(enc), enable);
+			SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable,
+					sde_crtc->enabled,
+					sde_crtc->suspend,
+					sde_crtc->vblank_requested);
 
 			sde_encoder_register_vblank_callback(enc, NULL, NULL);
 		}
@@ -2257,6 +2375,8 @@
 		_sde_crtc_power_enable(sde_crtc, false);
 		mutex_lock(&sde_crtc->crtc_lock);
 	}
+
+	return 0;
 }
 
 /**
@@ -2269,8 +2389,7 @@
 	struct sde_crtc *sde_crtc;
 	struct msm_drm_private *priv;
 	struct sde_kms *sde_kms;
-	struct drm_event event;
-	u32 power_on;
+	int ret = 0;
 
 	if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
 		SDE_ERROR("invalid crtc\n");
@@ -2286,35 +2405,27 @@
 	sde_kms = to_sde_kms(priv->kms);
 
 	SDE_DEBUG("crtc%d suspend = %d\n", crtc->base.id, enable);
+	SDE_EVT32_VERBOSE(DRMID(crtc), enable);
 
 	mutex_lock(&sde_crtc->crtc_lock);
 
-	event.type = DRM_EVENT_CRTC_POWER;
-	event.length = sizeof(u32);
-	/*
-	 * Update CP on suspend/resume transitions
-	 */
-	if (enable && !sde_crtc->suspend) {
-		sde_cp_crtc_suspend(crtc);
-		power_on = 0;
-	} else if (!enable && sde_crtc->suspend) {
-		sde_cp_crtc_resume(crtc);
-		power_on = 1;
-	}
-
 	/*
 	 * If the vblank is enabled, release a power reference on suspend
 	 * and take it back during resume (if it is still enabled).
 	 */
+	SDE_EVT32(DRMID(&sde_crtc->base), enable, sde_crtc->enabled,
+			sde_crtc->suspend, sde_crtc->vblank_requested);
 	if (sde_crtc->suspend == enable)
 		SDE_DEBUG("crtc%d suspend already set to %d, ignoring update\n",
 				crtc->base.id, enable);
-	else if (sde_crtc->vblank_enable)
-		_sde_crtc_vblank_enable_nolock(sde_crtc, !enable);
+	else if (sde_crtc->enabled && sde_crtc->vblank_requested) {
+		ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, !enable);
+		if (ret)
+			SDE_ERROR("%s vblank enable failed: %d\n",
+					sde_crtc->name, ret);
+	}
 
 	sde_crtc->suspend = enable;
-	msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
-			(u8 *)&power_on);
 	mutex_unlock(&sde_crtc->crtc_lock);
 }
 
@@ -2394,36 +2505,22 @@
 
 	_sde_crtc_set_input_fence_timeout(cstate);
 
-	_sde_crtc_rp_reset(&cstate->rp);
+	_sde_crtc_rp_reset(&cstate->rp, &sde_crtc->rp_lock,
+			&sde_crtc->rp_head);
 
 	cstate->base.crtc = crtc;
 	crtc->state = &cstate->base;
 }
 
-static int _sde_crtc_vblank_no_lock(struct sde_crtc *sde_crtc, bool en)
-{
-	if (!sde_crtc) {
-		SDE_ERROR("invalid crtc\n");
-		return -EINVAL;
-	}
-
-	if (!sde_crtc->base.enabled || sde_crtc->suspend)
-		SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->base.enabled, en,
-				sde_crtc->vblank_enable, sde_crtc->suspend);
-	else if (sde_crtc->vblank_enable != en)
-		_sde_crtc_vblank_enable_nolock(sde_crtc, en);
-	sde_crtc->vblank_enable = en;
-
-	return 0;
-}
-
 static void sde_crtc_handle_power_event(u32 event_type, void *arg)
 {
 	struct drm_crtc *crtc = arg;
 	struct sde_crtc *sde_crtc;
+	struct drm_plane *plane;
 	struct drm_encoder *encoder;
+	struct sde_crtc_mixer *m;
 	struct drm_event event;
-	u32 power_on = 0;
+	u32 power_on = 0, i, misr_status;
 
 	if (!crtc) {
 		SDE_ERROR("invalid crtc\n");
@@ -2435,7 +2532,8 @@
 
 	SDE_EVT32(DRMID(crtc), event_type);
 
-	if (event_type == SDE_POWER_EVENT_POST_ENABLE) {
+	switch (event_type) {
+	case SDE_POWER_EVENT_POST_ENABLE:
 		/* restore encoder; crtc will be programmed during commit */
 		drm_for_each_encoder(encoder, crtc->dev) {
 			if (encoder->crtc != crtc)
@@ -2450,9 +2548,31 @@
 		power_on = 1;
 		msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
 				(u8 *)&power_on);
-	} else if (event_type == SDE_POWER_EVENT_POST_DISABLE) {
-		struct drm_plane *plane;
 
+		for (i = 0; i < sde_crtc->num_mixers; ++i) {
+			m = &sde_crtc->mixers[i];
+			if (!m->hw_lm || !m->hw_lm->ops.setup_misr ||
+					!sde_crtc->misr_enable)
+				continue;
+
+			m->hw_lm->ops.setup_misr(m->hw_lm, true,
+					sde_crtc->misr_frame_count);
+		}
+		break;
+	case SDE_POWER_EVENT_PRE_DISABLE:
+		for (i = 0; i < sde_crtc->num_mixers; ++i) {
+			m = &sde_crtc->mixers[i];
+			if (!m->hw_lm || !m->hw_lm->ops.collect_misr ||
+					!sde_crtc->misr_enable)
+				continue;
+
+			misr_status = m->hw_lm->ops.collect_misr(m->hw_lm);
+			sde_crtc->misr_data[i] = misr_status ? misr_status :
+							sde_crtc->misr_data[i];
+		}
+		sde_cp_crtc_pre_ipc(crtc);
+		break;
+	case SDE_POWER_EVENT_POST_DISABLE:
 		/*
 		 * set revalidate flag in planes, so it will be re-programmed
 		 * in the next frame update
@@ -2467,8 +2587,10 @@
 		power_on = 0;
 		msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
 				(u8 *)&power_on);
-	} else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) {
-		sde_cp_crtc_pre_ipc(crtc);
+		break;
+	default:
+		SDE_DEBUG("event:%d not handled\n", event_type);
+		break;
 	}
 
 	mutex_unlock(&sde_crtc->crtc_lock);
@@ -2482,6 +2604,8 @@
 	struct msm_drm_private *priv;
 	unsigned long flags;
 	struct sde_crtc_irq_info *node = NULL;
+	struct drm_event event;
+	u32 power_on;
 	int ret;
 
 	if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) {
@@ -2498,7 +2622,15 @@
 		_sde_crtc_set_suspend(crtc, true);
 
 	mutex_lock(&sde_crtc->crtc_lock);
-	SDE_EVT32(DRMID(crtc));
+	SDE_EVT32_VERBOSE(DRMID(crtc));
+
+	/* update color processing on suspend */
+	event.type = DRM_EVENT_CRTC_POWER;
+	event.length = sizeof(u32);
+	sde_cp_crtc_suspend(crtc);
+	power_on = 0;
+	msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
+			(u8 *)&power_on);
 
 	/* wait for frame_event_done completion */
 	if (_sde_crtc_wait_for_frame_done(crtc))
@@ -2506,13 +2638,16 @@
 				crtc->base.id,
 				atomic_read(&sde_crtc->frame_pending));
 
-	if (sde_crtc->vblank_enable && !sde_crtc->suspend) {
-		SDE_DEBUG("crtc%d vblank left enabled at disable time\n",
-				crtc->base.id);
-		SDE_EVT32(DRMID(crtc), sde_crtc->vblank_enable,
-				SDE_EVTLOG_FUNC_CASE1);
-		_sde_crtc_vblank_enable_nolock(sde_crtc, false);
+	SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend,
+			sde_crtc->vblank_requested);
+	if (sde_crtc->enabled && !sde_crtc->suspend &&
+			sde_crtc->vblank_requested) {
+		ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, false);
+		if (ret)
+			SDE_ERROR("%s vblank enable failed: %d\n",
+					sde_crtc->name, ret);
 	}
+	sde_crtc->enabled = false;
 
 	if (atomic_read(&sde_crtc->frame_pending)) {
 		SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->frame_pending),
@@ -2563,6 +2698,8 @@
 	struct msm_drm_private *priv;
 	unsigned long flags;
 	struct sde_crtc_irq_info *node = NULL;
+	struct drm_event event;
+	u32 power_on;
 	int ret;
 
 	if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
@@ -2572,7 +2709,7 @@
 	priv = crtc->dev->dev_private;
 
 	SDE_DEBUG("crtc%d\n", crtc->base.id);
-	SDE_EVT32(DRMID(crtc));
+	SDE_EVT32_VERBOSE(DRMID(crtc));
 	sde_crtc = to_sde_crtc(crtc);
 
 	drm_for_each_encoder(encoder, crtc->dev) {
@@ -2583,13 +2720,25 @@
 	}
 
 	mutex_lock(&sde_crtc->crtc_lock);
-	if (sde_crtc->vblank_enable) {
-		/* honor user vblank request on crtc while it was disabled */
-		SDE_DEBUG("%s vblank found enabled at crtc enable time\n",
-				sde_crtc->name);
-		SDE_EVT32(DRMID(crtc), sde_crtc->vblank_enable);
-		_sde_crtc_vblank_enable_nolock(sde_crtc, true);
+	SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend,
+			sde_crtc->vblank_requested);
+	if (!sde_crtc->enabled && !sde_crtc->suspend &&
+			sde_crtc->vblank_requested) {
+		ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, true);
+		if (ret)
+			SDE_ERROR("%s vblank enable failed: %d\n",
+					sde_crtc->name, ret);
 	}
+	sde_crtc->enabled = true;
+
+	/* update color processing on resume */
+	event.type = DRM_EVENT_CRTC_POWER;
+	event.length = sizeof(u32);
+	sde_cp_crtc_resume(crtc);
+	power_on = 1;
+	msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
+			(u8 *)&power_on);
+
 	mutex_unlock(&sde_crtc->crtc_lock);
 
 	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
@@ -2803,7 +2952,7 @@
 	 */
 	if (((secure == SDE_DRM_SEC_ONLY) &&
 				(fb_ns || fb_sec || fb_sec_dir)) ||
-			(fb_sec || fb_sec_dir)) {
+			(fb_sec && fb_sec_dir)) {
 		SDE_ERROR(
 			"crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d, NS_Dir%d\n",
 				crtc->base.id,
@@ -3110,7 +3259,7 @@
 int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
 {
 	struct sde_crtc *sde_crtc;
-	int rc;
+	int ret;
 
 	if (!crtc) {
 		SDE_ERROR("invalid crtc\n");
@@ -3119,10 +3268,18 @@
 	sde_crtc = to_sde_crtc(crtc);
 
 	mutex_lock(&sde_crtc->crtc_lock);
-	rc = _sde_crtc_vblank_no_lock(sde_crtc, en);
+	SDE_EVT32(DRMID(&sde_crtc->base), en, sde_crtc->enabled,
+			sde_crtc->suspend, sde_crtc->vblank_requested);
+	if (sde_crtc->enabled && !sde_crtc->suspend) {
+		ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, en);
+		if (ret)
+			SDE_ERROR("%s vblank enable failed: %d\n",
+					sde_crtc->name, ret);
+	}
+	sde_crtc->vblank_requested = en;
 	mutex_unlock(&sde_crtc->crtc_lock);
 
-	return rc;
+	return 0;
 }
 
 void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
@@ -3588,7 +3745,7 @@
 		sde_crtc->vblank_cb_time = ktime_set(0, 0);
 	}
 
-	seq_printf(s, "vblank_enable:%d\n", sde_crtc->vblank_enable);
+	seq_printf(s, "vblank_enable:%d\n", sde_crtc->vblank_requested);
 
 	mutex_unlock(&sde_crtc->crtc_lock);
 
@@ -3631,9 +3788,11 @@
 
 	mutex_lock(&sde_crtc->crtc_lock);
 	sde_crtc->misr_enable = enable;
+	sde_crtc->misr_frame_count = frame_count;
 	for (i = 0; i < sde_crtc->num_mixers; ++i) {
+		sde_crtc->misr_data[i] = 0;
 		m = &sde_crtc->mixers[i];
-		if (!m->hw_lm)
+		if (!m->hw_lm || !m->hw_lm->ops.setup_misr)
 			continue;
 
 		m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count);
@@ -3650,6 +3809,7 @@
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_mixer *m;
 	int i = 0, rc;
+	u32 misr_status;
 	ssize_t len = 0;
 	char buf[MISR_BUFF_SIZE + 1] = {'\0'};
 
@@ -3673,13 +3833,16 @@
 
 	for (i = 0; i < sde_crtc->num_mixers; ++i) {
 		m = &sde_crtc->mixers[i];
-		if (!m->hw_lm)
+		if (!m->hw_lm || !m->hw_lm->ops.collect_misr)
 			continue;
 
+		misr_status = m->hw_lm->ops.collect_misr(m->hw_lm);
+		sde_crtc->misr_data[i] = misr_status ? misr_status :
+							sde_crtc->misr_data[i];
 		len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n",
 					m->hw_lm->idx - LM_0);
 		len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
-				m->hw_lm->ops.collect_misr(m->hw_lm));
+							sde_crtc->misr_data[i]);
 	}
 
 buff_check:
@@ -3720,6 +3883,7 @@
 	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
 	struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state);
 	struct sde_crtc_res *res;
+	struct sde_crtc_respool *rp;
 	int i;
 
 	seq_printf(s, "num_connectors: %d\n", cstate->num_connectors);
@@ -3737,12 +3901,16 @@
 				sde_crtc->cur_perf.max_per_pipe_ib[i]);
 	}
 
-	seq_printf(s, "rp.%d: ", cstate->rp.sequence_id);
-	list_for_each_entry(res, &cstate->rp.res_list, list)
-		seq_printf(s, "0x%x/0x%llx/%pK/%d ",
-				res->type, res->tag, res->val,
-				atomic_read(&res->refcount));
-	seq_puts(s, "\n");
+	mutex_lock(&sde_crtc->rp_lock);
+	list_for_each_entry(rp, &sde_crtc->rp_head, rp_list) {
+		seq_printf(s, "rp.%d: ", rp->sequence_id);
+		list_for_each_entry(res, &rp->res_list, list)
+			seq_printf(s, "0x%x/0x%llx/%pK/%d ",
+					res->type, res->tag, res->val,
+					atomic_read(&res->refcount));
+		seq_puts(s, "\n");
+	}
+	mutex_unlock(&sde_crtc->rp_lock);
 
 	return 0;
 }
@@ -3959,6 +4127,9 @@
 	spin_lock_init(&sde_crtc->spin_lock);
 	atomic_set(&sde_crtc->frame_pending, 0);
 
+	mutex_init(&sde_crtc->rp_lock);
+	INIT_LIST_HEAD(&sde_crtc->rp_head);
+
 	init_completion(&sde_crtc->frame_done_comp);
 
 	INIT_LIST_HEAD(&sde_crtc->frame_event_list);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 439aeac..f8ab110 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -123,8 +123,11 @@
  * @vblank_cb_count : count of vblank callback since last reset
  * @play_count    : frame count between crtc enable and disable
  * @vblank_cb_time  : ktime at vblank count reset
- * @vblank_enable : whether the user has requested vblank events
+ * @vblank_requested : whether the user has requested vblank events
  * @suspend         : whether or not a suspend operation is in progress
+ * @enabled       : whether the SDE CRTC is currently enabled. updated in the
+ *                  commit-thread, not state-swap time which is earlier, so
+ *                  safe to make decisions on during VBLANK on/off work
  * @feature_list  : list of color processing features supported on a crtc
  * @active_list   : list of color processing features are active
  * @dirty_list    : list of color processing features are dirty
@@ -142,8 +145,12 @@
  * @event_free_list : List of available event structures
  * @event_lock    : Spinlock around event handling code
  * @misr_enable   : boolean entry indicates misr enable/disable status.
+ * @misr_frame_count  : misr frame count provided by client
+ * @misr_data     : store misr data before turning off the clocks.
  * @power_event   : registered power event handle
  * @cur_perf      : current performance committed to clock/bandwidth driver
+ * @rp_lock       : serialization lock for resource pool
+ * @rp_head       : list of active resource pool
  */
 struct sde_crtc {
 	struct drm_crtc base;
@@ -171,8 +178,9 @@
 	u32 vblank_cb_count;
 	u64 play_count;
 	ktime_t vblank_cb_time;
-	bool vblank_enable;
+	bool vblank_requested;
 	bool suspend;
+	bool enabled;
 
 	struct list_head feature_list;
 	struct list_head active_list;
@@ -194,10 +202,15 @@
 	struct list_head event_free_list;
 	spinlock_t event_lock;
 	bool misr_enable;
+	u32 misr_frame_count;
+	u32 misr_data[CRTC_DUAL_MIXERS];
 
 	struct sde_power_event *power_event;
 
 	struct sde_core_perf_params cur_perf;
+
+	struct mutex rp_lock;
+	struct list_head rp_head;
 };
 
 #define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
@@ -242,11 +255,17 @@
 
 /**
  * sde_crtc_respool - crtc resource pool
+ * @rp_lock: pointer to serialization lock
+ * @rp_head: pointer to head of active resource pools of this crtc
+ * @rp_list: list of crtc resource pool
  * @sequence_id: sequence identifier, incremented per state duplication
  * @res_list: list of resource managed by this resource pool
  * @ops: resource operations for parent resource pool
  */
 struct sde_crtc_respool {
+	struct mutex *rp_lock;
+	struct list_head *rp_head;
+	struct list_head rp_list;
 	u32 sequence_id;
 	struct list_head res_list;
 	struct sde_crtc_res_ops ops;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 4ba2b75..d2637a4 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -71,9 +71,12 @@
 
 #define MISR_BUFF_SIZE			256
 
-#define IDLE_TIMEOUT	64
+#define IDLE_TIMEOUT	(66 - 16/2)
 #define IDLE_SHORT_TIMEOUT	1
 
+/* Maximum number of VSYNC wait attempts for RSC state transition */
+#define MAX_RSC_WAIT	5
+
 /**
  * enum sde_enc_rc_events - events for resource control state machine
  * @SDE_ENC_RC_EVENT_KICKOFF:
@@ -87,15 +90,29 @@
  *	Event signals the end of the data transfer after the PP FRAME_DONE
  *	event. At the end of this event, a delayed work is scheduled to go to
  *	IDLE_PC state after IDLE_TIMEOUT time.
+ * @SDE_ENC_RC_EVENT_PRE_STOP:
+ *	This event happens at NORMAL priority.
+ *	This event, when received during the ON state, set RSC to IDLE, and
+ *	and leave the RC STATE in the PRE_OFF state.
+ *	It should be followed by the STOP event as part of encoder disable.
+ *	If received during IDLE or OFF states, it will do nothing.
  * @SDE_ENC_RC_EVENT_STOP:
  *	This event happens at NORMAL priority.
- *	When this event is received, disable all the MDP/DSI core clocks
- *	and request RSC with IDLE state. Resource state should be in OFF
- *	at the end of the event.
- * @SDE_ENC_RC_EARLY_WAKEUP
+ *	When this event is received, disable all the MDP/DSI core clocks, and
+ *	disable IRQs. It should be called from the PRE_OFF or IDLE states.
+ *	IDLE is expected when IDLE_PC has run, and PRE_OFF did nothing.
+ *	PRE_OFF is expected when PRE_STOP was executed during the ON state.
+ *	Resource state should be in OFF at the end of the event.
+ * @SDE_ENC_RC_EVENT_PRE_MODESET:
  *	This event happens at NORMAL priority from a work item.
- *	Event signals that there will be frame update soon and the driver should
- *	wake up early to update the frame with minimum latency.
+ *	Event signals that there is a seamless mode switch is in prgoress. A
+ *	client needs to turn of only irq - leave clocks ON to reduce the mode
+ *	switch latency.
+ * @SDE_ENC_RC_EVENT_POST_MODESET:
+ *	This event happens at NORMAL priority from a work item.
+ *	Event signals that seamless mode switch is complete and resources are
+ *	acquired. Clients wants to turn on the irq again and update the rsc
+ *	with new vtotal.
  * @SDE_ENC_RC_EVENT_ENTER_IDLE:
  *	This event happens at NORMAL priority from a work item.
  *	Event signals that there were no frame updates for IDLE_TIMEOUT time.
@@ -105,20 +122,26 @@
 enum sde_enc_rc_events {
 	SDE_ENC_RC_EVENT_KICKOFF = 1,
 	SDE_ENC_RC_EVENT_FRAME_DONE,
+	SDE_ENC_RC_EVENT_PRE_STOP,
 	SDE_ENC_RC_EVENT_STOP,
-	SDE_ENC_RC_EVENT_EARLY_WAKE_UP,
+	SDE_ENC_RC_EVENT_PRE_MODESET,
+	SDE_ENC_RC_EVENT_POST_MODESET,
 	SDE_ENC_RC_EVENT_ENTER_IDLE
 };
 
 /*
  * enum sde_enc_rc_states - states that the resource control maintains
  * @SDE_ENC_RC_STATE_OFF: Resource is in OFF state
+ * @SDE_ENC_RC_STATE_PRE_OFF: Resource is transitioning to OFF state
  * @SDE_ENC_RC_STATE_ON: Resource is in ON state
+ * @SDE_ENC_RC_STATE_MODESET: Resource is in modeset state
  * @SDE_ENC_RC_STATE_IDLE: Resource is in IDLE state
  */
 enum sde_enc_rc_states {
 	SDE_ENC_RC_STATE_OFF,
+	SDE_ENC_RC_STATE_PRE_OFF,
 	SDE_ENC_RC_STATE_ON,
+	SDE_ENC_RC_STATE_MODESET,
 	SDE_ENC_RC_STATE_IDLE
 };
 
@@ -162,6 +185,7 @@
  * @disp_info:			local copy of msm_display_info struct
  * @mode_info:			local copy of msm_mode_info struct
  * @misr_enable:		misr enable/disable status
+ * @misr_frame_count:		misr frame count before start capturing the data
  * @idle_pc_supported:		indicate if idle power collaps is supported
  * @rc_lock:			resource control mutex lock to protect
  *				virt encoder over various state changes
@@ -170,7 +194,7 @@
  *				clks and resources after IDLE_TIMEOUT time.
  * @topology:                   topology of the display
  * @mode_set_complete:          flag to indicate modeset completion
- * @rsc_cfg:			rsc configuration
+ * @rsc_config:			rsc configuration for display vtotal, fps, etc.
  * @cur_conn_roi:		current connector roi
  * @prv_conn_roi:		previous connector roi to optimize if unchanged
  */
@@ -206,6 +230,7 @@
 	struct msm_display_info disp_info;
 	struct msm_mode_info mode_info;
 	bool misr_enable;
+	u32 misr_frame_count;
 
 	bool idle_pc_supported;
 	struct mutex rc_lock;
@@ -214,7 +239,7 @@
 	struct msm_display_topology topology;
 	bool mode_set_complete;
 
-	struct sde_encoder_rsc_config rsc_cfg;
+	struct sde_rsc_cmd_config rsc_config;
 	struct sde_rect cur_conn_roi;
 	struct sde_rect prv_conn_roi;
 };
@@ -324,6 +349,8 @@
 	/* return EWOULDBLOCK since we know the wait isn't necessary */
 	if (phys_enc->enable_state == SDE_ENC_DISABLED) {
 		SDE_ERROR_PHYS(phys_enc, "encoder is disabled\n");
+		SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx,
+				irq->irq_idx, intr_idx, SDE_EVTLOG_ERROR);
 		return -EWOULDBLOCK;
 	}
 
@@ -1197,28 +1224,35 @@
 	}
 }
 
-static int sde_encoder_update_rsc_client(
+static int _sde_encoder_update_rsc_client(
 		struct drm_encoder *drm_enc,
 		struct sde_encoder_rsc_config *config, bool enable)
 {
 	struct sde_encoder_virt *sde_enc;
+	struct drm_crtc *crtc;
 	enum sde_rsc_state rsc_state;
-	struct sde_rsc_cmd_config rsc_config;
-	int ret;
+	struct sde_rsc_cmd_config *rsc_config;
+	int ret, prefill_lines;
 	struct msm_display_info *disp_info;
 	struct msm_mode_info *mode_info;
+	int wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID;
+	int wait_count = 0;
+	struct drm_crtc *primary_crtc;
+	int pipe = -1;
 
-	if (!drm_enc) {
-		SDE_ERROR("invalid encoder\n");
+	if (!drm_enc || !drm_enc->crtc || !drm_enc->dev) {
+		SDE_ERROR("invalid arguments\n");
 		return -EINVAL;
 	}
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
+	crtc = drm_enc->crtc;
 	disp_info = &sde_enc->disp_info;
 	mode_info = &sde_enc->mode_info;
+	rsc_config = &sde_enc->rsc_config;
 
 	if (!sde_enc->rsc_client) {
-		SDE_DEBUG("rsc client not created\n");
+		SDE_DEBUG_ENC(sde_enc, "rsc client not created\n");
 		return 0;
 	}
 
@@ -1231,40 +1265,119 @@
 		(((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) &&
 		  disp_info->is_primary) ? SDE_RSC_CMD_STATE :
 		SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
+	prefill_lines = config ? mode_info->prefill_lines +
+		config->inline_rotate_prefill : mode_info->prefill_lines;
 
-	if (config && memcmp(&sde_enc->rsc_cfg, config,
-			sizeof(sde_enc->rsc_cfg)))
+	/* compare specific items and reconfigure the rsc */
+	if ((rsc_config->fps != mode_info->frame_rate) ||
+	    (rsc_config->vtotal != mode_info->vtotal) ||
+	    (rsc_config->prefill_lines != prefill_lines) ||
+	    (rsc_config->jitter_numer != mode_info->jitter_numer) ||
+	    (rsc_config->jitter_denom != mode_info->jitter_denom)) {
+		rsc_config->fps = mode_info->frame_rate;
+		rsc_config->vtotal = mode_info->vtotal;
+		rsc_config->prefill_lines = prefill_lines;
+		rsc_config->jitter_numer = mode_info->jitter_numer;
+		rsc_config->jitter_denom = mode_info->jitter_denom;
 		sde_enc->rsc_state_init = false;
+	}
 
 	if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_init
 					&& disp_info->is_primary) {
-		rsc_config.fps = mode_info->frame_rate;
-		rsc_config.vtotal = mode_info->vtotal;
-		rsc_config.prefill_lines = mode_info->prefill_lines;
-		rsc_config.jitter_numer = mode_info->jitter_numer;
-		rsc_config.jitter_denom = mode_info->jitter_denom;
-		rsc_config.prefill_lines += config ?
-				config->inline_rotate_prefill : 0;
 		/* update it only once */
 		sde_enc->rsc_state_init = true;
-		if (config)
-			sde_enc->rsc_cfg = *config;
 
 		ret = sde_rsc_client_state_update(sde_enc->rsc_client,
-			rsc_state, &rsc_config,
-			drm_enc->crtc ? drm_enc->crtc->index : -1);
+			rsc_state, rsc_config, crtc->base.id,
+			&wait_vblank_crtc_id);
 	} else {
 		ret = sde_rsc_client_state_update(sde_enc->rsc_client,
-			rsc_state, NULL,
-			drm_enc->crtc ? drm_enc->crtc->index : -1);
+			rsc_state, NULL, crtc->base.id,
+			&wait_vblank_crtc_id);
 	}
 
-	if (ret)
-		SDE_ERROR("sde rsc client update failed ret:%d\n", ret);
+	/**
+	 * if RSC performed a state change that requires a VBLANK wait, it will
+	 * set wait_vblank_crtc_id to the CRTC whose VBLANK we must wait on.
+	 *
+	 * if we are the primary display, we will need to enable and wait
+	 * locally since we hold the commit thread
+	 *
+	 * if we are an external display, we must send a signal to the primary
+	 * to enable its VBLANK and wait one, since the RSC hardware is driven
+	 * by the primary panel's VBLANK signals
+	 */
+	SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id);
+	if (ret) {
+		SDE_ERROR_ENC(sde_enc,
+				"sde rsc client update failed ret:%d\n", ret);
+		return ret;
+	} else if (wait_vblank_crtc_id == SDE_RSC_INVALID_CRTC_ID) {
+		return ret;
+	}
+
+	if (crtc->base.id != wait_vblank_crtc_id) {
+		primary_crtc = drm_crtc_find(drm_enc->dev, wait_vblank_crtc_id);
+		if (!primary_crtc) {
+			SDE_ERROR_ENC(sde_enc,
+					"failed to find primary crtc id %d\n",
+					wait_vblank_crtc_id);
+			return -EINVAL;
+		}
+		pipe = drm_crtc_index(primary_crtc);
+	}
+
+	/**
+	 * note: VBLANK is expected to be enabled at this point in
+	 * resource control state machine if on primary CRTC
+	 */
+	for (wait_count = 0; wait_count < MAX_RSC_WAIT; wait_count++) {
+		if (sde_rsc_client_is_state_update_complete(
+				sde_enc->rsc_client))
+			break;
+
+		if (crtc->base.id == wait_vblank_crtc_id)
+			ret = sde_encoder_wait_for_event(drm_enc,
+					MSM_ENC_VBLANK);
+		else
+			drm_wait_one_vblank(drm_enc->dev, pipe);
+
+		if (ret) {
+			SDE_ERROR_ENC(sde_enc,
+					"wait for vblank failed ret:%d\n", ret);
+			break;
+		}
+	}
+
+	if (wait_count >= MAX_RSC_WAIT)
+		SDE_EVT32(DRMID(drm_enc), wait_vblank_crtc_id, wait_count,
+				SDE_EVTLOG_ERROR);
 
 	return ret;
 }
 
+static void _sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable)
+{
+	struct sde_encoder_virt *sde_enc;
+	int i;
+
+	if (!drm_enc) {
+		SDE_ERROR("invalid encoder\n");
+		return;
+	}
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+
+	SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable);
+	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+		if (phys && phys->ops.irq_control)
+			phys->ops.irq_control(phys, enable);
+	}
+
+}
+
 struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *drm_enc)
 {
 	struct sde_encoder_virt *sde_enc;
@@ -1275,14 +1388,43 @@
 	return sde_enc->rsc_client;
 }
 
+static void _sde_encoder_resource_control_rsc_update(
+		struct drm_encoder *drm_enc, bool enable)
+{
+	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+	struct sde_encoder_rsc_config rsc_cfg = { 0 };
+
+	if (enable) {
+		rsc_cfg.inline_rotate_prefill =
+				sde_crtc_get_inline_prefill(drm_enc->crtc);
+
+		/* connect the TE source to actual TE GPIO to drive RSC */
+		_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
+				false);
+
+		_sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
+	} else {
+		_sde_encoder_update_rsc_client(drm_enc, NULL, false);
+
+		/**
+		 * disconnect the TE source from the actual TE GPIO for RSC
+		 *
+		 * this call is for hardware workaround on sdm845 and should
+		 * not be removed without considering the design changes for
+		 * sde rsc + command mode concurrency. It may lead to pp
+		 * timeout due to vsync from panel for command mode panel.
+		 */
+		_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
+				true);
+	}
+}
+
 static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
 		bool enable)
 {
 	struct msm_drm_private *priv;
 	struct sde_kms *sde_kms;
 	struct sde_encoder_virt *sde_enc;
-	struct sde_encoder_rsc_config rsc_cfg = { 0 };
-	int i;
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
 	priv = drm_enc->dev->dev_private;
@@ -1305,43 +1447,11 @@
 		sde_connector_clk_ctrl(sde_enc->cur_master->connector, true);
 
 		/* enable all the irq */
-		for (i = 0; i < sde_enc->num_phys_encs; i++) {
-			struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
-
-			if (phys && phys->ops.irq_control)
-				phys->ops.irq_control(phys, true);
-		}
-
-		rsc_cfg.inline_rotate_prefill =
-				sde_crtc_get_inline_prefill(drm_enc->crtc);
-
-		_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
-									false);
-
-		/* enable RSC */
-		sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
+		_sde_encoder_irq_control(drm_enc, true);
 
 	} else {
-
-		/* disable RSC */
-		sde_encoder_update_rsc_client(drm_enc, NULL, false);
-
-		/**
-		 * this call is for hardware workaround on sdm845 and should
-		 * not be removed without considering the design changes for
-		 * sde rsc + command mode concurrency. It may lead to pp
-		 * timeout due to vsync from panel for command mode panel.
-		 */
-		_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
-									true);
 		/* disable all the irq */
-		for (i = 0; i < sde_enc->num_phys_encs; i++) {
-			struct sde_encoder_phys *phys =
-						sde_enc->phys_encs[i];
-
-			if (phys && phys->ops.irq_control)
-				phys->ops.irq_control(phys, false);
-		}
+		_sde_encoder_irq_control(drm_enc, false);
 
 		/* disable DSI clks */
 		sde_connector_clk_ctrl(sde_enc->cur_master->connector, false);
@@ -1356,12 +1466,12 @@
 static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
 		u32 sw_event)
 {
-	bool schedule_off = false;
 	bool autorefresh_enabled = false;
 	unsigned int lp, idle_timeout;
 	struct sde_encoder_virt *sde_enc;
 	struct msm_drm_private *priv;
 	struct msm_drm_thread *disp_thread;
+	int ret;
 
 	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
 			!drm_enc->crtc) {
@@ -1378,12 +1488,15 @@
 	disp_thread = &priv->disp_thread[drm_enc->crtc->index];
 
 	/*
-	 * when idle_pc is not supported, process only KICKOFF and STOP
-	 * event and return early for other events (ie video mode).
+	 * when idle_pc is not supported, process only KICKOFF, STOP and MODESET
+	 * events and return early for other events (ie video mode).
 	 */
 	if (!sde_enc->idle_pc_supported &&
 			(sw_event != SDE_ENC_RC_EVENT_KICKOFF &&
-				sw_event != SDE_ENC_RC_EVENT_STOP))
+			sw_event != SDE_ENC_RC_EVENT_PRE_MODESET &&
+			sw_event != SDE_ENC_RC_EVENT_POST_MODESET &&
+			sw_event != SDE_ENC_RC_EVENT_STOP &&
+			sw_event != SDE_ENC_RC_EVENT_PRE_STOP))
 		return 0;
 
 	SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc_supported:%d\n", sw_event,
@@ -1407,10 +1520,19 @@
 					sw_event);
 			mutex_unlock(&sde_enc->rc_lock);
 			return 0;
+		} else if (sde_enc->rc_state != SDE_ENC_RC_STATE_OFF &&
+				sde_enc->rc_state != SDE_ENC_RC_STATE_IDLE) {
+			SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc in state %d\n",
+					sw_event, sde_enc->rc_state);
+			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+					SDE_EVTLOG_ERROR);
+			mutex_unlock(&sde_enc->rc_lock);
+			return -EINVAL;
 		}
 
 		/* enable all the clks and resources */
 		_sde_encoder_resource_control_helper(drm_enc, true);
+		_sde_encoder_resource_control_rsc_update(drm_enc, true);
 
 		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
 				SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1);
@@ -1429,6 +1551,8 @@
 		if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
 			SDE_ERROR_ENC(sde_enc, "sw_event:%d,rc:%d-unexpected\n",
 					sw_event, sde_enc->rc_state);
+			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+					SDE_EVTLOG_ERROR);
 			return -EINVAL;
 		}
 
@@ -1472,7 +1596,7 @@
 				sw_event);
 		break;
 
-	case SDE_ENC_RC_EVENT_STOP:
+	case SDE_ENC_RC_EVENT_PRE_STOP:
 		/* cancel delayed off work, if any */
 		if (kthread_cancel_delayed_work_sync(
 				&sde_enc->delayed_off_work))
@@ -1481,79 +1605,128 @@
 
 		mutex_lock(&sde_enc->rc_lock);
 
+		/* skip if is already OFF or IDLE, resources are off already */
+		if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF ||
+				sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in %d state\n",
+					sw_event, sde_enc->rc_state);
+			mutex_unlock(&sde_enc->rc_lock);
+			return 0;
+		}
+
+		/**
+		 * IRQs are still enabled currently, which allows wait for
+		 * VBLANK which RSC may require to correctly transition to OFF
+		 */
+		_sde_encoder_resource_control_rsc_update(drm_enc, false);
+
+		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+				SDE_ENC_RC_STATE_PRE_OFF,
+				SDE_EVTLOG_FUNC_CASE3);
+
+		sde_enc->rc_state = SDE_ENC_RC_STATE_PRE_OFF;
+
+		mutex_unlock(&sde_enc->rc_lock);
+		break;
+
+	case SDE_ENC_RC_EVENT_STOP:
+		mutex_lock(&sde_enc->rc_lock);
+
 		/* return if the resource control is already in OFF state */
 		if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
 			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
 					sw_event);
 			mutex_unlock(&sde_enc->rc_lock);
 			return 0;
+		} else if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON ||
+			   sde_enc->rc_state == SDE_ENC_RC_STATE_MODESET) {
+			SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc in state %d\n",
+					sw_event, sde_enc->rc_state);
+			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+					SDE_EVTLOG_ERROR);
+			mutex_unlock(&sde_enc->rc_lock);
+			return -EINVAL;
 		}
 
-		/*
-		 * disable the clks and resources only if the resource control
-		 * is in ON state, otherwise the clks and resources would have
-		 * been disabled while going into IDLE state
+		/**
+		 * expect to arrive here only if in either idle state or pre-off
+		 * and in IDLE state the resources are already disabled
 		 */
-		if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON)
+		if (sde_enc->rc_state == SDE_ENC_RC_STATE_PRE_OFF)
 			_sde_encoder_resource_control_helper(drm_enc, false);
 
 		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
-				SDE_ENC_RC_STATE_OFF, SDE_EVTLOG_FUNC_CASE3);
+				SDE_ENC_RC_STATE_OFF, SDE_EVTLOG_FUNC_CASE4);
 
 		sde_enc->rc_state = SDE_ENC_RC_STATE_OFF;
 
 		mutex_unlock(&sde_enc->rc_lock);
 		break;
 
-	case SDE_ENC_RC_EVENT_EARLY_WAKE_UP:
+	case SDE_ENC_RC_EVENT_PRE_MODESET:
 		/* cancel delayed off work, if any */
 		if (kthread_cancel_delayed_work_sync(
-				&sde_enc->delayed_off_work)) {
+				&sde_enc->delayed_off_work))
 			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
 					sw_event);
-			schedule_off = true;
-		}
 
 		mutex_lock(&sde_enc->rc_lock);
 
-		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
-				schedule_off, SDE_EVTLOG_FUNC_CASE4);
-
-		/* return if the resource control is in OFF state */
-		if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
-			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
-					sw_event);
-			mutex_unlock(&sde_enc->rc_lock);
-			return 0;
-		}
-
-		/*
-		 * enable all the clks and resources if resource control is
-		 * coming out of IDLE state
-		 */
-		if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
+		/* return if the resource control is already in ON state */
+		if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
+			/* enable all the clks and resources */
 			_sde_encoder_resource_control_helper(drm_enc, true);
+
+			_sde_encoder_resource_control_rsc_update(drm_enc, true);
+
+			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+				SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE5);
 			sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
-			schedule_off = true;
 		}
 
-		/*
-		 * schedule off work when there are no frames pending and
-		 * 1. early wakeup cancelled off work
-		 * 2. early wakeup changed the rc_state to ON - this is to
-		 *	handle cases where early wakeup is called but no
-		 *	frame updates
-		 */
-		if (schedule_off && !sde_crtc_frame_pending(drm_enc->crtc)) {
-			/* schedule delayed off work */
-			kthread_queue_delayed_work(
-					&disp_thread->worker,
-					&sde_enc->delayed_off_work,
-					msecs_to_jiffies(IDLE_TIMEOUT));
-			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
-					sw_event);
+		ret = sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
+		if (ret && ret != -EWOULDBLOCK) {
+			SDE_ERROR_ENC(sde_enc,
+					"wait for commit done returned %d\n",
+					ret);
+			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+					ret, SDE_EVTLOG_ERROR);
+			mutex_unlock(&sde_enc->rc_lock);
+			return -EINVAL;
 		}
 
+		_sde_encoder_irq_control(drm_enc, false);
+
+		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+			SDE_ENC_RC_STATE_MODESET, SDE_EVTLOG_FUNC_CASE5);
+
+		sde_enc->rc_state = SDE_ENC_RC_STATE_MODESET;
+		mutex_unlock(&sde_enc->rc_lock);
+		break;
+
+	case SDE_ENC_RC_EVENT_POST_MODESET:
+		mutex_lock(&sde_enc->rc_lock);
+
+		/* return if the resource control is already in ON state */
+		if (sde_enc->rc_state != SDE_ENC_RC_STATE_MODESET) {
+			SDE_ERROR_ENC(sde_enc,
+					"sw_event:%d, rc:%d !MODESET state\n",
+					sw_event, sde_enc->rc_state);
+			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+					SDE_EVTLOG_ERROR);
+			mutex_unlock(&sde_enc->rc_lock);
+			return -EINVAL;
+		}
+
+		_sde_encoder_irq_control(drm_enc, true);
+
+		_sde_encoder_update_rsc_client(drm_enc, NULL, true);
+
+		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+				SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE6);
+
+		sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
+
 		mutex_unlock(&sde_enc->rc_lock);
 		break;
 
@@ -1561,10 +1734,10 @@
 		mutex_lock(&sde_enc->rc_lock);
 
 		if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
-			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
+			SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
 					sw_event, sde_enc->rc_state);
-			SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event,
-					sde_enc->rc_state);
+			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+					SDE_EVTLOG_ERROR);
 			mutex_unlock(&sde_enc->rc_lock);
 			return 0;
 		}
@@ -1574,19 +1747,20 @@
 		 * ignore the IDLE event, it's probably a stale timer event
 		 */
 		if (sde_enc->frame_busy_mask[0]) {
-			SDE_DEBUG_ENC(sde_enc,
+			SDE_ERROR_ENC(sde_enc,
 					"sw_event:%d, rc:%d frame pending\n",
 					sw_event, sde_enc->rc_state);
-			SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event,
-					sde_enc->rc_state);
+			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+					SDE_EVTLOG_ERROR);
 			mutex_unlock(&sde_enc->rc_lock);
 			return 0;
 		}
 
 		/* disable all the clks and resources */
+		_sde_encoder_resource_control_rsc_update(drm_enc, false);
 		_sde_encoder_resource_control_helper(drm_enc, false);
 		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
-				SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE5);
+				SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE7);
 		sde_enc->rc_state = SDE_ENC_RC_STATE_IDLE;
 
 		mutex_unlock(&sde_enc->rc_lock);
@@ -1667,6 +1841,19 @@
 		}
 	}
 
+	/* release resources before seamless mode change */
+	if (msm_is_mode_seamless_dms(adj_mode)) {
+		/* restore resource state before releasing them */
+		ret = sde_encoder_resource_control(drm_enc,
+				SDE_ENC_RC_EVENT_PRE_MODESET);
+		if (ret) {
+			SDE_ERROR_ENC(sde_enc,
+					"sde resource control failed: %d\n",
+					ret);
+			return;
+		}
+	}
+
 	/* Reserve dynamic resources now. Indicating non-AtomicTest phase */
 	ret = sde_rm_reserve(&sde_kms->rm, drm_enc, drm_enc->crtc->state,
 			conn->state, false);
@@ -1708,6 +1895,11 @@
 		}
 	}
 
+	/* update resources after seamless mode change */
+	if (msm_is_mode_seamless_dms(adj_mode))
+		sde_encoder_resource_control(&sde_enc->base,
+						SDE_ENC_RC_EVENT_POST_MODESET);
+
 	sde_enc->mode_set_complete = true;
 }
 
@@ -1735,6 +1927,12 @@
 		return;
 	}
 
+	if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DisplayPort &&
+	    sde_enc->cur_master->hw_mdptop &&
+	    sde_enc->cur_master->hw_mdptop->ops.intf_audio_select)
+		sde_enc->cur_master->hw_mdptop->ops.intf_audio_select(
+					sde_enc->cur_master->hw_mdptop);
+
 	if (sde_enc->cur_master->hw_mdptop &&
 			sde_enc->cur_master->hw_mdptop->ops.reset_ubwc)
 		sde_enc->cur_master->hw_mdptop->ops.reset_ubwc(
@@ -1784,11 +1982,10 @@
 	}
 	sde_enc = to_sde_encoder_virt(drm_enc);
 	comp_info = &sde_enc->mode_info.comp_info;
+	cur_mode = &sde_enc->base.crtc->state->adjusted_mode;
 
 	SDE_DEBUG_ENC(sde_enc, "\n");
-	SDE_EVT32(DRMID(drm_enc));
-
-	cur_mode = &sde_enc->base.crtc->state->adjusted_mode;
+	SDE_EVT32(DRMID(drm_enc), cur_mode->hdisplay, cur_mode->vdisplay);
 
 	sde_enc->cur_master = NULL;
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
@@ -1832,6 +2029,11 @@
 			else if (phys->ops.enable)
 				phys->ops.enable(phys);
 		}
+
+		if (sde_enc->misr_enable && (sde_enc->disp_info.capabilities &
+		     MSM_DISPLAY_CAP_VID_MODE) && phys->ops.setup_misr)
+			phys->ops.setup_misr(phys, true,
+						sde_enc->misr_frame_count);
 	}
 
 	if (msm_is_mode_seamless_dms(cur_mode) &&
@@ -1869,18 +2071,18 @@
 
 	SDE_EVT32(DRMID(drm_enc));
 
+	/* wait for idle */
+	sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
+
+	sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_PRE_STOP);
+
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
-		if (phys && phys->ops.disable && !phys->ops.is_master(phys)) {
+		if (phys && phys->ops.disable)
 			phys->ops.disable(phys);
-			phys->connector = NULL;
-		}
 	}
 
-	if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
-		sde_enc->cur_master->ops.disable(sde_enc->cur_master);
-
 	/* after phys waits for frame-done, should be no more frames pending */
 	if (atomic_xchg(&sde_enc->frame_done_timeout, 0)) {
 		SDE_ERROR("enc%d timeout pending\n", drm_enc->base.id);
@@ -2737,6 +2939,7 @@
 
 	mutex_lock(&sde_enc->enc_lock);
 	sde_enc->misr_enable = enable;
+	sde_enc->misr_frame_count = frame_count;
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
@@ -3237,6 +3440,13 @@
 		case MSM_ENC_TX_COMPLETE:
 			fn_wait = phys->ops.wait_for_tx_complete;
 			break;
+		case MSM_ENC_VBLANK:
+			fn_wait = phys->ops.wait_for_vblank;
+			break;
+		default:
+			SDE_ERROR_ENC(sde_enc, "unknown wait event %d\n",
+					event);
+			return -EINVAL;
 		};
 
 		if (phys && fn_wait) {
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 7170d55..2098b9f 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -113,6 +113,7 @@
  *				current pending frames to hardware
  * @wait_for_tx_complete:	Wait for hardware to transfer the pixels
  *				to the panel
+ * @wait_for_vblank:		Wait for VBLANK, for sub-driver internal use
  * @prepare_for_kickoff:	Do any work necessary prior to a kickoff
  *				For CMD encoder, may wait for previous tx done
  * @handle_post_kickoff:	Do any work necessary post-kickoff work
@@ -152,6 +153,7 @@
 	int (*control_vblank_irq)(struct sde_encoder_phys *enc, bool enable);
 	int (*wait_for_commit_done)(struct sde_encoder_phys *phys_enc);
 	int (*wait_for_tx_complete)(struct sde_encoder_phys *phys_enc);
+	int (*wait_for_vblank)(struct sde_encoder_phys *phys_enc);
 	void (*prepare_for_kickoff)(struct sde_encoder_phys *phys_enc,
 			struct sde_encoder_kickoff_params *params);
 	void (*handle_post_kickoff)(struct sde_encoder_phys *phys_enc);
@@ -313,10 +315,12 @@
  * @serialize_wait4pp:	serialize wait4pp feature waits for pp_done interrupt
  *			after ctl_start instead of before next frame kickoff
  * @pp_timeout_report_cnt: number of pingpong done irq timeout errors
+ * @autorefresh: autorefresh feature state
  * @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be
  *                      signaled at the next rd_ptr_irq
  * @rd_ptr_timestamp: last rd_ptr_irq timestamp
- * @autorefresh: autorefresh feature state
+ * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
+ * @pending_vblank_wq: Wait queue for blocking until VBLANK received
  */
 struct sde_encoder_phys_cmd {
 	struct sde_encoder_phys base;
@@ -326,6 +330,8 @@
 	struct sde_encoder_phys_cmd_autorefresh autorefresh;
 	atomic_t pending_rd_ptr_cnt;
 	ktime_t rd_ptr_timestamp;
+	atomic_t pending_vblank_cnt;
+	wait_queue_head_t pending_vblank_wq;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index ad00a7f..23604bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -250,6 +250,8 @@
 
 	cmd_enc->rd_ptr_timestamp = ktime_get();
 
+	atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0);
+	wake_up_all(&cmd_enc->pending_vblank_wq);
 	SDE_ATRACE_END("rd_ptr_irq");
 }
 
@@ -599,22 +601,29 @@
 	struct sde_encoder_phys_cmd *cmd_enc =
 		to_sde_encoder_phys_cmd(phys_enc);
 	int ret = 0;
+	int refcount;
 
 	if (!phys_enc) {
 		SDE_ERROR("invalid encoder\n");
 		return -EINVAL;
 	}
 
+	refcount = atomic_read(&phys_enc->vblank_refcount);
+
 	/* Slave encoders don't report vblank */
 	if (!sde_encoder_phys_cmd_is_master(phys_enc))
 		goto end;
 
-	SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n",
-			__builtin_return_address(0),
-			enable, atomic_read(&phys_enc->vblank_refcount));
+	/* protect against negative */
+	if (!enable && refcount == 0) {
+		ret = -EINVAL;
+		goto end;
+	}
 
+	SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n",
+			__builtin_return_address(0), enable, refcount);
 	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
-			enable, atomic_read(&phys_enc->vblank_refcount));
+			enable, refcount);
 
 	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
 		ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR);
@@ -623,10 +632,14 @@
 				INTR_IDX_RDPTR);
 
 end:
-	if (ret)
+	if (ret) {
 		SDE_ERROR_CMDENC(cmd_enc,
-				"control vblank irq error %d, enable %d\n",
-				ret, enable);
+				"control vblank irq error %d, enable %d, refcount %d\n",
+				ret, enable, refcount);
+		SDE_EVT32(DRMID(phys_enc->parent),
+				phys_enc->hw_pp->idx - PINGPONG_0,
+				enable, refcount, SDE_EVTLOG_ERROR);
+	}
 
 	return ret;
 }
@@ -722,6 +735,9 @@
 
 	tc_cfg.vsync_count = vsync_hz / (mode->vtotal * mode->vrefresh);
 
+	/* enable external TE after kickoff to avoid premature autorefresh */
+	tc_cfg.hw_vsync_mode = 0;
+
 	/*
 	 * By setting sync_cfg_height to near max register value, we essentially
 	 * disable sde hw generated TE signal, since hw TE will arrive first.
@@ -733,7 +749,6 @@
 	tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE;
 	tc_cfg.start_pos = mode->vdisplay;
 	tc_cfg.rd_ptr_irq = mode->vdisplay + 1;
-	tc_cfg.hw_vsync_mode = true;
 
 	SDE_DEBUG_CMDENC(cmd_enc,
 		"tc %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n",
@@ -862,37 +877,37 @@
 	return cfg.enable;
 }
 
+static void _sde_encoder_phys_cmd_connect_te(
+		struct sde_encoder_phys *phys_enc, bool enable)
+{
+	if (!phys_enc || !phys_enc->hw_pp ||
+			!phys_enc->hw_pp->ops.connect_external_te)
+		return;
+
+	SDE_EVT32(DRMID(phys_enc->parent), enable);
+	phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable);
+}
+
 static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
 {
 	struct sde_encoder_phys_cmd *cmd_enc =
 		to_sde_encoder_phys_cmd(phys_enc);
-	int ret;
 
 	if (!phys_enc || !phys_enc->hw_pp) {
 		SDE_ERROR("invalid encoder\n");
 		return;
 	}
-	SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
+	SDE_DEBUG_CMDENC(cmd_enc, "pp %d state %d\n",
+			phys_enc->hw_pp->idx - PINGPONG_0,
+			phys_enc->enable_state);
+	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
+			phys_enc->enable_state);
 
 	if (phys_enc->enable_state == SDE_ENC_DISABLED) {
 		SDE_ERROR_CMDENC(cmd_enc, "already disabled\n");
 		return;
 	}
 
-	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0);
-
-	if (!_sde_encoder_phys_is_ppsplit_slave(phys_enc)) {
-		ret = _sde_encoder_phys_cmd_wait_for_idle(phys_enc);
-		if (ret) {
-			atomic_set(&phys_enc->pending_kickoff_cnt, 0);
-			SDE_ERROR_CMDENC(cmd_enc,
-					"pp %d failed wait for idle, %d\n",
-					phys_enc->hw_pp->idx - PINGPONG_0, ret);
-			SDE_EVT32(DRMID(phys_enc->parent),
-					phys_enc->hw_pp->idx - PINGPONG_0, ret);
-		}
-	}
-
 	if (phys_enc->hw_pp->ops.enable_tearcheck)
 		phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, false);
 	phys_enc->enable_state = SDE_ENC_DISABLED;
@@ -1047,6 +1062,34 @@
 	return rc;
 }
 
+static int sde_encoder_phys_cmd_wait_for_vblank(
+		struct sde_encoder_phys *phys_enc)
+{
+	int rc = 0;
+	struct sde_encoder_phys_cmd *cmd_enc;
+	struct sde_encoder_wait_info wait_info;
+
+	if (!phys_enc)
+		return -EINVAL;
+
+	cmd_enc = to_sde_encoder_phys_cmd(phys_enc);
+
+	/* only required for master controller */
+	if (!sde_encoder_phys_cmd_is_master(phys_enc))
+		return rc;
+
+	wait_info.wq = &cmd_enc->pending_vblank_wq;
+	wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt;
+	wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(cmd_enc);
+
+	atomic_inc(&cmd_enc->pending_vblank_cnt);
+
+	rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_RDPTR,
+			&wait_info);
+
+	return rc;
+}
+
 static void sde_encoder_phys_cmd_update_split_role(
 		struct sde_encoder_phys *phys_enc,
 		enum sde_enc_split_role role)
@@ -1132,6 +1175,19 @@
 	SDE_DEBUG_CMDENC(cmd_enc, "disabled autorefresh\n");
 }
 
+static void sde_encoder_phys_cmd_handle_post_kickoff(
+		struct sde_encoder_phys *phys_enc)
+{
+	if (!phys_enc)
+		return;
+
+	/**
+	 * re-enable external TE, either for the first time after enabling
+	 * or if disabled for Autorefresh
+	 */
+	_sde_encoder_phys_cmd_connect_te(phys_enc, true);
+}
+
 static void sde_encoder_phys_cmd_trigger_start(
 		struct sde_encoder_phys *phys_enc)
 {
@@ -1167,6 +1223,7 @@
 	ops->wait_for_commit_done = sde_encoder_phys_cmd_wait_for_commit_done;
 	ops->prepare_for_kickoff = sde_encoder_phys_cmd_prepare_for_kickoff;
 	ops->wait_for_tx_complete = sde_encoder_phys_cmd_wait_for_tx_complete;
+	ops->wait_for_vblank = sde_encoder_phys_cmd_wait_for_vblank;
 	ops->trigger_start = sde_encoder_phys_cmd_trigger_start;
 	ops->needs_single_flush = sde_encoder_phys_cmd_needs_single_flush;
 	ops->hw_reset = sde_encoder_helper_hw_reset;
@@ -1175,6 +1232,7 @@
 	ops->restore = sde_encoder_phys_cmd_enable_helper;
 	ops->is_autorefresh_enabled =
 			sde_encoder_phys_cmd_is_autorefresh_enabled;
+	ops->handle_post_kickoff = sde_encoder_phys_cmd_handle_post_kickoff;
 }
 
 struct sde_encoder_phys *sde_encoder_phys_cmd_init(
@@ -1258,7 +1316,9 @@
 	atomic_set(&phys_enc->pending_ctlstart_cnt, 0);
 	atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
 	atomic_set(&cmd_enc->pending_rd_ptr_cnt, 0);
+	atomic_set(&cmd_enc->pending_vblank_cnt, 0);
 	init_waitqueue_head(&phys_enc->pending_kickoff_wq);
+	init_waitqueue_head(&cmd_enc->pending_vblank_wq);
 	atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0);
 	init_waitqueue_head(&cmd_enc->autorefresh.kickoff_wq);
 
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 933e4812..7850cb7 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -657,7 +657,7 @@
 	hw_res->intfs[vid_enc->hw_intf->idx - INTF_0] = INTF_MODE_VIDEO;
 }
 
-static int sde_encoder_phys_vid_wait_for_vblank(
+static int _sde_encoder_phys_vid_wait_for_vblank(
 		struct sde_encoder_phys *phys_enc, bool notify)
 {
 	struct sde_encoder_wait_info wait_info;
@@ -696,10 +696,10 @@
 	return ret;
 }
 
-static int sde_encoder_phys_vid_wait_for_commit_done(
+static int sde_encoder_phys_vid_wait_for_vblank(
 		struct sde_encoder_phys *phys_enc)
 {
-	return sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
+	return _sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
 }
 
 static void sde_encoder_phys_vid_prepare_for_kickoff(
@@ -781,7 +781,7 @@
 	 * scanout buffer) don't latch properly..
 	 */
 	if (sde_encoder_phys_vid_is_master(phys_enc)) {
-		ret = sde_encoder_phys_vid_wait_for_vblank(phys_enc, false);
+		ret = _sde_encoder_phys_vid_wait_for_vblank(phys_enc, false);
 		if (ret) {
 			atomic_set(&phys_enc->pending_kickoff_cnt, 0);
 			SDE_ERROR_VIDENC(vid_enc,
@@ -866,7 +866,9 @@
 	ops->destroy = sde_encoder_phys_vid_destroy;
 	ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
 	ops->control_vblank_irq = sde_encoder_phys_vid_control_vblank_irq;
-	ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_commit_done;
+	ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_vblank;
+	ops->wait_for_vblank = sde_encoder_phys_vid_wait_for_vblank;
+	ops->wait_for_tx_complete = sde_encoder_phys_vid_wait_for_vblank;
 	ops->prepare_for_kickoff = sde_encoder_phys_vid_prepare_for_kickoff;
 	ops->handle_post_kickoff = sde_encoder_phys_vid_handle_post_kickoff;
 	ops->needs_single_flush = sde_encoder_phys_vid_needs_single_flush;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
index 5cbfe8e..6896ba7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_common_v4.h
@@ -13,10 +13,10 @@
 #define _SDE_HW_COLOR_PROC_COMMON_V4_H_
 
 #define GAMUT_TABLE_SEL_OFF 0x4
-#define GAMUT_SCALEA_OFFSET_OFF 0x10
-#define GAMUT_SCALEB_OFFSET_OFF 0x50
-#define GAMUT_LOWER_COLOR_OFF 0xc
 #define GAMUT_UPPER_COLOR_OFF 0x8
+#define GAMUT_LOWER_COLOR_OFF 0xc
+#define GAMUT_SCALEA_OFFSET_OFF 0x10
+#define GAMUT_SCALEB_OFFSET_OFF 0xe0
 #define GAMUT_TABLE0_SEL BIT(12)
 #define GAMUT_MAP_EN BIT(1)
 #define GAMUT_EN BIT(0)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
index 4da0456..dcfd81d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_color_proc_v4.c
@@ -18,6 +18,7 @@
 		u32 *opcode)
 {
 	u32 reg, tbl_len, tbl_off, scale_off, i, j;
+	u32 scale_tbl_len, scale_tbl_off;
 	u32 *scale_data;
 
 	if (!payload || !opcode || !hw) {
@@ -50,7 +51,7 @@
 		*opcode = gamut_mode_5 << 2;
 		*opcode |= GAMUT_MAP_EN;
 		tbl_len = GAMUT_3D_MODE5_TBL_SZ;
-		tbl_off = 0;
+		tbl_off = GAMUT_MODE_5_OFF;
 		scale_off = GAMUT_SCALEB_OFFSET_OFF;
 		break;
 	default:
@@ -75,12 +76,18 @@
 	}
 
 	if ((*opcode & GAMUT_MAP_EN)) {
-		scale_data = &payload->scale_off[0][0];
-		tbl_off = base + scale_off;
-		tbl_len = GAMUT_3D_SCALE_OFF_TBL_NUM * GAMUT_3D_SCALE_OFF_SZ;
-		for (i = 0; i < tbl_len; i++)
-			SDE_REG_WRITE(hw, tbl_off + (i * sizeof(u32)),
-					scale_data[i]);
+		if (scale_off == GAMUT_SCALEA_OFFSET_OFF)
+			scale_tbl_len = GAMUT_3D_SCALE_OFF_SZ;
+		else
+			scale_tbl_len = GAMUT_3D_SCALEB_OFF_SZ;
+		for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) {
+			scale_tbl_off = base + scale_off + i * scale_tbl_len;
+			scale_data = &payload->scale_off[i][0];
+			for (j = 0; j < scale_tbl_len; j++)
+				SDE_REG_WRITE(hw,
+					scale_tbl_off + (j * sizeof(u32)),
+					scale_data[j]);
+		}
 	}
 	SDE_REG_WRITE(hw, base, *opcode);
 	return 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index e844bc0..e88f40f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -231,6 +231,29 @@
 	return 0;
 }
 
+static int sde_hw_pp_connect_external_te(struct sde_hw_pingpong *pp,
+		bool enable_external_te)
+{
+	struct sde_hw_blk_reg_map *c = &pp->hw;
+	u32 cfg;
+	int orig;
+
+	if (!pp)
+		return -EINVAL;
+
+	c = &pp->hw;
+	cfg = SDE_REG_READ(c, PP_SYNC_CONFIG_VSYNC);
+	orig = (bool)(cfg & BIT(20));
+	if (enable_external_te)
+		cfg |= BIT(20);
+	else
+		cfg &= ~BIT(20);
+	SDE_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg);
+	SDE_EVT32(pp->idx - PINGPONG_0, cfg);
+
+	return orig;
+}
+
 static int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp,
 		struct sde_hw_pp_vsync_info *info)
 {
@@ -257,6 +280,7 @@
 
 	ops->setup_tearcheck = sde_hw_pp_setup_te_config;
 	ops->enable_tearcheck = sde_hw_pp_enable_te;
+	ops->connect_external_te = sde_hw_pp_connect_external_te;
 	ops->get_vsync_info = sde_hw_pp_get_vsync_info;
 	ops->setup_autorefresh = sde_hw_pp_setup_autorefresh_config;
 	ops->setup_dsc = sde_hw_pp_setup_dsc;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
index 4f27ff5..f0a2054 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
@@ -80,6 +80,13 @@
 			bool enable);
 
 	/**
+	 * read, modify, write to either set or clear listening to external TE
+	 * @Return: 1 if TE was originally connected, 0 if not, or -ERROR
+	 */
+	int (*connect_external_te)(struct sde_hw_pingpong *pp,
+			bool enable_external_te);
+
+	/**
 	 * provides the programmed and current
 	 * line_count
 	 */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
index 70427ab..55cb260 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1_color_proc.c
@@ -26,6 +26,7 @@
 		REG_DMA_HEADERS_BUFFER_SZ)
 #define GAMUT_SCALE_OFF_LEN (GAMUT_3D_SCALE_OFF_SZ * \
 		GAMUT_3D_SCALE_OFF_TBL_NUM * sizeof(u32))
+#define GAMUT_SCALE_OFF_LEN_12 (GAMUT_3D_SCALEB_OFF_SZ * sizeof(u32))
 
 #define GC_LUT_MEM_SIZE ((sizeof(struct drm_msm_pgc_lut)) + \
 		REG_DMA_HEADERS_BUFFER_SZ)
@@ -430,6 +431,8 @@
 	struct sde_reg_dma_kickoff_cfg kick_off;
 	struct sde_hw_cp_cfg *hw_cfg = cfg;
 	u32 op_mode, reg, tbl_len, tbl_off, scale_off, i;
+	u32 scale_tbl_len, scale_tbl_off;
+	u32 *scale_data;
 	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
 	struct sde_hw_reg_dma_ops *dma_ops;
 	int rc;
@@ -493,14 +496,24 @@
 	}
 
 	if (op_mode & GAMUT_MAP_EN) {
-		REG_DMA_SETUP_OPS(dma_write_cfg,
-			ctx->cap->sblk->gamut.base + scale_off,
-			payload->scale_off[0], GAMUT_SCALE_OFF_LEN,
-			REG_BLK_WRITE_SINGLE, 0, 0);
-		rc = dma_ops->setup_payload(&dma_write_cfg);
-		if (rc) {
-			DRM_ERROR("write scale/off reg failed ret %d\n", rc);
-			return;
+		if (scale_off == GAMUT_SCALEA_OFFSET_OFF)
+			scale_tbl_len = GAMUT_SCALE_OFF_LEN;
+		else
+			scale_tbl_len = GAMUT_SCALE_OFF_LEN_12;
+
+		for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) {
+			scale_tbl_off = ctx->cap->sblk->gamut.base + scale_off +
+					(i * scale_tbl_len);
+			scale_data = &payload->scale_off[i][0];
+			REG_DMA_SETUP_OPS(dma_write_cfg, scale_tbl_off,
+					scale_data, scale_tbl_len,
+					REG_BLK_WRITE_SINGLE, 0, 0);
+			rc = dma_ops->setup_payload(&dma_write_cfg);
+			if (rc) {
+				DRM_ERROR("write scale/off reg failed ret %d\n",
+						rc);
+				return;
+			}
 		}
 	}
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index bbd5931..1a00517 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -62,6 +62,16 @@
 }
 
 /**
+ * _sde_hw_rot_reg_dump - perform register dump
+ * @ptr: private pointer to rotator platform device
+ * return: None
+ */
+static void _sde_hw_rot_reg_dump(void *ptr)
+{
+	sde_rotator_inline_reg_dump((struct platform_device *) ptr);
+}
+
+/**
  * sde_hw_rot_start - start rotator before any commit
  * @hw: Pointer to rotator hardware driver
  * return: 0 if success; error code otherwise
@@ -78,6 +88,10 @@
 
 	pdev = hw->caps->pdev;
 
+	rc = sde_dbg_reg_register_cb(hw->name, _sde_hw_rot_reg_dump, pdev);
+	if (rc)
+		SDE_ERROR("failed to register debug dump %d\n", rc);
+
 	hw->rot_ctx = sde_rotator_inline_open(pdev);
 	if (IS_ERR_OR_NULL(hw->rot_ctx)) {
 		rc = PTR_ERR(hw->rot_ctx);
@@ -95,13 +109,16 @@
  */
 static void sde_hw_rot_stop(struct sde_hw_rot *hw)
 {
-	if (!hw) {
+	if (!hw || !hw->caps || !hw->caps->pdev) {
 		SDE_ERROR("invalid parameter\n");
 		return;
 	}
 
 	sde_rotator_inline_release(hw->rot_ctx);
 	hw->rot_ctx = NULL;
+
+	sde_dbg_reg_unregister_cb(hw->name, _sde_hw_rot_reg_dump,
+			hw->caps->pdev);
 }
 
 /**
@@ -576,6 +593,7 @@
 		return -EINVAL;
 	}
 
+	rot_cmd.sequence_id = data->sequence_id;
 	rot_cmd.video_mode = data->video_mode;
 	rot_cmd.fps = data->fps;
 
@@ -667,10 +685,8 @@
 				hw_cmd);
 
 		rc = sde_rotator_inline_commit(hw->rot_ctx, &rot_cmd, cmd_type);
-		if (rc) {
-			SDE_ERROR("failed to commit inline rotation %d\n", rc);
+		if (rc)
 			return rc;
-		}
 
 		/* return to caller */
 		data->priv_handle = rot_cmd.priv_handle;
@@ -899,6 +915,7 @@
 	c->idx = idx;
 	c->caps = cfg;
 	_setup_rot_ops(&c->ops, c->caps->features);
+	snprintf(c->name, ARRAY_SIZE(c->name), "sde_rot_%d", idx - ROT_0);
 
 	rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx, &sde_hw_rot_ops);
 	if (rc) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.h b/drivers/gpu/drm/msm/sde/sde_hw_rot.h
index e490052..1237858 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.h
@@ -18,6 +18,8 @@
 #include "sde_hw_util.h"
 #include "sde_hw_blk.h"
 
+#define SDE_HW_ROT_NAME_SIZE	80
+
 struct sde_hw_rot;
 
 /**
@@ -137,6 +139,7 @@
 struct sde_hw_rot {
 	struct sde_hw_blk base;
 	struct sde_hw_blk_reg_map hw;
+	char name[SDE_HW_ROT_NAME_SIZE];
 	int idx;
 	const struct sde_rot_cfg *caps;
 	struct sde_hw_rot_ops ops;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index 613ac53..ecb445d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -348,6 +348,18 @@
 	SDE_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static);
 }
 
+static void sde_hw_intf_audio_select(struct sde_hw_mdp *mdp)
+{
+	struct sde_hw_blk_reg_map *c;
+
+	if (!mdp)
+		return;
+
+	c = &mdp->hw;
+
+	SDE_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1);
+}
+
 static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
 		unsigned long cap)
 {
@@ -360,6 +372,7 @@
 	ops->get_safe_status = sde_hw_get_safe_status;
 	ops->setup_dce = sde_hw_setup_dce;
 	ops->reset_ubwc = sde_hw_reset_ubwc;
+	ops->intf_audio_select = sde_hw_intf_audio_select;
 }
 
 static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index 86c4219..0ca5af9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -182,6 +182,12 @@
 	 * @m: pointer to mdss catalog data
 	 */
 	void (*reset_ubwc)(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m);
+
+	/**
+	 * intf_audio_select - select the external interface for audio
+	 * @mdp: mdp top context driver
+	 */
+	void (*intf_audio_select)(struct sde_hw_mdp *mdp);
 };
 
 struct sde_hw_mdp {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
index 9e6a246..90a2ca9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
@@ -33,11 +33,34 @@
 #define VBIF_OUT_WR_LIM_CONF0		0x00D4
 #define VBIF_OUT_AXI_AMEMTYPE_CONF0	0x0160
 #define VBIF_OUT_AXI_AMEMTYPE_CONF1	0x0164
+#define VBIF_XIN_PND_ERR		0x0190
+#define VBIF_XIN_SRC_ERR		0x0194
+#define VBIF_XIN_CLR_ERR		0x019C
 #define VBIF_XIN_HALT_CTRL0		0x0200
 #define VBIF_XIN_HALT_CTRL1		0x0204
 #define VBIF_XINL_QOS_RP_REMAP_000	0x0550
 #define VBIF_XINL_QOS_LVL_REMAP_000	0x0590
 
+static void sde_hw_clear_errors(struct sde_hw_vbif *vbif,
+		u32 *pnd_errors, u32 *src_errors)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 pnd, src;
+
+	if (!vbif)
+		return;
+	c = &vbif->hw;
+	pnd = SDE_REG_READ(c, VBIF_XIN_PND_ERR);
+	src = SDE_REG_READ(c, VBIF_XIN_SRC_ERR);
+
+	if (pnd_errors)
+		*pnd_errors = pnd;
+	if (src_errors)
+		*src_errors = src;
+
+	SDE_REG_WRITE(c, VBIF_XIN_CLR_ERR, pnd | src);
+}
+
 static void sde_hw_set_mem_type(struct sde_hw_vbif *vbif,
 		u32 xin_id, u32 value)
 {
@@ -192,6 +215,7 @@
 	if (test_bit(SDE_VBIF_QOS_REMAP, &cap))
 		ops->set_qos_remap = sde_hw_set_qos_remap;
 	ops->set_mem_type = sde_hw_set_mem_type;
+	ops->clear_errors = sde_hw_clear_errors;
 	ops->set_write_gather_en = sde_hw_set_write_gather_en;
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
index 81cb9d6..84f0e04 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
@@ -82,6 +82,18 @@
 			u32 xin_id, u32 value);
 
 	/**
+	 * clear_errors - clear any vbif errors
+	 *	This function clears any detected pending/source errors
+	 *	on the VBIF interface, and optionally returns the detected
+	 *	error mask(s).
+	 * @vbif: vbif context driver
+	 * @pnd_errors: pointer to pending error reporting variable
+	 * @src_errors: pointer to source error reporting variable
+	 */
+	void (*clear_errors)(struct sde_hw_vbif *vbif,
+		u32 *pnd_errors, u32 *src_errors);
+
+	/**
 	 * set_write_gather_en - set write_gather enable
 	 * @vbif: vbif context driver
 	 * @xin_id: client interface identifier
diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h
index c95bace..cc020d9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hwio.h
+++ b/drivers/gpu/drm/msm/sde/sde_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, 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
@@ -52,6 +52,7 @@
 #define SPLIT_DISPLAY_LOWER_PIPE_CTRL   0x3F0
 #define SPLIT_DISPLAY_TE_LINE_INTERVAL  0x3F4
 #define INTF_SW_RESET_MASK              0x3FC
+#define HDMI_DP_CORE_SELECT             0x408
 #define MDP_OUT_CTL_0                   0x410
 #define MDP_VSYNC_SEL                   0x414
 #define DCE_SEL                         0x450
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 1affa9c..bd2d56c 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1575,14 +1575,13 @@
  *	enumerating over all planes attached to the same rotator
  * @plane: Pointer to drm plane
  * @state: Pointer to drm state to be updated
- * return: none
+ * return: 0 if success; error code otherwise
  */
-static void sde_plane_rot_calc_cfg(struct drm_plane *plane,
+static int sde_plane_rot_calc_cfg(struct drm_plane *plane,
 		struct drm_plane_state *state)
 {
 	struct sde_plane_state *pstate;
 	struct sde_plane_rot_state *rstate;
-	struct sde_hw_blk *hw_blk;
 	struct drm_crtc_state *cstate;
 	struct drm_rect *in_rot, *out_rot;
 	struct drm_plane *attached_plane;
@@ -1593,24 +1592,19 @@
 
 	if (!plane || !state || !state->state) {
 		SDE_ERROR("invalid parameters\n");
-		return;
+		return -EINVAL;
 	}
 
 	cstate = _sde_plane_get_crtc_state(state);
 	if (IS_ERR_OR_NULL(cstate)) {
 		ret = PTR_ERR(cstate);
 		SDE_ERROR("invalid crtc state %d\n", ret);
-		return;
+		return ret;
 	}
 
 	pstate = to_sde_plane_state(state);
 	rstate = &pstate->rot;
 
-	if (!rstate->rot_hw) {
-		SDE_ERROR("invalid rotator hw\n");
-		return;
-	}
-
 	in_rot = &rstate->in_rot_rect;
 	in_rot->x1 = state->src_x;
 	in_rot->y1 = state->src_y;
@@ -1636,8 +1630,6 @@
 
 	rstate->out_src_rect = rstate->out_rot_rect;
 
-	hw_blk = &rstate->rot_hw->base;
-
 	/* enumerating over all planes attached to the same rotator */
 	drm_atomic_crtc_state_for_each_plane(attached_plane, cstate) {
 		struct drm_plane_state *attached_state;
@@ -1710,6 +1702,71 @@
 			attached_out_rect.y2 = dst_y + dst_h;
 		}
 
+		/* check source split left/right mismatch */
+		if (attached_out_rect.y1 != rstate->out_src_rect.y1 ||
+			attached_out_rect.y2 != rstate->out_src_rect.y2) {
+			SDE_ERROR(
+				"plane%d.%u src:%dx%d+%d+%d rot:0x%llx fb:%d plane%d.%u src:%dx%d+%d+%d rot:0x%llx fb:%d mismatch\n",
+					plane->base.id,
+					rstate->sequence_id,
+					state->src_w >> 16,
+					state->src_h >> 16,
+					state->src_x >> 16,
+					state->src_y >> 16,
+					sde_plane_get_property(pstate,
+							PLANE_PROP_ROTATION),
+					state->fb ?
+						state->fb->base.id :
+						-1,
+					attached_plane->base.id,
+					attached_rstate->sequence_id,
+					attached_state->src_w >> 16,
+					attached_state->src_h >> 16,
+					attached_state->src_x >> 16,
+					attached_state->src_y >> 16,
+					sde_plane_get_property(attached_pstate,
+							PLANE_PROP_ROTATION),
+					attached_state->fb ?
+						attached_state->fb->base.id :
+						-1);
+			SDE_ERROR(
+				"plane%d.%u sspp:%dx%d+%d+%d plane%d.%u sspp:%dx%d+%d+%d\n",
+					plane->base.id,
+					rstate->sequence_id,
+					(rstate->out_src_rect.x2 -
+						rstate->out_src_rect.x1) >> 16,
+					(rstate->out_src_rect.y2 -
+						rstate->out_src_rect.y1) >> 16,
+					rstate->out_src_rect.x1 >> 16,
+					rstate->out_src_rect.y1 >> 16,
+					attached_plane->base.id,
+					attached_rstate->sequence_id,
+					(attached_out_rect.x2 -
+						attached_out_rect.x1) >> 16,
+					(attached_out_rect.y2 -
+						attached_out_rect.y1) >> 16,
+					attached_out_rect.x1 >> 16,
+					attached_out_rect.y1 >> 16);
+			SDE_EVT32(DRMID(plane),
+					rstate->sequence_id,
+					rstate->out_src_rect.x1 >> 16,
+					rstate->out_src_rect.y1 >> 16,
+					(rstate->out_src_rect.x2 -
+						rstate->out_src_rect.x1) >> 16,
+					(rstate->out_src_rect.y2 -
+						rstate->out_src_rect.y1) >> 16,
+					attached_plane->base.id,
+					attached_rstate->sequence_id,
+					attached_out_rect.x1 >> 16,
+					attached_out_rect.y1 >> 16,
+					(attached_out_rect.x2 -
+						attached_out_rect.x1) >> 16,
+					(attached_out_rect.y2 -
+						attached_out_rect.y1) >> 16,
+					SDE_EVTLOG_ERROR);
+			return -EINVAL;
+		}
+
 		/* find relative sspp position */
 		if (attached_out_rect.x1 < rstate->out_src_rect.x1)
 			xpos++;
@@ -1753,7 +1810,7 @@
 			drm_rect_height(&rstate->out_rot_rect) >> 16,
 			rstate->out_rot_rect.x1 >> 16,
 			rstate->out_rot_rect.y1 >> 16);
-	SDE_EVT32_VERBOSE(DRMID(plane), rstate->sequence_id,
+	SDE_EVT32(DRMID(plane), rstate->sequence_id,
 			rstate->out_xpos, rstate->nplane,
 			in_rot->x1 >> 16, in_rot->y1 >> 16,
 			drm_rect_width(in_rot) >> 16,
@@ -1762,6 +1819,8 @@
 			rstate->out_rot_rect.y1 >> 16,
 			drm_rect_width(&rstate->out_rot_rect) >> 16,
 			drm_rect_height(&rstate->out_rot_rect) >> 16);
+
+	return 0;
 }
 
 /**
@@ -1840,8 +1899,8 @@
 	rot_cmd->src_rect_y = rstate->in_rot_rect.y1 >> 16;
 	rot_cmd->src_rect_w = drm_rect_width(&rstate->in_rot_rect) >> 16;
 	rot_cmd->src_rect_h = drm_rect_height(&rstate->in_rot_rect) >> 16;
-	rot_cmd->dst_rect_x = rstate->out_rot_rect.x1 >> 16;
-	rot_cmd->dst_rect_y = rstate->out_rot_rect.y1 >> 16;
+	rot_cmd->dst_rect_x = 0;
+	rot_cmd->dst_rect_y = 0;
 	rot_cmd->dst_rect_w = drm_rect_width(&rstate->out_rot_rect) >> 16;
 	rot_cmd->dst_rect_h = drm_rect_height(&rstate->out_rot_rect) >> 16;
 
@@ -1886,10 +1945,8 @@
 	}
 
 	ret = rstate->rot_hw->ops.commit(rstate->rot_hw, rot_cmd, hw_cmd);
-	if (ret) {
-		SDE_ERROR("failed to commit rotator %d\n", ret);
+	if (ret)
 		return ret;
-	}
 
 	rstate->out_rotation = rstate->in_rotation;
 	rstate->out_fb_flags = rot_cmd->dst_modifier ?
@@ -2017,7 +2074,9 @@
 	}
 
 	/* need to re-calc based on all newly validated plane states */
-	sde_plane_rot_calc_cfg(plane, new_state);
+	ret = sde_plane_rot_calc_cfg(plane, new_state);
+	if (ret)
+		return ret;
 
 	/* check if stream buffer is already attached to rotator */
 	if (sde_plane_enabled(new_state) && !new_rstate->out_fb)
@@ -2222,6 +2281,8 @@
 			SDE_ERROR("plane%d.%d no available rotator, fb %d\n",
 					plane->base.id, rstate->sequence_id,
 					state->fb ? state->fb->base.id : -1);
+			SDE_EVT32(DRMID(plane), rstate->sequence_id,
+					SDE_EVTLOG_ERROR);
 			return -EINVAL;
 		}
 
@@ -2249,13 +2310,20 @@
 		SDE_DEBUG("plane%d.%d use rotator, fb %d\n",
 				plane->base.id, rstate->sequence_id, fb_id);
 
-		sde_plane_rot_calc_cfg(plane, state);
+		ret = sde_plane_rot_calc_cfg(plane, state);
+		if (ret)
+			return ret;
 
 		ret = sde_plane_rot_submit_command(plane, state,
 				SDE_HW_ROT_CMD_VALIDATE);
 		if (ret)
 			return ret;
 
+		if (rstate->nplane != old_rstate->nplane ||
+				rstate->out_xpos != old_rstate->out_xpos)
+			pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
+				SDE_PLANE_DIRTY_RECTS;
+
 		/* check if stream buffer is already attached to rotator */
 		_sde_plane_rot_get_fb(plane, cstate, rstate);
 
@@ -2353,16 +2421,18 @@
 	sde_plane_rot_submit_command(plane, state, SDE_HW_ROT_CMD_COMMIT);
 }
 
-/**
- * sde_plane_rot_flush - perform final flush related rotator options
- * @plane: Pointer to drm plane
- * @pstate: Pointer to sde plane state
- */
-static void sde_plane_rot_flush(struct drm_plane *plane,
-		struct sde_plane_state *pstate)
+void sde_plane_kickoff(struct drm_plane *plane)
 {
-	if (!plane || !pstate || !pstate->rot.rot_hw ||
-			!pstate->rot.rot_hw->ops.commit)
+	struct sde_plane_state *pstate;
+
+	if (!plane || !plane->state) {
+		SDE_ERROR("invalid plane\n");
+		return;
+	}
+
+	pstate = to_sde_plane_state(plane->state);
+
+	if (!pstate->rot.rot_hw || !pstate->rot.rot_hw->ops.commit)
 		return;
 
 	pstate->rot.rot_hw->ops.commit(pstate->rot.rot_hw,
@@ -3140,10 +3210,6 @@
 	return ret;
 }
 
-/**
- * sde_plane_flush - final plane operations before commit flush
- * @plane: Pointer to drm plane structure
- */
 void sde_plane_flush(struct drm_plane *plane)
 {
 	struct sde_plane *psde;
@@ -3177,9 +3243,6 @@
 	/* flag h/w flush complete */
 	if (plane->state)
 		pstate->pending = false;
-
-	/* signal inline rotator start */
-	sde_plane_rot_flush(plane, pstate);
 }
 
 static int sde_plane_sspp_atomic_update(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index a5599a5..325d342 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -227,6 +227,12 @@
 void sde_plane_flush(struct drm_plane *plane);
 
 /**
+ * sde_plane_kickoff - final plane operations before commit kickoff
+ * @plane: Pointer to drm plane structure
+ */
+void sde_plane_kickoff(struct drm_plane *plane);
+
+/**
  * sde_plane_init - create new sde plane for the given pipe
  * @dev:   Pointer to DRM device
  * @pipe:  sde hardware pipe identifier
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index 47fc39b..19cda3e 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -179,7 +179,7 @@
 			memset(&__entry->data[cnt], 0,
 				(SDE_TRACE_EVTLOG_SIZE - cnt) * sizeof(u32));
 	),
-	TP_printk("%d|%s:%d|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
+	TP_printk("%d|%s:%d|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x",
 			__entry->pid, __get_str(evtlog_tag),
 			__entry->tag_id,
 			__entry->data[0], __entry->data[1],
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.c b/drivers/gpu/drm/msm/sde/sde_vbif.c
index d31f828..7fcd03e 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.c
@@ -269,6 +269,29 @@
 		mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
 }
 
+void sde_vbif_clear_errors(struct sde_kms *sde_kms)
+{
+	struct sde_hw_vbif *vbif;
+	u32 i, pnd, src;
+
+	if (!sde_kms) {
+		SDE_ERROR("invalid argument\n");
+		return;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
+		vbif = sde_kms->hw_vbif[i];
+		if (vbif && vbif->ops.clear_errors) {
+			vbif->ops.clear_errors(vbif, &pnd, &src);
+			if (pnd || src) {
+				SDE_EVT32(i, pnd, src);
+				SDE_DEBUG("VBIF %d: pnd 0x%X, src 0x%X\n",
+						vbif->idx - VBIF_0, pnd, src);
+			}
+		}
+	}
+}
+
 void sde_vbif_init_memtypes(struct sde_kms *sde_kms)
 {
 	struct sde_hw_vbif *vbif;
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.h b/drivers/gpu/drm/msm/sde/sde_vbif.h
index f1da68b1..a4830a0 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.h
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.h
@@ -67,6 +67,12 @@
 		struct sde_vbif_set_qos_params *params);
 
 /**
+ * sde_vbif_clear_errors - clear any vbif errors
+ * @sde_kms:	SDE handler
+ */
+void sde_vbif_clear_errors(struct sde_kms *sde_kms);
+
+/**
  * sde_vbif_init_memtypes - initialize xin memory types for vbif
  * @sde_kms:	SDE handler
  */
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 58069f2..7e58c2f 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -106,6 +106,8 @@
  * @buf: buffer used for manual register dumping
  * @buf_len:  buffer length used for manual register dumping
  * @reg_dump: address for the mem dump if no ranges used
+ * @cb: callback for external dump function, null if not defined
+ * @cb_ptr: private pointer to callback function
  */
 struct sde_dbg_reg_base {
 	struct list_head reg_base_head;
@@ -118,6 +120,8 @@
 	char *buf;
 	size_t buf_len;
 	u32 *reg_dump;
+	void (*cb)(void *ptr);
+	void *cb_ptr;
 };
 
 struct sde_debug_bus_entry {
@@ -2144,16 +2148,17 @@
 	size_t len;
 	struct sde_dbg_reg_range *range_node;
 
-	if (!dbg || !dbg->base) {
+	if (!dbg || !(dbg->base || dbg->cb)) {
 		pr_err("dbg base is null!\n");
 		return;
 	}
 
 	dev_info(sde_dbg_base.dev, "%s:=========%s DUMP=========\n", __func__,
 			dbg->name);
-
+	if (dbg->cb) {
+		dbg->cb(dbg->cb_ptr);
 	/* If there is a list to dump the registers by ranges, use the ranges */
-	if (!list_empty(&dbg->sub_range_list)) {
+	} else if (!list_empty(&dbg->sub_range_list)) {
 		/* sort the list by start address first */
 		list_sort(NULL, &dbg->sub_range_list, _sde_dump_reg_range_cmp);
 		list_for_each_entry(range_node, &dbg->sub_range_list, head) {
@@ -2302,10 +2307,14 @@
 				mem_base + head->wr_addr);
 		wmb(); /* make sure test bits were written */
 
-		if (bus->cmn.flags & DBGBUS_FLAGS_DSPP)
+		if (bus->cmn.flags & DBGBUS_FLAGS_DSPP) {
 			offset = DBGBUS_DSPP_STATUS;
-		else
+			/* keep DSPP test point enabled */
+			if (head->wr_addr != DBGBUS_DSPP)
+				writel_relaxed(0xF, mem_base + DBGBUS_DSPP);
+		} else {
 			offset = head->wr_addr + 0x4;
+		}
 
 		status = readl_relaxed(mem_base + offset);
 
@@ -2327,7 +2336,9 @@
 
 		/* Disable debug bus once we are done */
 		writel_relaxed(0, mem_base + head->wr_addr);
-
+		if (bus->cmn.flags & DBGBUS_FLAGS_DSPP &&
+						head->wr_addr != DBGBUS_DSPP)
+			writel_relaxed(0x0, mem_base + DBGBUS_DSPP);
 	}
 	_sde_dbg_enable_power(false);
 
@@ -3179,6 +3190,60 @@
 	return 0;
 }
 
+int sde_dbg_reg_register_cb(const char *name, void (*cb)(void *), void *ptr)
+{
+	struct sde_dbg_base *dbg_base = &sde_dbg_base;
+	struct sde_dbg_reg_base *reg_base;
+
+	if (!name || !strlen(name)) {
+		pr_err("no debug name provided\n");
+		return -EINVAL;
+	}
+
+	reg_base = kzalloc(sizeof(*reg_base), GFP_KERNEL);
+	if (!reg_base)
+		return -ENOMEM;
+
+	strlcpy(reg_base->name, name, sizeof(reg_base->name));
+	reg_base->base = NULL;
+	reg_base->max_offset = 0;
+	reg_base->off = 0;
+	reg_base->cnt = DEFAULT_BASE_REG_CNT;
+	reg_base->reg_dump = NULL;
+	reg_base->cb = cb;
+	reg_base->cb_ptr = ptr;
+
+	/* Initialize list to make sure check for null list will be valid */
+	INIT_LIST_HEAD(&reg_base->sub_range_list);
+
+	pr_debug("%s cb: %pK cb_ptr: %pK\n", reg_base->name,
+			reg_base->cb, reg_base->cb_ptr);
+
+	list_add(&reg_base->reg_base_head, &dbg_base->reg_base_list);
+
+	return 0;
+}
+
+void sde_dbg_reg_unregister_cb(const char *name, void (*cb)(void *), void *ptr)
+{
+	struct sde_dbg_base *dbg_base = &sde_dbg_base;
+	struct sde_dbg_reg_base *reg_base;
+
+	if (!dbg_base)
+		return;
+
+	list_for_each_entry(reg_base, &dbg_base->reg_base_list, reg_base_head) {
+		if (strlen(reg_base->name) &&
+			!strcmp(reg_base->name, name)) {
+			pr_debug("%s cb: %pK cb_ptr: %pK\n", reg_base->name,
+					reg_base->cb, reg_base->cb_ptr);
+			list_del(&reg_base->reg_base_head);
+			kfree(reg_base);
+			break;
+		}
+	}
+}
+
 void sde_dbg_reg_register_dump_range(const char *base_name,
 		const char *range_name, u32 offset_start, u32 offset_end,
 		uint32_t xin_id)
diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h
index e14d60e..a266574 100644
--- a/drivers/gpu/drm/msm/sde_dbg.h
+++ b/drivers/gpu/drm/msm/sde_dbg.h
@@ -25,6 +25,11 @@
 #define SDE_EVTLOG_FUNC_CASE3	0x5555
 #define SDE_EVTLOG_FUNC_CASE4	0x6666
 #define SDE_EVTLOG_FUNC_CASE5	0x7777
+#define SDE_EVTLOG_FUNC_CASE6	0x8888
+#define SDE_EVTLOG_FUNC_CASE7	0x9999
+#define SDE_EVTLOG_FUNC_CASE8	0xaaaa
+#define SDE_EVTLOG_FUNC_CASE9	0xbbbb
+#define SDE_EVTLOG_FUNC_CASE10	0xcccc
 #define SDE_EVTLOG_PANIC	0xdead
 #define SDE_EVTLOG_FATAL	0xbad
 #define SDE_EVTLOG_ERROR	0xebad
@@ -251,6 +256,26 @@
 		size_t max_offset);
 
 /**
+ * sde_dbg_reg_register_cb - register a hw register callback for later
+ *	dumping.
+ * @name:	name of base region
+ * @cb:		callback of external region
+ * @cb_ptr:	private pointer of external region
+ * Returns:	0 or -ERROR
+ */
+int sde_dbg_reg_register_cb(const char *name, void (*cb)(void *), void *ptr);
+
+/**
+ * sde_dbg_reg_unregister_cb - register a hw unregister callback for later
+ *	dumping.
+ * @name:	name of base region
+ * @cb:		callback of external region
+ * @cb_ptr:	private pointer of external region
+ * Returns:	None
+ */
+void sde_dbg_reg_unregister_cb(const char *name, void (*cb)(void *), void *ptr);
+
+/**
  * sde_dbg_reg_register_dump_range - register a hw register sub-region for
  *	later register dumping associated with base specified by
  *	sde_dbg_reg_register_base
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 28a2d4d..e5c83cb 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -76,7 +76,7 @@
 
 	if (phandle->rsc_client)
 		ret = sde_rsc_client_state_update(phandle->rsc_client,
-			rsc_state, NULL, -1);
+			rsc_state, NULL, SDE_RSC_INVALID_CRTC_ID, NULL);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index 4fc40d9..7a52ece 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -58,12 +58,8 @@
 #define TRY_CLK_MODE_SWITCH		0xFFFE
 #define STATE_UPDATE_NOT_ALLOWED	0xFFFD
 
-/**
- * Expected primary command mode panel vsync ranges
- * Note: update if a primary panel is expected to run lower than 60fps
- */
-#define PRIMARY_VBLANK_MIN_US (18 * 1000)
-#define PRIMARY_VBLANK_MAX_US (20 * 1000)
+/* Primary panel worst case VSYNC expected to be no less than 30fps */
+#define PRIMARY_VBLANK_WORST_CASE_MS 34
 
 static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT];
 
@@ -153,9 +149,22 @@
 	state = client->current_state;
 	mutex_unlock(&rsc->client_lock);
 
-	if (state != SDE_RSC_IDLE_STATE)
-		sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE,
-								NULL, -1);
+	if (state != SDE_RSC_IDLE_STATE) {
+		int wait_vblank_crtc_id;
+
+		sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE, NULL,
+				SDE_RSC_INVALID_CRTC_ID, &wait_vblank_crtc_id);
+
+		/* if vblank wait required at shutdown, use a simple sleep */
+		if (wait_vblank_crtc_id != SDE_RSC_INVALID_CRTC_ID) {
+			pr_err("unexpected sleep required on crtc %d at rsc client destroy\n",
+					wait_vblank_crtc_id);
+			SDE_EVT32(client->id, state, rsc->current_state,
+					client->crtc_id, wait_vblank_crtc_id,
+					SDE_EVTLOG_ERROR);
+			msleep(PRIMARY_VBLANK_WORST_CASE_MS);
+		}
+	}
 	mutex_lock(&rsc->client_lock);
 	list_del_init(&client->list);
 	mutex_unlock(&rsc->client_lock);
@@ -395,7 +404,13 @@
 	/* mode 2 is infinite */
 	rsc->timer_config.rsc_time_slot_2_ns = 0xFFFFFFFF;
 
-	if (rsc->hw_ops.init) {
+	/* timer update should be called with client call */
+	if (cmd_config && rsc->hw_ops.timer_update) {
+		ret = rsc->hw_ops.timer_update(rsc);
+		if (ret)
+			pr_err("sde rsc: hw timer update failed ret:%d\n", ret);
+	/* rsc init should be called during rsc probe - one time only */
+	} else if (rsc->hw_ops.init) {
 		ret = rsc->hw_ops.init(rsc);
 		if (ret)
 			pr_err("sde rsc: hw init failed ret:%d\n", ret);
@@ -449,7 +464,8 @@
 
 static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
 	struct sde_rsc_cmd_config *config,
-	struct sde_rsc_client *caller_client)
+	struct sde_rsc_client *caller_client,
+	int *wait_vblank_crtc_id)
 {
 	struct sde_rsc_client *client;
 	int rc = STATE_UPDATE_NOT_ALLOWED;
@@ -469,9 +485,19 @@
 	if (config)
 		sde_rsc_timer_calculate(rsc, config);
 
+	/**
+	 * rsc clients can still send config at any time. If a config is
+	 * received during cmd_state then vsync_wait will execute with the logic
+	 * below. If a config is received when rsc is in AMC mode; A mode
+	 * switch will do the vsync wait. updated checks still support all cases
+	 * for dynamic mode switch and inline rotation.
+	 */
 	if (rsc->current_state == SDE_RSC_CMD_STATE) {
 		rc = 0;
-		goto vsync_wait;
+		if (config)
+			goto vsync_wait;
+		else
+			goto end;
 	}
 
 	/* any one client in video state blocks the cmd state switch */
@@ -486,15 +512,29 @@
 	}
 
 vsync_wait:
-	/* wait for vsync for vid to cmd state switch and config update */
+	/* indicate wait for vsync for vid to cmd state switch & cfg update */
 	if (!rc && (rsc->current_state == SDE_RSC_VID_STATE ||
-			rsc->current_state == SDE_RSC_CMD_STATE))
-		usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
+			rsc->current_state == SDE_RSC_CMD_STATE)) {
+		/* clear VSYNC timestamp for indication when update completes */
+		if (rsc->hw_ops.hw_vsync)
+			rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
+		if (!wait_vblank_crtc_id) {
+			pr_err("invalid crtc id wait pointer, client %d\n",
+					caller_client->id);
+			SDE_EVT32(caller_client->id, rsc->current_state,
+					caller_client->crtc_id,
+					wait_vblank_crtc_id, SDE_EVTLOG_ERROR);
+			msleep(PRIMARY_VBLANK_WORST_CASE_MS);
+		} else {
+			*wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+		}
+	}
 end:
 	return rc;
 }
 
-static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc)
+static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc,
+		int *wait_vblank_crtc_id)
 {
 	struct sde_rsc_client *client;
 	int rc = STATE_UPDATE_NOT_ALLOWED;
@@ -510,17 +550,27 @@
 			rpmh_mode_solver_set(rsc->disp_rsc, false);
 	}
 
-	/* wait for vsync for cmd to clk state switch */
+	/* indicate wait for vsync for cmd to clk state switch */
 	if (!rc && rsc->primary_client &&
-				(rsc->current_state == SDE_RSC_CMD_STATE))
-		usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
+			(rsc->current_state == SDE_RSC_CMD_STATE)) {
+		/* clear VSYNC timestamp for indication when update completes */
+		if (rsc->hw_ops.hw_vsync)
+			rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
+		if (!wait_vblank_crtc_id) {
+			pr_err("invalid crtc id wait pointer provided\n");
+			msleep(PRIMARY_VBLANK_WORST_CASE_MS);
+		} else {
+			*wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+		}
+	}
 end:
 	return rc;
 }
 
 static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
 	struct sde_rsc_cmd_config *config,
-	struct sde_rsc_client *caller_client)
+	struct sde_rsc_client *caller_client,
+	int *wait_vblank_crtc_id)
 {
 	int rc = 0;
 
@@ -539,16 +589,62 @@
 			rpmh_mode_solver_set(rsc->disp_rsc, false);
 	}
 
-	/* wait for vsync for cmd to vid state switch */
+	/* indicate wait for vsync for cmd to vid state switch */
 	if (!rc && rsc->primary_client &&
-			(rsc->current_state == SDE_RSC_CMD_STATE))
-		usleep_range(PRIMARY_VBLANK_MIN_US, PRIMARY_VBLANK_MAX_US);
+			(rsc->current_state == SDE_RSC_CMD_STATE)) {
+		/* clear VSYNC timestamp for indication when update completes */
+		if (rsc->hw_ops.hw_vsync)
+			rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0);
+		if (!wait_vblank_crtc_id) {
+			pr_err("invalid crtc id wait pointer provided\n");
+			msleep(PRIMARY_VBLANK_WORST_CASE_MS);
+		} else {
+			*wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+		}
+	}
 
 end:
 	return rc;
 }
 
 /**
+ * sde_rsc_client_is_state_update_complete() - check if state update is complete
+ * RSC state transition is not complete until HW receives VBLANK signal. This
+ * function checks RSC HW to determine whether that signal has been received.
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: true if the state update has completed.
+ */
+bool sde_rsc_client_is_state_update_complete(
+		struct sde_rsc_client *caller_client)
+{
+	struct sde_rsc_priv *rsc;
+	u32 vsync_timestamp0 = 0;
+
+	if (!caller_client) {
+		pr_err("invalid client for rsc state update\n");
+		return false;
+	} else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
+		pr_err("invalid rsc index\n");
+		return false;
+	}
+
+	rsc = rsc_prv_list[caller_client->rsc_index];
+	if (!rsc)
+		return false;
+
+	/**
+	 * state updates clear VSYNC timestamp, check if a new one arrived.
+	 * use VSYNC mode 0 (CMD TE) always for this, per HW recommendation.
+	 */
+	if (rsc->hw_ops.hw_vsync)
+		vsync_timestamp0 = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ_VSYNC0,
+				NULL, 0, 0);
+
+	return vsync_timestamp0 != 0;
+}
+
+/**
  * sde_rsc_client_state_update() - rsc client state update
  * Video mode, cmd mode and clk state are suppoed as modes. A client need to
  * set this property during panel config time. A switching client can set the
@@ -559,12 +655,18 @@
  * @config:	 fps, vtotal, porches, etc configuration for command mode
  *               panel
  * @crtc_id:	 current client's crtc id
+ * @wait_vblank_crtc_id:	Output parameter. If set to non-zero, rsc hw
+ *				state update requires a wait for one vblank on
+ *				the primary crtc. In that case, this output
+ *				param will be set to the crtc on which to wait.
+ *				If SDE_RSC_INVALID_CRTC_ID, no wait necessary
  *
  * Return: error code.
  */
 int sde_rsc_client_state_update(struct sde_rsc_client *caller_client,
 	enum sde_rsc_state state,
-	struct sde_rsc_cmd_config *config, int crtc_id)
+	struct sde_rsc_cmd_config *config, int crtc_id,
+	int *wait_vblank_crtc_id)
 {
 	int rc = 0;
 	struct sde_rsc_priv *rsc;
@@ -581,6 +683,9 @@
 	if (!rsc)
 		return -EINVAL;
 
+	if (wait_vblank_crtc_id)
+		*wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID;
+
 	mutex_lock(&rsc->client_lock);
 	SDE_EVT32_VERBOSE(caller_client->id, caller_client->current_state,
 			state, rsc->current_state, SDE_EVTLOG_FUNC_ENTRY);
@@ -610,28 +715,31 @@
 		/* video state client might be exiting; try cmd state switch */
 		if (rc == TRY_CMD_MODE_SWITCH) {
 			rc = sde_rsc_switch_to_cmd(rsc, NULL,
-							rsc->primary_client);
+					rsc->primary_client,
+					wait_vblank_crtc_id);
 			if (!rc)
 				state = SDE_RSC_CMD_STATE;
 
 		/* cmd state client might be exiting; try clk state switch */
 		} else if (rc == TRY_CLK_MODE_SWITCH) {
-			rc = sde_rsc_switch_to_clk(rsc);
+			rc = sde_rsc_switch_to_clk(rsc, wait_vblank_crtc_id);
 			if (!rc)
 				state = SDE_RSC_CLK_STATE;
 		}
 		break;
 
 	case SDE_RSC_CMD_STATE:
-		rc = sde_rsc_switch_to_cmd(rsc, config, caller_client);
+		rc = sde_rsc_switch_to_cmd(rsc, config, caller_client,
+				wait_vblank_crtc_id);
 		break;
 
 	case SDE_RSC_VID_STATE:
-		rc = sde_rsc_switch_to_vid(rsc, config, caller_client);
+		rc = sde_rsc_switch_to_vid(rsc, config, caller_client,
+				wait_vblank_crtc_id);
 		break;
 
 	case SDE_RSC_CLK_STATE:
-		rc = sde_rsc_switch_to_clk(rsc);
+		rc = sde_rsc_switch_to_clk(rsc, wait_vblank_crtc_id);
 		break;
 
 	default:
@@ -815,7 +923,7 @@
 
 end:
 	mutex_unlock(&rsc->client_lock);
-	if (blen < 0)
+	if (blen <= 0)
 		return 0;
 
 	if (copy_to_user(buf, buffer, blen))
@@ -907,7 +1015,7 @@
 
 end:
 	mutex_unlock(&rsc->client_lock);
-	if (blen < 0)
+	if (blen <= 0)
 		return 0;
 
 	if (copy_to_user(buf, buffer, blen))
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index aa8fa01..b474d21 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -296,6 +296,47 @@
 	return 0;
 }
 
+static int rsc_hw_timer_update(struct sde_rsc_priv *rsc)
+{
+	if (!rsc) {
+		pr_debug("invalid input param\n");
+		return -EINVAL;
+	}
+
+	pr_debug("rsc hw timer update\n");
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0,
+		rsc->timer_config.rsc_time_slot_0_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0,
+		rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0,
+		rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0,
+			rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0,
+			rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1,
+			rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1,
+			rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2,
+			rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0,
+		rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode);
+
+	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD,
+		rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode);
+
+	/* make sure that hw timers are updated */
+	wmb();
+
+	return 0;
+}
+
 static int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc,
 						enum sde_rsc_state state)
 {
@@ -428,6 +469,7 @@
 
 	if (rc) {
 		pr_err("mdss gdsc power down failed rc:%d\n", rc);
+		SDE_EVT32(rc, SDE_EVTLOG_ERROR);
 		goto end;
 	}
 
@@ -675,10 +717,24 @@
 				rsc->debug_mode));
 		break;
 
+	case VSYNC_READ_VSYNC0:
+		return dss_reg_r(&rsc->wrapper_io,
+				SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0,
+				rsc->debug_mode);
+
 	case VSYNC_ENABLE:
-		reg = BIT(8) | ((mode & 0x7) << 10);
+		/* clear the current VSYNC value */
+		reg = BIT(9) | ((mode & 0x7) << 10);
 		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS,
 					reg, rsc->debug_mode);
+
+		/* enable the VSYNC logging */
+		reg = BIT(8) | ((mode & 0x7) << 10);
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS,
+				reg, rsc->debug_mode);
+
+		/* ensure vsync config has been written before waiting on it */
+		wmb();
 		break;
 
 	case VSYNC_DISABLE:
@@ -740,6 +796,7 @@
 	pr_debug("rsc hardware register\n");
 
 	rsc->hw_ops.init = rsc_hw_init;
+	rsc->hw_ops.timer_update = rsc_hw_timer_update;
 
 	rsc->hw_ops.tcs_wait = rsc_hw_tcs_wait;
 	rsc->hw_ops.tcs_use_ok = rsc_hw_tcs_use_ok;
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
index b90b0ac..c96ce75 100644
--- a/drivers/gpu/drm/msm/sde_rsc_priv.h
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -51,11 +51,13 @@
 /**
  * rsc_vsync_req: sde rsc vsync request information
  * VSYNC_READ: read vsync status
+ * VSYNC_READ_VSYNC0: read value vsync0 timestamp (cast to int from u32)
  * VSYNC_ENABLE: enable rsc wrapper vsync status
  * VSYNC_DISABLE: disable rsc wrapper vsync status
  */
 enum rsc_vsync_req {
 	VSYNC_READ,
+	VSYNC_READ_VSYNC0,
 	VSYNC_ENABLE,
 	VSYNC_DISABLE,
 };
@@ -64,6 +66,8 @@
  * struct sde_rsc_hw_ops - sde resource state coordinator hardware ops
  * @init:			Initialize the sequencer, solver, qtimer,
 				etc. hardware blocks on RSC.
+ * @timer_update:		update the static wrapper time and pdc/rsc
+				backoff time.
  * @tcs_wait:			Waits for TCS block OK to allow sending a
  *				TCS command.
  * @hw_vsync:			Enables the vsync on RSC block.
@@ -77,6 +81,7 @@
 
 struct sde_rsc_hw_ops {
 	int (*init)(struct sde_rsc_priv *rsc);
+	int (*timer_update)(struct sde_rsc_priv *rsc);
 	int (*tcs_wait)(struct sde_rsc_priv *rsc);
 	int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request,
 		char *buffer, int buffer_size, u32 mode);
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index 431a67e..e112fd1 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -117,6 +117,7 @@
 #define A6XX_CP_ALWAYS_ON_COUNTER_HI     0x981
 #define A6XX_CP_AHB_CNTL                 0x98D
 #define A6XX_CP_APERTURE_CNTL_HOST       0xA00
+#define A6XX_CP_APERTURE_CNTL_CD         0xA03
 #define A6XX_VSC_ADDR_MODE_CNTL          0xC01
 
 /* RBBM registers */
@@ -599,6 +600,8 @@
 #define A6XX_RB_PERFCTR_CMP_SEL_1           0x8E2D
 #define A6XX_RB_PERFCTR_CMP_SEL_2           0x8E2E
 #define A6XX_RB_PERFCTR_CMP_SEL_3           0x8E2F
+#define A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_HOST  0x8E3B
+#define A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD    0x8E3D
 #define A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE 0x8E50
 
 /* PC registers */
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index d717cf1..7e9482a 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -562,11 +562,20 @@
 /* Ucode workaround masks */
 #define CP_INIT_UCODE_WORKAROUND_MASK BIT(5)
 
+/*
+ * Operation mode mask
+ *
+ * This ordinal provides the option to disable the
+ * save/restore of performance counters across preemption.
+ */
+#define CP_INIT_OPERATION_MODE_MASK BIT(6)
+
 #define CP_INIT_MASK (CP_INIT_MAX_CONTEXT | \
 		CP_INIT_ERROR_DETECTION_CONTROL | \
 		CP_INIT_HEADER_DUMP | \
 		CP_INIT_DEFAULT_RESET_STATE | \
-		CP_INIT_UCODE_WORKAROUND_MASK)
+		CP_INIT_UCODE_WORKAROUND_MASK | \
+		CP_INIT_OPERATION_MODE_MASK)
 
 static void _set_ordinals(struct adreno_device *adreno_dev,
 		unsigned int *cmds, unsigned int count)
@@ -599,6 +608,9 @@
 	if (CP_INIT_MASK & CP_INIT_UCODE_WORKAROUND_MASK)
 		*cmds++ = 0x00000000;
 
+	if (CP_INIT_MASK & CP_INIT_OPERATION_MODE_MASK)
+		*cmds++ = 0x00000002;
+
 	/* Pad rest of the cmds with 0's */
 	while ((unsigned int)(cmds - start) < count)
 		*cmds++ = 0x0;
diff --git a/drivers/gpu/msm/adreno_a6xx.h b/drivers/gpu/msm/adreno_a6xx.h
index ddf89d6..02748a6 100644
--- a/drivers/gpu/msm/adreno_a6xx.h
+++ b/drivers/gpu/msm/adreno_a6xx.h
@@ -73,7 +73,7 @@
 	uint32_t  context_idr;
 };
 
-#define A6XX_CP_SMMU_INFO_MAGIC_REF     0x3618CDA3UL
+#define A6XX_CP_SMMU_INFO_MAGIC_REF     0x241350D5UL
 
 #define A6XX_CP_CTXRECORD_MAGIC_REF     0xAE399D6EUL
 /* Size of each CP preemption record */
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index e1f1595..6264574 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -31,12 +31,20 @@
 	0x8400, 0x840B,
 };
 
-static const unsigned int a6xx_ps_cluster[] = {
+static const unsigned int a6xx_ps_cluster_rac[] = {
 	0x8800, 0x8806, 0x8809, 0x8811, 0x8818, 0x881E, 0x8820, 0x8865,
 	0x8870, 0x8879, 0x8880, 0x8889, 0x8890, 0x8891, 0x8898, 0x8898,
-	0x88C0, 0x88c1, 0x88D0, 0x88E3, 0x88F0, 0x88F3, 0x8900, 0x891A,
-	0x8927, 0x8928, 0x8C00, 0x8C01, 0x8C17, 0x8C33, 0x9200, 0x9216,
-	0x9218, 0x9236, 0x9300, 0x9306,
+	0x88C0, 0x88C1, 0x88D0, 0x88E3, 0x8900, 0x890C, 0x890F, 0x891A,
+	0x8C00, 0x8C01, 0x8C08, 0x8C10, 0x8C17, 0x8C1F, 0x8C26, 0x8C33,
+};
+
+static const unsigned int a6xx_ps_cluster_rbp[] = {
+	0x88F0, 0x88F3, 0x890D, 0x890E, 0x8927, 0x8928, 0x8BF0, 0x8BF1,
+	0x8C02, 0x8C07, 0x8C11, 0x8C16, 0x8C20, 0x8C25,
+};
+
+static const unsigned int a6xx_ps_cluster[] = {
+	0x9200, 0x9216, 0x9218, 0x9236, 0x9300, 0x9306,
 };
 
 static const unsigned int a6xx_fe_cluster[] = {
@@ -48,18 +56,41 @@
 	0x9100, 0x9108, 0x9300, 0x9306, 0x9980, 0x9981, 0x9B00, 0x9B07,
 };
 
+static const struct sel_reg {
+	unsigned int host_reg;
+	unsigned int cd_reg;
+	unsigned int val;
+} _a6xx_rb_rac_aperture = {
+	.host_reg = A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_HOST,
+	.cd_reg = A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD,
+	.val = 0x0,
+},
+_a6xx_rb_rbp_aperture = {
+	.host_reg = A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_HOST,
+	.cd_reg = A6XX_RB_RB_SUB_BLOCK_SEL_CNTL_CD,
+	.val = 0x9,
+};
+
 static struct a6xx_cluster_registers {
 	unsigned int id;
 	const unsigned int *regs;
 	unsigned int num_sets;
+	const struct sel_reg *sel;
 	unsigned int offset0;
 	unsigned int offset1;
 } a6xx_clusters[] = {
-	{ CP_CLUSTER_GRAS, a6xx_gras_cluster, ARRAY_SIZE(a6xx_gras_cluster)/2 },
-	{ CP_CLUSTER_PS, a6xx_ps_cluster, ARRAY_SIZE(a6xx_ps_cluster)/2 },
-	{ CP_CLUSTER_FE, a6xx_fe_cluster, ARRAY_SIZE(a6xx_fe_cluster)/2 },
+	{ CP_CLUSTER_GRAS, a6xx_gras_cluster, ARRAY_SIZE(a6xx_gras_cluster)/2,
+		NULL },
+	{ CP_CLUSTER_PS, a6xx_ps_cluster_rac, ARRAY_SIZE(a6xx_ps_cluster_rac)/2,
+		&_a6xx_rb_rac_aperture },
+	{ CP_CLUSTER_PS, a6xx_ps_cluster_rbp, ARRAY_SIZE(a6xx_ps_cluster_rbp)/2,
+		&_a6xx_rb_rbp_aperture },
+	{ CP_CLUSTER_PS, a6xx_ps_cluster, ARRAY_SIZE(a6xx_ps_cluster)/2,
+		NULL },
+	{ CP_CLUSTER_FE, a6xx_fe_cluster, ARRAY_SIZE(a6xx_fe_cluster)/2,
+		NULL },
 	{ CP_CLUSTER_PC_VS, a6xx_pc_vs_cluster,
-					ARRAY_SIZE(a6xx_pc_vs_cluster)/2 },
+		ARRAY_SIZE(a6xx_pc_vs_cluster)/2, NULL },
 };
 
 struct a6xx_cluster_regs_info {
@@ -246,6 +277,16 @@
 	0x26400, 0x26416, 0x26420, 0x26427,
 };
 
+static const unsigned int a6xx_rb_rac_registers[] = {
+	0x8E04, 0x8E05, 0x8E07, 0x8E08, 0x8E10, 0x8E1C, 0x8E20, 0x8E25,
+	0x8E28, 0x8E28, 0x8E2C, 0x8E2F, 0x8E50, 0x8E52,
+};
+
+static const unsigned int a6xx_rb_rbp_registers[] = {
+	0x8E01, 0x8E01, 0x8E0C, 0x8E0C, 0x8E3B, 0x8E3E, 0x8E40, 0x8E43,
+	0x8E53, 0x8E5F, 0x8E70, 0x8E77,
+};
+
 static const struct adreno_vbif_snapshot_registers
 a6xx_vbif_snapshot_registers[] = {
 	{ 0x20040000, 0xFF000000, a6xx_vbif_ver_20xxxxxx_registers,
@@ -282,10 +323,6 @@
 	/* GRAS */
 	0x8600, 0x8601, 0x8610, 0x861B, 0x8620, 0x8620, 0x8628, 0x862B,
 	0x8630, 0x8637,
-	/* RB */
-	0x8E01, 0x8E01, 0x8E04, 0x8E05, 0x8E07, 0x8E08, 0x8E0C, 0x8E0C,
-	0x8E10, 0x8E1C, 0x8E20, 0x8E25, 0x8E28, 0x8E28, 0x8E2C, 0x8E2F,
-	0x8E3B, 0x8E3E, 0x8E40, 0x8E43, 0x8E50, 0x8E5E, 0x8E70, 0x8E77,
 	/* VPC */
 	0x9600, 0x9604, 0x9624, 0x9637,
 	/* PC */
@@ -516,27 +553,43 @@
 static struct kgsl_memdesc a6xx_crashdump_registers;
 static bool crash_dump_valid;
 
-static size_t a6xx_legacy_snapshot_registers(struct kgsl_device *device,
-		u8 *buf, size_t remain)
-{
-	struct kgsl_snapshot_registers regs = {
-		.regs = a6xx_registers,
-		.count = ARRAY_SIZE(a6xx_registers) / 2,
-	};
-
-	return kgsl_snapshot_dump_registers(device, buf, remain, &regs);
-}
-
-static struct cdregs {
+static struct reg_list {
 	const unsigned int *regs;
-	unsigned int size;
-} _a6xx_cd_registers[] = {
-	{ a6xx_registers, ARRAY_SIZE(a6xx_registers) },
+	unsigned int count;
+	const struct sel_reg *sel;
+} a6xx_reg_list[] = {
+	{ a6xx_registers, ARRAY_SIZE(a6xx_registers) / 2, NULL },
+	{ a6xx_rb_rac_registers, ARRAY_SIZE(a6xx_rb_rac_registers) / 2,
+		&_a6xx_rb_rac_aperture },
+	{ a6xx_rb_rbp_registers, ARRAY_SIZE(a6xx_rb_rbp_registers) / 2,
+		&_a6xx_rb_rbp_aperture },
 };
 
 #define REG_PAIR_COUNT(_a, _i) \
 	(((_a)[(2 * (_i)) + 1] - (_a)[2 * (_i)]) + 1)
 
+static size_t a6xx_legacy_snapshot_registers(struct kgsl_device *device,
+		u8 *buf, size_t remain)
+{
+	unsigned int i;
+	size_t used = 0;
+
+	for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+		struct reg_list *regs = &a6xx_reg_list[i];
+		struct kgsl_snapshot_registers snapshot_regs = {
+			.regs = regs->regs,
+			.count = regs->count,
+		};
+
+		if (regs->sel)
+			kgsl_regwrite(device, regs->sel->host_reg,
+				regs->sel->val);
+		used += kgsl_snapshot_dump_registers(device, buf + used,
+						remain - used, &snapshot_regs);
+	}
+	return used;
+}
+
 static size_t a6xx_snapshot_registers(struct kgsl_device *device, u8 *buf,
 		size_t remain, void *priv)
 {
@@ -556,10 +609,10 @@
 
 	remain -= sizeof(*header);
 
-	for (i = 0; i < ARRAY_SIZE(_a6xx_cd_registers); i++) {
-		struct cdregs *regs = &_a6xx_cd_registers[i];
+	for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+		struct reg_list *regs = &a6xx_reg_list[i];
 
-		for (j = 0; j < regs->size / 2; j++) {
+		for (j = 0; j < regs->count; j++) {
 			unsigned int start = regs->regs[2 * j];
 			unsigned int end = regs->regs[(2 * j) + 1];
 
@@ -959,6 +1012,10 @@
 	aperture_cntl = ((cur_cluster->id & 0x7) << 8) | (ctxt << 4) | ctxt;
 	kgsl_regwrite(device, A6XX_CP_APERTURE_CNTL_HOST, aperture_cntl);
 
+	if (cur_cluster->sel)
+		kgsl_regwrite(device, cur_cluster->sel->host_reg,
+			cur_cluster->sel->val);
+
 	for (i = 0; i < cur_cluster->num_sets; i++) {
 		start = cur_cluster->regs[2 * i];
 		end = cur_cluster->regs[2 * i + 1];
@@ -1592,6 +1649,12 @@
 	for (i = 0; i < ARRAY_SIZE(a6xx_clusters); i++) {
 		struct a6xx_cluster_registers *cluster = &a6xx_clusters[i];
 
+		if (cluster->sel) {
+			ptr[qwords++] = cluster->sel->val;
+			ptr[qwords++] = ((uint64_t)cluster->sel->cd_reg << 44) |
+				(1 << 21) | 1;
+		}
+
 		cluster->offset0 = *offset;
 		for (j = 0; j < A6XX_NUM_CTXTS; j++) {
 
@@ -1600,7 +1663,7 @@
 
 			ptr[qwords++] = (cluster->id << 8) | (j << 4) | j;
 			ptr[qwords++] =
-				((uint64_t)A6XX_CP_APERTURE_CNTL_HOST << 44) |
+				((uint64_t)A6XX_CP_APERTURE_CNTL_CD << 44) |
 				(1 << 21) | 1;
 
 			for (k = 0; k < cluster->num_sets; k++) {
@@ -1747,14 +1810,18 @@
 	 * To save the registers, we need 16 bytes per register pair for the
 	 * script and a dword for each register in the data
 	 */
-	for (i = 0; i < ARRAY_SIZE(_a6xx_cd_registers); i++) {
-		struct cdregs *regs = &_a6xx_cd_registers[i];
+	for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+		struct reg_list *regs = &a6xx_reg_list[i];
+
+		/* 16 bytes for programming the aperture */
+		if (regs->sel)
+			script_size += 16;
 
 		/* Each pair needs 16 bytes (2 qwords) */
-		script_size += (regs->size / 2) * 16;
+		script_size += regs->count * 16;
 
 		/* Each register needs a dword in the data */
-		for (j = 0; j < regs->size / 2; j++)
+		for (j = 0; j < regs->count; j++)
 			data_size += REG_PAIR_COUNT(regs->regs, j) *
 				sizeof(unsigned int);
 
@@ -1850,10 +1917,17 @@
 	ptr = (uint64_t *)a6xx_capturescript.hostptr;
 
 	/* For the registers, program a read command for each pair */
-	for (i = 0; i < ARRAY_SIZE(_a6xx_cd_registers); i++) {
-		struct cdregs *regs = &_a6xx_cd_registers[i];
+	for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+		struct reg_list *regs = &a6xx_reg_list[i];
 
-		for (j = 0; j < regs->size / 2; j++) {
+		/* Program the SEL_CNTL_CD register appropriately */
+		if (regs->sel) {
+			*ptr++ = regs->sel->val;
+			*ptr++ = (((uint64_t)regs->sel->cd_reg << 44)) |
+					(1 << 21) | 1;
+		}
+
+		for (j = 0; j < regs->count; j++) {
 			unsigned int r = REG_PAIR_COUNT(regs->regs, j);
 			*ptr++ = a6xx_crashdump_registers.gpuaddr + offset;
 			*ptr++ = (((uint64_t) regs->regs[2 * j]) << 44) | r;
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index c511040..36fdd51 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1218,20 +1218,11 @@
 
 static int gmu_disable_clks(struct gmu_device *gmu)
 {
-	int ret, j = 0;
-	unsigned int gmu_freq;
+	int j = 0;
 
 	if (IS_ERR_OR_NULL(gmu->clks[0]))
 		return 0;
 
-	gmu_freq = gmu->gmu_freqs[gmu->num_gmupwrlevels - 1];
-	ret = clk_set_rate(gmu->clks[0], gmu_freq);
-	if (ret) {
-		dev_err(&gmu->pdev->dev, "fail to reset GMU clk freq %d\n",
-				gmu_freq);
-		return ret;
-	}
-
 	while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
 		clk_disable_unprepare(gmu->clks[j]);
 		j++;
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 8f8e3e9..015d07f 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -370,7 +370,8 @@
 	unsigned long flags;
 	struct kgsl_sync_fence *kfence, *next;
 
-	kref_get(&ktimeline->kref);
+	if (!kref_get_unless_zero(&ktimeline->kref))
+		return;
 
 	spin_lock_irqsave(&ktimeline->lock, flags);
 	if (timestamp_cmp(timestamp, ktimeline->last_timestamp) > 0)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 946e0ba..91e7b0c 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -26,6 +26,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/qcom-geni-se.h>
 #include <linux/ipc_logging.h>
+#include <linux/dmaengine.h>
+#include <linux/msm_gpi.h>
 
 #define SE_I2C_TX_TRANS_LEN		(0x26C)
 #define SE_I2C_RX_TRANS_LEN		(0x270)
@@ -54,6 +56,7 @@
 #define SLV_ADDR_MSK		(GENMASK(15, 9))
 #define SLV_ADDR_SHFT		(9)
 
+#define I2C_PACK_EN		(BIT(0) | BIT(1))
 #define I2C_CORE2X_VOTE		(10000)
 #define GP_IRQ0			0
 #define GP_IRQ1			1
@@ -71,6 +74,12 @@
 #define I2C_ARB_LOST		GP_IRQ4
 #define DM_I2C_RX_ERR		((GP_IRQ1 | GP_IRQ3 | GP_IRQ4) >> 4)
 
+enum i2c_se_mode {
+	UNINITIALIZED,
+	FIFO_SE_DMA,
+	GSI_ONLY,
+};
+
 struct geni_i2c_dev {
 	struct device *dev;
 	void __iomem *base;
@@ -86,6 +95,24 @@
 	struct device *wrapper_dev;
 	void *ipcl;
 	int clk_fld_idx;
+	struct dma_chan *tx_c;
+	struct dma_chan *rx_c;
+	struct msm_gpi_tre cfg0_t;
+	struct msm_gpi_tre go_t;
+	struct msm_gpi_tre tx_t;
+	struct msm_gpi_tre rx_t;
+	dma_addr_t tx_ph;
+	dma_addr_t rx_ph;
+	struct msm_gpi_ctrl tx_ev;
+	struct msm_gpi_ctrl rx_ev;
+	struct scatterlist tx_sg[5]; /* lock, cfg0, go, TX, unlock */
+	struct scatterlist rx_sg;
+	int cfg_sent;
+	struct dma_async_tx_descriptor *tx_desc;
+	struct dma_async_tx_descriptor *rx_desc;
+	struct msm_gpi_dma_async_tx_cb_param tx_cb;
+	struct msm_gpi_dma_async_tx_cb_param rx_cb;
+	enum i2c_se_mode se_mode;
 };
 
 struct geni_i2c_err_log {
@@ -184,6 +211,9 @@
 		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n",
 			     gi2c_log[err].msg);
 	}
+	if (gi2c->se_mode == GSI_ONLY)
+		goto err_out;
+
 	if (dma) {
 		rx_st = readl_relaxed(gi2c->base + SE_DMA_RX_IRQ_STAT);
 		tx_st = readl_relaxed(gi2c->base + SE_DMA_TX_IRQ_STAT);
@@ -194,6 +224,7 @@
 	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
 		     "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n",
 		     dma, tx_st, rx_st, m_stat);
+err_out:
 	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
 			     "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
 			     m_cmd, geni_s, geni_ios);
@@ -305,6 +336,258 @@
 	return IRQ_HANDLED;
 }
 
+static void gi2c_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb_str,
+		       void *ptr)
+{
+	struct geni_i2c_dev *gi2c = ptr;
+	u32 m_stat = cb_str->status;
+
+	switch (cb_str->cb_event) {
+	case MSM_GPI_QUP_ERROR:
+	case MSM_GPI_QUP_SW_ERROR:
+	case MSM_GPI_QUP_MAX_EVENT:
+		/* fall through to stall impacted channel */
+	case MSM_GPI_QUP_CH_ERROR:
+	case MSM_GPI_QUP_PENDING_EVENT:
+	case MSM_GPI_QUP_EOT_DESC_MISMATCH:
+		break;
+	case MSM_GPI_QUP_NOTIFY:
+		if (m_stat & M_GP_IRQ_1_EN)
+			geni_i2c_err(gi2c, I2C_NACK);
+		if (m_stat & M_GP_IRQ_3_EN)
+			geni_i2c_err(gi2c, I2C_BUS_PROTO);
+		if (m_stat & M_GP_IRQ_4_EN)
+			geni_i2c_err(gi2c, I2C_ARB_LOST);
+		complete(&gi2c->xfer);
+		break;
+	default:
+		break;
+	}
+	if (cb_str->cb_event != MSM_GPI_QUP_NOTIFY)
+		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+				"GSI QN err:0x%x, status:0x%x, err:%d\n",
+				cb_str->error_log.error_code,
+				m_stat, cb_str->cb_event);
+}
+
+static void gi2c_gsi_tx_cb(void *ptr)
+{
+	struct msm_gpi_dma_async_tx_cb_param *tx_cb = ptr;
+	struct geni_i2c_dev *gi2c = tx_cb->userdata;
+
+	if (!(gi2c->cur->flags & I2C_M_RD))
+		complete(&gi2c->xfer);
+}
+
+static void gi2c_gsi_rx_cb(void *ptr)
+{
+	struct msm_gpi_dma_async_tx_cb_param *rx_cb = ptr;
+	struct geni_i2c_dev *gi2c = rx_cb->userdata;
+
+	if (gi2c->cur->flags & I2C_M_RD) {
+		if (rx_cb->status & DM_I2C_RX_ERR) {
+			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+				    "RX TCE Unexpected Err, stat:0x%x\n",
+				    rx_cb->status);
+			if (rx_cb->status & GP_IRQ1)
+				geni_i2c_err(gi2c, I2C_NACK);
+			if (rx_cb->status & GP_IRQ3)
+				geni_i2c_err(gi2c, I2C_BUS_PROTO);
+			if (rx_cb->status & GP_IRQ4)
+				geni_i2c_err(gi2c, I2C_ARB_LOST);
+		}
+		complete(&gi2c->xfer);
+	}
+}
+
+static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+			     int num)
+{
+	struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
+	int i, ret = 0, timeout = 0;
+
+	if (!gi2c->tx_c) {
+		gi2c->tx_c = dma_request_slave_channel(gi2c->dev, "tx");
+		if (!gi2c->tx_c) {
+			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+				    "tx dma req slv chan ret :%d\n", ret);
+			return -EIO;
+		}
+		gi2c->tx_ev.init.callback = gi2c_ev_cb;
+		gi2c->tx_ev.init.cb_param = gi2c;
+		gi2c->tx_ev.cmd = MSM_GPI_INIT;
+		gi2c->tx_c->private = &gi2c->tx_ev;
+		ret = dmaengine_slave_config(gi2c->tx_c, NULL);
+		if (ret) {
+			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+				    "tx dma slave config ret :%d\n", ret);
+			return ret;
+		}
+	}
+	if (!gi2c->rx_c) {
+		gi2c->rx_c = dma_request_slave_channel(gi2c->dev, "rx");
+		if (!gi2c->rx_c) {
+			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+				    "rx dma req slv chan ret :%d\n", ret);
+			return -EIO;
+		}
+		gi2c->rx_ev.init.cb_param = gi2c;
+		gi2c->rx_ev.init.callback = gi2c_ev_cb;
+		gi2c->rx_ev.cmd = MSM_GPI_INIT;
+		gi2c->rx_c->private = &gi2c->rx_ev;
+		ret = dmaengine_slave_config(gi2c->rx_c, NULL);
+		if (ret) {
+			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+				    "rx dma slave config ret :%d\n", ret);
+			return ret;
+		}
+	}
+
+	if (!gi2c->cfg_sent) {
+		struct geni_i2c_clk_fld *itr = geni_i2c_clk_map +
+							gi2c->clk_fld_idx;
+		struct msm_gpi_tre *cfg0 = &gi2c->cfg0_t;
+
+		/* config0 */
+		cfg0->dword[0] = MSM_GPI_I2C_CONFIG0_TRE_DWORD0(I2C_PACK_EN,
+								itr->t_cycle,
+								itr->t_high,
+								itr->t_low);
+		cfg0->dword[1] = MSM_GPI_I2C_CONFIG0_TRE_DWORD1(0, 0);
+		cfg0->dword[2] = MSM_GPI_I2C_CONFIG0_TRE_DWORD2(0,
+								itr->clk_div);
+		cfg0->dword[3] = MSM_GPI_I2C_CONFIG0_TRE_DWORD3(0, 0, 0, 1);
+
+		gi2c->tx_cb.userdata = gi2c;
+		gi2c->rx_cb.userdata = gi2c;
+	}
+
+	for (i = 0; i < num; i++) {
+		u8 op = (msgs[i].flags & I2C_M_RD) ? 2 : 1;
+		int segs = 3 - op;
+		int index = 0;
+		int stretch = (i < (num - 1));
+		dma_cookie_t tx_cookie, rx_cookie;
+		struct msm_gpi_tre *go_t = &gi2c->go_t;
+		struct device *rx_dev = gi2c->rx_c->device->dev;
+		struct device *tx_dev = gi2c->tx_c->device->dev;
+
+		gi2c->cur = &msgs[i];
+		if (!gi2c->cfg_sent) {
+			segs++;
+			sg_init_table(gi2c->tx_sg, segs);
+			sg_set_buf(gi2c->tx_sg, &gi2c->cfg0_t,
+						sizeof(gi2c->cfg0_t));
+			gi2c->cfg_sent = 1;
+			index++;
+		} else {
+			sg_init_table(gi2c->tx_sg, segs);
+		}
+
+		go_t->dword[0] = MSM_GPI_I2C_GO_TRE_DWORD0((stretch << 2),
+							   msgs[i].addr, op);
+		go_t->dword[1] = MSM_GPI_I2C_GO_TRE_DWORD1;
+
+		if (msgs[i].flags & I2C_M_RD) {
+			go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(msgs[i].len);
+			go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 1, 0);
+		} else {
+			go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0);
+			go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 0, 1);
+		}
+
+		sg_set_buf(&gi2c->tx_sg[index++], &gi2c->go_t,
+						  sizeof(gi2c->go_t));
+
+		if (msgs[i].flags & I2C_M_RD) {
+			sg_init_table(&gi2c->rx_sg, 1);
+			gi2c->rx_ph = dma_map_single(rx_dev, msgs[i].buf,
+						     msgs[i].len,
+						     DMA_FROM_DEVICE);
+			gi2c->rx_t.dword[0] =
+				MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph);
+			gi2c->rx_t.dword[1] =
+				MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->rx_ph);
+			gi2c->rx_t.dword[2] =
+				MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
+			gi2c->rx_t.dword[3] =
+				MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 1, 0, 0);
+
+			sg_set_buf(&gi2c->rx_sg, &gi2c->rx_t,
+						 sizeof(gi2c->rx_t));
+			gi2c->rx_desc = dmaengine_prep_slave_sg(gi2c->rx_c,
+							&gi2c->rx_sg, 1,
+							DMA_DEV_TO_MEM,
+							(DMA_PREP_INTERRUPT |
+							 DMA_CTRL_ACK));
+			if (!gi2c->rx_desc) {
+				GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+					    "prep_slave_sg for rx failed\n");
+				gi2c->err = -ENOMEM;
+				return gi2c->err;
+			}
+			gi2c->rx_desc->callback = gi2c_gsi_rx_cb;
+			gi2c->rx_desc->callback_param = &gi2c->rx_cb;
+
+			/* Issue RX */
+			rx_cookie = dmaengine_submit(gi2c->rx_desc);
+			dma_async_issue_pending(gi2c->rx_c);
+		} else {
+			gi2c->tx_ph = dma_map_single(tx_dev, msgs[i].buf,
+						     msgs[i].len,
+						     DMA_TO_DEVICE);
+			gi2c->tx_t.dword[0] =
+				MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph);
+			gi2c->tx_t.dword[1] =
+				MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->tx_ph);
+			gi2c->tx_t.dword[2] =
+				MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len);
+			gi2c->tx_t.dword[3] =
+				MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 1, 0, 0);
+
+			sg_set_buf(&gi2c->tx_sg[index++], &gi2c->tx_t,
+							  sizeof(gi2c->tx_t));
+		}
+
+		gi2c->tx_desc = dmaengine_prep_slave_sg(gi2c->tx_c, gi2c->tx_sg,
+						segs, DMA_MEM_TO_DEV,
+						(DMA_PREP_INTERRUPT |
+						 DMA_CTRL_ACK));
+		if (!gi2c->tx_desc) {
+			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+				    "prep_slave_sg for tx failed\n");
+			gi2c->err = -ENOMEM;
+			return gi2c->err;
+		}
+		gi2c->tx_desc->callback = gi2c_gsi_tx_cb;
+		gi2c->tx_desc->callback_param = &gi2c->tx_cb;
+
+		/* Issue TX */
+		tx_cookie = dmaengine_submit(gi2c->tx_desc);
+		dma_async_issue_pending(gi2c->tx_c);
+
+		timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
+		if (msgs[i].flags & I2C_M_RD)
+			dma_unmap_single(rx_dev, gi2c->rx_ph, msgs[i].len,
+					 DMA_FROM_DEVICE);
+		else
+			dma_unmap_single(tx_dev, gi2c->tx_ph, msgs[i].len,
+					 DMA_TO_DEVICE);
+
+		if (!timeout) {
+			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
+				    "GSI Txn timed out\n");
+			gi2c->err = -ETIMEDOUT;
+		}
+		if (gi2c->err) {
+			dmaengine_terminate_all(gi2c->tx_c);
+			gi2c->cfg_sent = 0;
+			return gi2c->err;
+		}
+	}
+	return gi2c->err;
+}
+
 static int geni_i2c_xfer(struct i2c_adapter *adap,
 			 struct i2c_msg msgs[],
 			 int num)
@@ -324,6 +607,11 @@
 		pm_runtime_set_suspended(gi2c->dev);
 		return ret;
 	}
+	if (gi2c->se_mode == GSI_ONLY) {
+		ret = geni_i2c_gsi_xfer(adap, msgs, num);
+		goto geni_i2c_txn_ret;
+	}
+
 	qcom_geni_i2c_conf(gi2c, 0);
 	dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n",
 				num, msgs[0].len, msgs[0].flags);
@@ -418,8 +706,9 @@
 			break;
 		}
 	}
+geni_i2c_txn_ret:
 	if (ret == 0)
-		ret = i;
+		ret = num;
 	pm_runtime_put_sync(gi2c->dev);
 	gi2c->cur = NULL;
 	gi2c->err = 0;
@@ -592,7 +881,9 @@
 {
 	struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
 
-	disable_irq(gi2c->irq);
+	if (gi2c->se_mode == FIFO_SE_DMA)
+		disable_irq(gi2c->irq);
+
 	se_geni_resources_off(&gi2c->i2c_rsc);
 	return 0;
 }
@@ -612,16 +903,31 @@
 	if (ret)
 		return ret;
 
-	if (unlikely(!gi2c->tx_wm)) {
-		int gi2c_tx_depth = get_tx_fifo_depth(gi2c->base);
+	if (gi2c->se_mode == UNINITIALIZED) {
+		u32 se_mode = readl_relaxed(gi2c->base +
+					GENI_IF_FIFO_DISABLE_RO);
 
-		gi2c->tx_wm = gi2c_tx_depth - 1;
-		geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth);
-		se_config_packing(gi2c->base, 8, 4, true);
-		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
-			    "i2c fifo depth:%d\n", gi2c_tx_depth);
+		if (se_mode) {
+			gi2c->se_mode = GSI_ONLY;
+			geni_se_select_mode(gi2c->base, GSI_DMA);
+			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+				    "i2c in GSI ONLY mode\n");
+		} else {
+			int gi2c_tx_depth = get_tx_fifo_depth(gi2c->base);
+
+			gi2c->se_mode = FIFO_SE_DMA;
+
+			gi2c->tx_wm = gi2c_tx_depth - 1;
+			geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth);
+			se_config_packing(gi2c->base, 8, 4, true);
+			GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
+				    "i2c fifo/se-dma mode. fifo depth:%d\n",
+				    gi2c_tx_depth);
+		}
 	}
-	enable_irq(gi2c->irq);
+	if (gi2c->se_mode == FIFO_SE_DMA)
+		enable_irq(gi2c->irq);
+
 	return 0;
 }
 
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 0dea590..7a6f50b 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -47,6 +47,8 @@
 	struct input_dev *input_dev;
 	s32 count;
 	struct mutex mutex;
+	struct mutex sensormutex;
+	struct hbtp_sensor_data *sensor_data;
 	bool touch_status[HBTP_MAX_FINGER];
 #if defined(CONFIG_FB)
 	struct notifier_block fb_notif;
@@ -88,10 +90,14 @@
 	u32 power_off_delay;
 	bool manage_pin_ctrl;
 	struct kobject *sysfs_kobject;
+	s16 ROI[MAX_ROI_SIZE];
+	s16 accelBuffer[MAX_ACCEL_SIZE];
 };
 
 static struct hbtp_data *hbtp;
 
+static struct kobject *sensor_kobject;
+
 #if defined(CONFIG_FB)
 static int hbtp_fb_suspend(struct hbtp_data *ts);
 static int hbtp_fb_early_resume(struct hbtp_data *ts);
@@ -151,6 +157,46 @@
 }
 #endif
 
+static ssize_t hbtp_sensor_roi_show(struct file *dev, struct kobject *kobj,
+		struct bin_attribute *attr, char *buf, loff_t pos,
+			size_t size) {
+	mutex_lock(&hbtp->sensormutex);
+	memcpy(buf, hbtp->ROI, size);
+	mutex_unlock(&hbtp->sensormutex);
+
+	return size;
+}
+
+static ssize_t hbtp_sensor_vib_show(struct file *dev, struct kobject *kobj,
+		struct bin_attribute *attr, char *buf, loff_t pos,
+			size_t size) {
+	mutex_lock(&hbtp->sensormutex);
+	memcpy(buf, hbtp->accelBuffer, size);
+	mutex_unlock(&hbtp->sensormutex);
+
+	return size;
+}
+
+static struct bin_attribute capdata_attr = {
+	.attr = {
+		.name = "capdata",
+		.mode = 0444,
+		},
+	.size = 1024,
+	.read = hbtp_sensor_roi_show,
+	.write = NULL,
+};
+
+static struct bin_attribute vibdata_attr = {
+	.attr = {
+		.name = "vib_data",
+		.mode = 0444,
+		},
+	.size = MAX_ACCEL_SIZE*sizeof(int16_t),
+	.read = hbtp_sensor_vib_show,
+	.write = NULL,
+};
+
 static int hbtp_input_open(struct inode *inode, struct file *file)
 {
 	mutex_lock(&hbtp->mutex);
@@ -749,6 +795,22 @@
 			return -EINVAL;
 		}
 		break;
+
+	case HBTP_SET_SENSORDATA:
+		if (copy_from_user(hbtp->sensor_data, (void __user *)arg,
+					sizeof(struct hbtp_sensor_data))) {
+			pr_err("%s: Error copying data\n", __func__);
+			return -EFAULT;
+		}
+		mutex_lock(&hbtp->sensormutex);
+		memcpy(hbtp->ROI, hbtp->sensor_data->ROI, sizeof(hbtp->ROI));
+		memcpy(hbtp->accelBuffer, hbtp->sensor_data->accelBuffer,
+			sizeof(hbtp->accelBuffer));
+		mutex_unlock(&hbtp->sensormutex);
+
+		error = 0;
+		break;
+
 	default:
 		pr_err("%s: Unsupported ioctl command %u\n", __func__, cmd);
 		error = -EINVAL;
@@ -1388,13 +1450,19 @@
 
 static int __init hbtp_init(void)
 {
-	int error;
+	int error = 0;
 
 	hbtp = kzalloc(sizeof(struct hbtp_data), GFP_KERNEL);
 	if (!hbtp)
 		return -ENOMEM;
 
+	hbtp->sensor_data = kzalloc(sizeof(struct hbtp_sensor_data),
+			GFP_KERNEL);
+	if (!hbtp->sensor_data)
+		goto err_sensordata;
+
 	mutex_init(&hbtp->mutex);
+	mutex_init(&hbtp->sensormutex);
 
 	error = misc_register(&hbtp_input_misc);
 	if (error) {
@@ -1412,6 +1480,28 @@
 	}
 #endif
 
+	sensor_kobject = kobject_create_and_add("hbtpsensor", kernel_kobj);
+	if (!sensor_kobject) {
+		pr_err("%s: Could not create hbtpsensor kobject\n", __func__);
+		goto err_kobject_create;
+	}
+
+	error = sysfs_create_bin_file(sensor_kobject, &capdata_attr);
+	if (error < 0) {
+		pr_err("%s: hbtp capdata sysfs creation failed: %d\n", __func__,
+			error);
+		goto err_sysfs_create_capdata;
+	}
+	pr_debug("capdata sysfs creation success\n");
+
+	error = sysfs_create_bin_file(sensor_kobject, &vibdata_attr);
+	if (error < 0) {
+		pr_err("%s: vibdata sysfs creation failed: %d\n", __func__,
+			error);
+		goto err_sysfs_create_vibdata;
+	}
+	pr_debug("vibdata sysfs creation success\n");
+
 	error = platform_driver_register(&hbtp_pdev_driver);
 	if (error) {
 		pr_err("Failed to register platform driver: %d\n", error);
@@ -1431,12 +1521,20 @@
 	return 0;
 
 err_platform_drv_reg:
+	sysfs_remove_bin_file(sensor_kobject, &vibdata_attr);
+err_sysfs_create_vibdata:
+	sysfs_remove_bin_file(sensor_kobject, &capdata_attr);
+err_sysfs_create_capdata:
+	kobject_put(sensor_kobject);
+err_kobject_create:
 #if defined(CONFIG_FB)
 	fb_unregister_client(&hbtp->fb_notif);
 err_fb_reg:
 #endif
 	misc_deregister(&hbtp_input_misc);
 err_misc_reg:
+	kfree(hbtp->sensor_data);
+err_sensordata:
 	kfree(hbtp);
 
 	return error;
@@ -1444,6 +1542,9 @@
 
 static void __exit hbtp_exit(void)
 {
+	sysfs_remove_bin_file(sensor_kobject, &vibdata_attr);
+	sysfs_remove_bin_file(sensor_kobject, &capdata_attr);
+	kobject_put(sensor_kobject);
 	misc_deregister(&hbtp_input_misc);
 	if (hbtp->input_dev)
 		input_unregister_device(hbtp->input_dev);
@@ -1454,6 +1555,7 @@
 
 	platform_driver_unregister(&hbtp_pdev_driver);
 
+	kfree(hbtp->sensor_data);
 	kfree(hbtp);
 }
 
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index a1e0908..f923db5 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -475,6 +475,8 @@
 		tcs = get_tcs_from_index(drv, m);
 		if (tcs && tcs->type != ACTIVE_TCS) {
 			data = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
+			data &= ~TCS_AMC_MODE_TRIGGER;
+			write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, data);
 			data &= ~TCS_AMC_MODE_ENABLE;
 			write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, data);
 			/*
@@ -555,7 +557,7 @@
 	u32 msgid, cmd_msgid = 0;
 	u32 cmd_enable = 0;
 	u32 cmd_complete;
-	u32 enable = TCS_AMC_MODE_ENABLE;
+	u32 enable;
 	struct tcs_cmd *cmd;
 	int i;
 	void __iomem *base = drv->reg_base;
@@ -589,12 +591,22 @@
 	write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, cmd_enable);
 
 	if (trigger) {
-		/* HW req: Clear the DRV_CONTROL and enable TCS again */
-		write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, 0);
+		/*
+		 * HW req: Clear the DRV_CONTROL and enable TCS again
+		 * While clearing ensure that the AMC mode trigger is cleared
+		 * and then the mode enable is cleared.
+		 */
+		enable = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
+		enable &= ~TCS_AMC_MODE_TRIGGER;
 		write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
-		/* Enable the AMC mode on the TCS */
+		enable &= ~TCS_AMC_MODE_ENABLE;
+		write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
+
+		/* Enable the AMC mode on the TCS and then trigger the TCS */
+		enable = TCS_AMC_MODE_ENABLE;
+		write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
 		enable |= TCS_AMC_MODE_TRIGGER;
-		write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
+		write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, enable);
 	}
 }
 
diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c
index 44193f5..2c90e47 100644
--- a/drivers/media/platform/msm/broadcast/tspp.c
+++ b/drivers/media/platform/msm/broadcast/tspp.c
@@ -47,6 +47,7 @@
 #include <linux/msm-bus.h>
 #include <linux/interrupt.h>	/* tasklet */
 #include <asm/arch_timer.h> /* Timer */
+#include <linux/dma-buf.h>
 
 /*
  * General defines
@@ -495,7 +496,6 @@
 	struct tspp_pinctrl pinctrl;
 	unsigned int tts_source; /* Time stamp source type LPASS timer/TCR */
 	struct dma_iommu_mapping *iommu_mapping;
-	bool bypass_s1_smmu;
 
 	struct dentry *dent;
 	struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
@@ -1068,7 +1068,6 @@
 static int tspp_iommu_init(struct tspp_device *device)
 {
 	struct dma_iommu_mapping *iommu_map;
-	int s1_bypass = 1;
 
 	iommu_map = arm_iommu_create_mapping(&platform_bus_type,
 						TSPP_SMMU_IOVA_START,
@@ -1077,12 +1076,6 @@
 		dev_err(&device->pdev->dev, "iommu_create_mapping failure\n");
 		return PTR_ERR(iommu_map);
 	}
-	if (iommu_domain_set_attr(iommu_map->domain,
-				  DOMAIN_ATTR_S1_BYPASS, &s1_bypass)) {
-		dev_err(&device->pdev->dev, "Can't bypass s1 translation\n");
-		arm_iommu_release_mapping(iommu_map);
-		return -EIO;
-	}
 	if (arm_iommu_attach_device(&device->pdev->dev, iommu_map)) {
 		dev_err(&device->pdev->dev, "can't arm_iommu_attach_device\n");
 		arm_iommu_release_mapping(iommu_map);
@@ -1095,7 +1088,7 @@
 
 static void tspp_iommu_release_iomapping(struct tspp_device *device)
 {
-	if (device->bypass_s1_smmu && device->iommu_mapping)
+	if (device->iommu_mapping)
 		arm_iommu_release_mapping(device->iommu_mapping);
 
 	device->iommu_mapping = NULL;
@@ -1113,7 +1106,7 @@
 	if (alloc) {
 		TSPP_DEBUG("tspp using alloc function");
 		desc->virt_base = alloc(channel_id, size,
-			&desc->phys_base, user);
+			&desc->phys_base, &desc->dma_base, user);
 	} else {
 		if (!dma_pool)
 			desc->virt_base = dma_alloc_coherent(NULL, size,
@@ -2605,7 +2598,8 @@
 		desc->next = channel->data;
 
 		/* prepare the sps descriptor */
-		desc->sps.phys_base = desc->desc.phys_base;
+		desc->sps.phys_base = ((alloc != NULL) ? desc->desc.dma_base :
+				       desc->desc.phys_base);
 		desc->sps.base = desc->desc.virt_base;
 		desc->sps.size = desc->desc.size;
 
@@ -2643,6 +2637,121 @@
 }
 EXPORT_SYMBOL(tspp_allocate_buffers);
 
+/**
+ * tspp_attach_ion_dma_buff- attach ion dma buffer to TSPP device
+ * It will attach the DMA buffer to TSPP device to go through SMMU.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @ion_dma_buf: It contains required members for ION buffer dma mapping.
+ *
+ * Return  error status
+ *
+ */
+int tspp_attach_ion_dma_buff(u32 dev, struct tspp_ion_dma_buf_info *ion_dma_buf)
+{
+	struct tspp_device *pdev;
+	int dir = DMA_FROM_DEVICE;
+	int ret = -1;
+
+	if (NULL == ion_dma_buf || NULL == ion_dma_buf->dbuf) {
+		pr_err("tspp: invalid input argument");
+		return -EINVAL;
+	}
+
+	if (dev >= TSPP_MAX_DEVICES) {
+		pr_err("tspp: device id out of range");
+		return -ENODEV;
+	}
+
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp: can't find device %i", dev);
+		return -ENODEV;
+	}
+
+	ion_dma_buf->attach = dma_buf_attach(ion_dma_buf->dbuf,
+					&pdev->pdev->dev);
+	if (IS_ERR_OR_NULL(ion_dma_buf->attach)) {
+		dev_err(&pdev->pdev->dev, "%s: dma_buf_attach fail", __func__);
+		return -ENODEV;
+	}
+	ion_dma_buf->table = dma_buf_map_attachment(ion_dma_buf->attach, dir);
+	if (IS_ERR_OR_NULL(ion_dma_buf->table)) {
+		dev_err(&pdev->pdev->dev, "dma_buf_map_attachment fail");
+		dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
+		return -ENODEV;
+	}
+	ret = dma_map_sg(&pdev->pdev->dev, ion_dma_buf->table->sgl,
+				ion_dma_buf->table->nents, dir);
+	if (ret <= 0) {
+		dev_err(&pdev->pdev->dev, "dma_map_sg failed! ret=%d\n", ret);
+		goto unmap_attachment;
+	}
+	if (ion_dma_buf->table->nents > 1) {
+		dev_err(&pdev->pdev->dev, "no of sg table entries %d > 1\n",
+			ion_dma_buf->table->nents);
+		goto unmap_attachment;
+	}
+
+	ion_dma_buf->dma_map_base = sg_dma_address(ion_dma_buf->table->sgl);
+	ion_dma_buf->smmu_map = true;
+	return 0;
+
+unmap_attachment:
+	dma_buf_unmap_attachment(ion_dma_buf->attach, ion_dma_buf->table, dir);
+	dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
+	dma_buf_put(ion_dma_buf->dbuf);
+
+	return ret;
+}
+EXPORT_SYMBOL(tspp_attach_ion_dma_buff);
+
+/**
+ * tspp_detach_ion_dma_buff - detach the mapped ion dma buffer from TSPP device
+ * It will detach previously mapped DMA buffer from TSPP device.
+ *
+ * @dev: TSPP device (up to TSPP_MAX_DEVICES)
+ * @ion_dma_buf: It contains required members for ION buffer dma mapping.
+ *
+ * Return  error status
+ *
+ */
+int tspp_detach_ion_dma_buff(u32 dev, struct tspp_ion_dma_buf_info *ion_dma_buf)
+{
+	struct tspp_device *pdev;
+	int dir = DMA_FROM_DEVICE;
+
+	if (ion_dma_buf == NULL || ion_dma_buf->dbuf == NULL ||
+	    ion_dma_buf->table == NULL || ion_dma_buf->table->sgl == NULL ||
+	    ion_dma_buf->smmu_map == false) {
+		pr_err("tspp: invalid input argument");
+		return -EINVAL;
+	}
+
+	if (dev >= TSPP_MAX_DEVICES) {
+		pr_err("tspp: device id out of range");
+		return -ENODEV;
+	}
+
+	pdev = tspp_find_by_id(dev);
+	if (!pdev) {
+		pr_err("tspp: can't find device %i", dev);
+		return -ENODEV;
+	}
+
+
+	dma_unmap_sg(&pdev->pdev->dev, ion_dma_buf->table->sgl,
+			ion_dma_buf->table->nents, dir);
+	dma_buf_unmap_attachment(ion_dma_buf->attach, ion_dma_buf->table, dir);
+	dma_buf_detach(ion_dma_buf->dbuf, ion_dma_buf->attach);
+	dma_buf_put(ion_dma_buf->dbuf);
+
+	ion_dma_buf->smmu_map = false;
+	return 0;
+}
+EXPORT_SYMBOL(tspp_detach_ion_dma_buff);
+
+
 /*** debugfs ***/
 static int debugfs_iomem_x32_set(void *data, u64 val)
 {
@@ -3002,12 +3111,9 @@
 		goto err_irq;
 	device->req_irqs = false;
 
-	if (of_property_read_bool(pdev->dev.of_node, "qcom,smmu-s1-bypass")) {
-		device->bypass_s1_smmu = true;
-		if (tspp_iommu_init(device)) {
-			dev_err(&pdev->dev, "iommu init failed");
-			goto err_iommu;
-		}
+	if (tspp_iommu_init(device)) {
+		dev_err(&pdev->dev, "iommu init failed");
+		goto err_iommu;
 	}
 
 	device->tts_source = TSIF_TTS_TCR;
@@ -3152,6 +3258,9 @@
 	if (device->tsif_vreg)
 		regulator_disable(device->tsif_vreg);
 
+	tspp_iommu_release_iomapping(device);
+	arm_iommu_detach_device(&pdev->dev);
+
 	pm_runtime_disable(&pdev->dev);
 
 	kfree(device);
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
index 1ee82b5..01c629d 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c
@@ -382,6 +382,7 @@
 	req_hdl_param.v4l2_sub_dev_flag = 0;
 	req_hdl_param.media_entity_flag = 0;
 	req_hdl_param.priv = ctx;
+	req_hdl_param.ops = ctx->crm_ctx_intf;
 
 	ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param);
 	if (ctx->dev_hdl <= 0) {
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
index 9150795..f74938d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
@@ -110,4 +110,13 @@
  */
 void cam_hfi_deinit(void);
 
+/**
+ * hfi_enable_ipe_bps_pc() - Enable interframe pc
+ * Host sends a command to firmware to enable interframe
+ * power collapse for IPE and BPS hardware.
+ *
+ * @enable: flag to enable/disable
+ */
+int hfi_enable_ipe_bps_pc(bool enable);
+
 #endif /* _HFI_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
index e7163ac..65dc4b3 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
@@ -158,6 +158,7 @@
 #define HFI_PROP_SYS_DEBUG_CFG         (HFI_PROPERTY_ICP_COMMON_START + 0x1)
 #define HFI_PROP_SYS_IMAGE_VER         (HFI_PROPERTY_ICP_COMMON_START + 0x3)
 #define HFI_PROP_SYS_SUPPORTED         (HFI_PROPERTY_ICP_COMMON_START + 0x4)
+#define HFI_PROP_SYS_IPEBPS_PC         (HFI_PROPERTY_ICP_COMMON_START + 0x5)
 
 /* Capabilities reported at sys init */
 #define HFI_CAPS_PLACEHOLDER_1         (HFI_COMMON_BASE + 0x1)
@@ -246,6 +247,14 @@
 	uint32_t debug_mode;
 } __packed;
 
+/**
+ * struct hfi_ipe_bps_pc
+ * payload structure to configure HFI_PROPERTY_SYS_IPEBPS_PC
+ * @enable: Flag to enable IPE, BPS interfrane power collapse
+ */
+struct hfi_ipe_bps_pc {
+	uint32_t enable;
+} __packed;
 
 /**
  * struct hfi_cmd_sys_init
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index 48e1f1c..68ce696f 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -193,6 +193,32 @@
 	return rc;
 }
 
+int hfi_enable_ipe_bps_pc(bool enable)
+{
+	uint8_t *prop;
+	struct hfi_cmd_prop *dbg_prop;
+	uint32_t size = 0;
+
+	size = sizeof(struct hfi_cmd_prop) +
+		sizeof(struct hfi_ipe_bps_pc);
+
+	prop = kzalloc(size, GFP_KERNEL);
+	if (!prop)
+		return -ENOMEM;
+
+	dbg_prop = (struct hfi_cmd_prop *)prop;
+	dbg_prop->size = size;
+	dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY;
+	dbg_prop->num_prop = 1;
+	dbg_prop->prop_data[0] = HFI_PROP_SYS_IPEBPS_PC;
+	dbg_prop->prop_data[1] = enable;
+
+	hfi_write_cmd(prop);
+	kfree(prop);
+
+	return 0;
+}
+
 void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size)
 {
 	switch (type) {
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c
index 08b934e..daffae8 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c
@@ -166,7 +166,7 @@
 
 static const struct of_device_id cam_a5_dt_match[] = {
 	{
-		.compatible = "qcom,cam_a5",
+		.compatible = "qcom,cam-a5",
 		.data = &cam_a5_hw_info,
 	},
 	{}
@@ -176,7 +176,7 @@
 static struct platform_driver cam_a5_driver = {
 	.probe = cam_a5_probe,
 	.driver = {
-		.name = "cam_a5",
+		.name = "cam-a5",
 		.owner = THIS_MODULE,
 		.of_match_table = cam_a5_dt_match,
 	},
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
index 557eaf1..55a2e1b 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
@@ -133,6 +133,77 @@
 	return rc;
 }
 
+static int cam_bps_handle_pc(struct cam_hw_info *bps_dev)
+{
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_bps_device_core_info *core_info = NULL;
+	struct cam_bps_device_hw_info *hw_info = NULL;
+	int pwr_ctrl;
+	int pwr_status;
+
+	soc_info = &bps_dev->soc_info;
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+	hw_info = core_info->bps_hw_info;
+
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl,
+		true, &pwr_ctrl);
+	if (!(pwr_ctrl & BPS_COLLAPSE_MASK)) {
+		cam_cpas_reg_read(core_info->cpas_handle,
+			CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+			true, &pwr_status);
+
+		cam_cpas_reg_write(core_info->cpas_handle,
+			CAM_CPAS_REG_CPASTOP,
+			hw_info->pwr_ctrl, true, 0x1);
+
+		if ((pwr_status >> BPS_PWR_ON_MASK))
+			return -EINVAL;
+	}
+	cam_bps_get_gdsc_control(soc_info);
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true,
+		&pwr_ctrl);
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+		true, &pwr_status);
+	CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x",
+		pwr_ctrl, pwr_status);
+
+	return 0;
+}
+
+static int cam_bps_handle_resume(struct cam_hw_info *bps_dev)
+{
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_bps_device_core_info *core_info = NULL;
+	struct cam_bps_device_hw_info *hw_info = NULL;
+	int pwr_ctrl;
+	int pwr_status;
+	int rc = 0;
+
+	soc_info = &bps_dev->soc_info;
+	core_info = (struct cam_bps_device_core_info *)bps_dev->core_info;
+	hw_info = core_info->bps_hw_info;
+
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl);
+	if (pwr_ctrl & BPS_COLLAPSE_MASK) {
+		CAM_ERR(CAM_ICP, "BPS: resume failed : %d", pwr_ctrl);
+		return -EINVAL;
+	}
+
+	rc = cam_bps_transfer_gdsc_control(soc_info);
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl);
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status);
+	CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x",
+		pwr_ctrl, pwr_status);
+
+	return rc;
+}
+
 int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type,
 	void *cmd_args, uint32_t arg_size)
 {
@@ -192,6 +263,12 @@
 			core_info->cpas_start = false;
 		}
 		break;
+	case CAM_ICP_BPS_CMD_POWER_COLLAPSE:
+		rc = cam_bps_handle_pc(bps_dev);
+		break;
+	case CAM_ICP_BPS_CMD_POWER_RESUME:
+		rc = cam_bps_handle_resume(bps_dev);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.h
index 8a15a7b..0a28bb4f 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.h
@@ -19,7 +19,13 @@
 #include <linux/platform_device.h>
 #include <linux/dma-buf.h>
 
+#define BPS_COLLAPSE_MASK 0x1
+#define BPS_PWR_ON_MASK   0x2
+
 struct cam_bps_device_hw_info {
+	uint32_t hw_idx;
+	uint32_t pwr_ctrl;
+	uint32_t pwr_status;
 	uint32_t reserved;
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c
index ddff677..419bb52 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c
@@ -25,7 +25,10 @@
 #include "cam_cpas_api.h"
 #include "cam_debug_util.h"
 
-struct cam_bps_device_hw_info cam_bps_hw_info = {
+static struct cam_bps_device_hw_info cam_bps_hw_info = {
+	.hw_idx = 0,
+	.pwr_ctrl = 0x5c,
+	.pwr_status = 0x58,
 	.reserved = 0,
 };
 EXPORT_SYMBOL(cam_bps_hw_info);
@@ -100,7 +103,7 @@
 		rc = -EINVAL;
 		return rc;
 	}
-	hw_info = (struct cam_bps_device_hw_info *)match_dev->data;
+	hw_info = &cam_bps_hw_info;
 	core_info->bps_hw_info = hw_info;
 
 	rc = cam_bps_init_soc_resources(&bps_dev->soc_info, cam_bps_irq,
@@ -135,7 +138,7 @@
 
 static const struct of_device_id cam_bps_dt_match[] = {
 	{
-		.compatible = "qcom,cam_bps",
+		.compatible = "qcom,cam-bps",
 		.data = &cam_bps_hw_info,
 	},
 	{}
@@ -145,7 +148,7 @@
 static struct platform_driver cam_bps_driver = {
 	.probe = cam_bps_probe,
 	.driver = {
-		.name = "cam_bps",
+		.name = "cam-bps",
 		.owner = THIS_MODULE,
 		.of_match_table = cam_bps_dt_match,
 	},
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
index 54e898c..07dacb2 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
@@ -82,3 +82,53 @@
 
 	return rc;
 }
+
+int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info)
+{
+	int i;
+	int rc;
+
+	for (i = 0; i < soc_info->num_rgltr; i++) {
+		rc = regulator_set_mode(soc_info->rgltr[i],
+			REGULATOR_MODE_FAST);
+		if (rc) {
+			CAM_ERR(CAM_ICP, "Regulator set mode %s failed",
+				soc_info->rgltr_name[i]);
+			goto rgltr_set_mode_failed;
+		}
+	}
+	return 0;
+
+rgltr_set_mode_failed:
+	for (i = i - 1; i >= 0; i--)
+		if (soc_info->rgltr[i])
+			regulator_set_mode(soc_info->rgltr[i],
+					REGULATOR_MODE_NORMAL);
+
+	return rc;
+}
+
+int cam_bps_get_gdsc_control(struct cam_hw_soc_info *soc_info)
+{
+	int i;
+	int rc;
+
+	for (i = 0; i < soc_info->num_rgltr; i++) {
+		rc = regulator_set_mode(soc_info->rgltr[i],
+			REGULATOR_MODE_NORMAL);
+		if (rc) {
+			CAM_ERR(CAM_ICP, "Regulator set mode %s failed",
+				soc_info->rgltr_name[i]);
+			goto rgltr_set_mode_failed;
+		}
+	}
+	return 0;
+
+rgltr_set_mode_failed:
+	for (i = i - 1; i >= 0; i--)
+		if (soc_info->rgltr[i])
+			regulator_set_mode(soc_info->rgltr[i],
+					REGULATOR_MODE_FAST);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
index b16db01..3cffb09 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
@@ -22,4 +22,8 @@
 
 int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info);
 
+int cam_bps_get_gdsc_control(struct cam_hw_soc_info *soc_info);
+
+int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info);
+
 #endif /* _CAM_BPS_SOC_H_*/
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 1b3afc0..f878403 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -46,12 +46,88 @@
 #include "hfi_sys_defs.h"
 #include "cam_debug_util.h"
 
-#define ICP_WORKQ_NUM_TASK 30
+#define ICP_WORKQ_NUM_TASK      30
 #define ICP_WORKQ_TASK_CMD_TYPE 1
 #define ICP_WORKQ_TASK_MSG_TYPE 2
 
 static struct cam_icp_hw_mgr icp_hw_mgr;
 
+static int cam_icp_mgr_ipe_bps_resume(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data)
+{
+	struct cam_hw_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+	int rc = 0;
+
+	if (!icp_hw_mgr.icp_pc_flag)
+		return rc;
+
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+	if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+		CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close");
+		return -EINVAL;
+	}
+
+	bps_dev_intf->hw_ops.process_cmd(
+		bps_dev_intf->hw_priv,
+		CAM_ICP_BPS_CMD_POWER_RESUME, NULL, 0);
+
+	ipe0_dev_intf->hw_ops.process_cmd(
+		ipe0_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
+
+	if (ipe1_dev_intf) {
+		ipe1_dev_intf->hw_ops.process_cmd(
+			ipe1_dev_intf->hw_priv,
+			CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
+	}
+
+	rc = hfi_enable_ipe_bps_pc(true);
+
+	return rc;
+}
+
+static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data, int dev_type)
+{
+	int rc = 0;
+	struct cam_hw_intf *ipe0_dev_intf = NULL;
+	struct cam_hw_intf *ipe1_dev_intf = NULL;
+	struct cam_hw_intf *bps_dev_intf = NULL;
+
+	if (!icp_hw_mgr.icp_pc_flag)
+		return rc;
+
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+	if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+		CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close");
+		return -EINVAL;
+	}
+
+	rc = bps_dev_intf->hw_ops.process_cmd(
+		bps_dev_intf->hw_priv,
+		CAM_ICP_BPS_CMD_POWER_COLLAPSE, NULL, 0);
+
+	rc = ipe0_dev_intf->hw_ops.process_cmd(
+		ipe0_dev_intf->hw_priv,
+		CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
+
+	if (ipe1_dev_intf) {
+		rc = ipe1_dev_intf->hw_ops.process_cmd(
+			ipe1_dev_intf->hw_priv,
+			CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
+	}
+
+	return rc;
+}
+
 static int cam_icp_hw_mgr_create_debugfs_entry(void)
 {
 	icp_hw_mgr.dentry = debugfs_create_dir("camera_icp", NULL);
@@ -66,6 +142,14 @@
 		return -ENOMEM;
 	}
 
+	if (!debugfs_create_bool("icp_pc",
+		0644,
+		icp_hw_mgr.dentry,
+		&icp_hw_mgr.icp_pc_flag)) {
+		CAM_ERR(CAM_ICP, "failed to create icp_pc entry");
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
@@ -88,34 +172,27 @@
 	return rc;
 }
 
-static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr)
+static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag)
 {
 	int i;
 	uint32_t idx;
 	uint64_t request_id;
 	struct cam_icp_hw_ctx_data *ctx_data = NULL;
 	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
-	struct hfi_msg_frame_process_done *frame_done;
 	struct hfi_frame_process_info *hfi_frame_process;
 	struct cam_hw_done_event_data buf_data;
 
 	ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
-	if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
-		CAM_ERR(CAM_ICP, "failed with error : %u",
-			ioconfig_ack->err_type);
-		return -EIO;
-	}
-
-	frame_done =
-		(struct hfi_msg_frame_process_done *)ioconfig_ack->msg_data;
-	if (frame_done->result) {
-		CAM_ERR(CAM_ICP, "result : %u", frame_done->result);
-		return -EIO;
-	}
-
-	ctx_data = (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
 	request_id = ioconfig_ack->user_data2;
+	ctx_data = (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1;
+	if (!ctx_data) {
+		CAM_ERR(CAM_ICP, "Invalid Context");
+		return -EINVAL;
+	}
+	CAM_DBG(CAM_ICP, "ctx : %pK, request_id :%lld",
+		(void *)ctx_data->context_priv, request_id);
 
+	mutex_lock(&ctx_data->ctx_mutex);
 	hfi_frame_process = &ctx_data->hfi_frame_process;
 	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
 		if (hfi_frame_process->request_id[i] == request_id)
@@ -124,23 +201,55 @@
 	if (i >= CAM_FRAME_CMD_MAX) {
 		CAM_ERR(CAM_ICP, "pkt not found in ctx data for req_id =%lld",
 			request_id);
+		mutex_unlock(&ctx_data->ctx_mutex);
 		return -EINVAL;
 	}
 	idx = i;
 
 	buf_data.request_id = hfi_frame_process->request_id[idx];
-	ctx_data->ctxt_event_cb(ctx_data->context_priv, false, &buf_data);
-
-	/* now release memory for hfi frame process command */
-	CAM_DBG(CAM_ICP, "matching request id: %lld",
-			hfi_frame_process->request_id[idx]);
-	mutex_lock(&ctx_data->hfi_frame_process.lock);
+	ctx_data->ctxt_event_cb(ctx_data->context_priv, flag, &buf_data);
 	hfi_frame_process->request_id[idx] = 0;
 	clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
-	mutex_unlock(&ctx_data->hfi_frame_process.lock);
+	mutex_unlock(&ctx_data->ctx_mutex);
+
 	return 0;
 }
 
+static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr)
+{
+	struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL;
+	struct hfi_msg_frame_process_done *frame_done;
+
+	if (!msg_ptr) {
+		CAM_ERR(CAM_ICP, "msg ptr is NULL");
+		return -EINVAL;
+	}
+
+	ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
+	if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
+		CAM_ERR(CAM_ICP, "failed with error : %u",
+			ioconfig_ack->err_type);
+		cam_icp_mgr_handle_frame_process(msg_ptr,
+			ICP_FRAME_PROCESS_FAILURE);
+		return -EIO;
+	}
+
+	frame_done =
+		(struct hfi_msg_frame_process_done *)ioconfig_ack->msg_data;
+	if (!frame_done) {
+		cam_icp_mgr_handle_frame_process(msg_ptr,
+			ICP_FRAME_PROCESS_FAILURE);
+		return -EINVAL;
+	}
+
+	if (frame_done->result)
+		return cam_icp_mgr_handle_frame_process(msg_ptr,
+			ICP_FRAME_PROCESS_FAILURE);
+	else
+		return cam_icp_mgr_handle_frame_process(msg_ptr,
+			ICP_FRAME_PROCESS_SUCCESS);
+}
+
 static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr)
 {
 	struct cam_icp_hw_ctx_data *ctx_data = NULL;
@@ -148,6 +257,11 @@
 	struct hfi_msg_ipe_config *ipe_config_ack = NULL;
 	struct hfi_msg_bps_common *bps_config_ack = NULL;
 
+	if (!msg_ptr) {
+		CAM_ERR(CAM_ICP, "msg ptr is NULL");
+		return -EINVAL;
+	}
+
 	ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
 
 	if (ioconfig_ack->opcode == HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO) {
@@ -164,10 +278,7 @@
 			CAM_ERR(CAM_ICP, "wrong ctx data from IPE response");
 			return -EINVAL;
 		}
-
-		mutex_lock(&ctx_data->ctx_mutex);
 		ctx_data->scratch_mem_size = ipe_config_ack->scratch_mem_size;
-		mutex_unlock(&ctx_data->ctx_mutex);
 	} else {
 		bps_config_ack =
 			(struct hfi_msg_bps_common *)(ioconfig_ack->msg_data);
@@ -205,9 +316,7 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&ctx_data->ctx_mutex);
 	ctx_data->fw_handle = create_handle_ack->fw_handle;
-	mutex_unlock(&ctx_data->ctx_mutex);
 	CAM_DBG(CAM_ICP, "fw_handle = %x", ctx_data->fw_handle);
 	complete(&ctx_data->wait_complete);
 
@@ -240,6 +349,11 @@
 {
 	int rc;
 
+	if (!msg_ptr) {
+		CAM_ERR(CAM_ICP, "msg ptr is NULL");
+		return -EINVAL;
+	}
+
 	switch (msg_ptr[ICP_PACKET_OPCODE]) {
 	case HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO:
 	case HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO:
@@ -258,10 +372,11 @@
 	default:
 		CAM_ERR(CAM_ICP, "Invalid opcode : %u",
 			msg_ptr[ICP_PACKET_OPCODE]);
+		rc = -EINVAL;
 		break;
 	}
 
-	return 0;
+	return rc;
 }
 
 static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr)
@@ -315,7 +430,6 @@
 
 	msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf;
 
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	switch (msg_ptr[ICP_PACKET_TYPE]) {
 	case HFI_MSG_SYS_INIT_DONE:
 		CAM_DBG(CAM_ICP, "received SYS_INIT_DONE");
@@ -347,11 +461,10 @@
 	default:
 		CAM_ERR(CAM_ICP, "invalid msg : %u",
 			msg_ptr[ICP_PACKET_TYPE]);
+		rc = -EINVAL;
 		break;
 	}
 
-	mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
-
 	return rc;
 }
 
@@ -521,20 +634,18 @@
 
 static void cam_icp_mgr_put_ctx(struct cam_icp_hw_ctx_data *ctx_data)
 {
-	mutex_lock(&ctx_data->ctx_mutex);
 	ctx_data->in_use = false;
-	mutex_unlock(&ctx_data->ctx_mutex);
 }
 
 static int cam_icp_mgr_abort_handle(
 	struct cam_icp_hw_ctx_data *ctx_data)
 {
 	int rc = 0;
+	unsigned long rem_jiffies;
 	int timeout = 5000;
 	struct hfi_cmd_work_data *task_data;
 	struct hfi_cmd_ipebps_async abort_cmd;
 	struct crm_workq_task *task;
-	unsigned long rem_jiffies;
 
 	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
 	if (!task)
@@ -585,10 +696,10 @@
 {
 	int rc = 0;
 	int timeout = 5000;
+	unsigned long rem_jiffies;
 	struct hfi_cmd_work_data *task_data;
 	struct hfi_cmd_ipebps_async destroy_cmd;
 	struct crm_workq_task *task;
-	unsigned long rem_jiffies;
 
 	task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
 	if (!task)
@@ -643,25 +754,20 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 	if (!hw_mgr->ctx_data[ctx_id].in_use) {
 		mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		return 0;
 	}
-	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
-
 	cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]);
 
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
-	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 	hw_mgr->ctx_data[ctx_id].in_use = false;
 	hw_mgr->ctx_data[ctx_id].fw_handle = 0;
 	hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0;
-	mutex_lock(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
 	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
 		clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
-	mutex_unlock(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
-	mutex_destroy(&hw_mgr->ctx_data[ctx_id].hfi_frame_process.lock);
 	kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
 	hw_mgr->ctxt_cnt--;
 	kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info);
@@ -737,8 +843,8 @@
 		sizeof(fw_buf_info));
 	if (rc)
 		CAM_ERR(CAM_ICP, "nullify the fw buf failed");
-
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
 		cam_icp_mgr_release_ctx(hw_mgr, i);
 
@@ -748,7 +854,8 @@
 	cam_icp_free_hfi_mem();
 	hw_mgr->fw_download = false;
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
-	return 0;
+
+	return rc;
 }
 
 static int cam_icp_mgr_device_init(struct cam_icp_hw_mgr *hw_mgr)
@@ -808,6 +915,10 @@
 	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
 
 	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	if (!a5_dev_intf) {
+		CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+		return -EINVAL;
+	}
 	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 
 	irq_cb.icp_hw_mgr_cb = cam_icp_hw_mgr_cb;
@@ -853,6 +964,10 @@
 	struct hfi_mem_info hfi_mem;
 
 	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	if (!a5_dev_intf) {
+		CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+		return -EINVAL;
+	}
 	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 
 	hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva;
@@ -891,6 +1006,11 @@
 	int timeout = 5000;
 
 	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	if (!a5_dev_intf) {
+		CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+		return -EINVAL;
+	}
+
 	reinit_completion(&hw_mgr->a5_complete);
 	CAM_DBG(CAM_ICP, "Sending HFI init command");
 	rc = a5_dev_intf->hw_ops.process_cmd(
@@ -931,6 +1051,11 @@
 	}
 
 	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+	if (!a5_dev_intf) {
+		CAM_ERR(CAM_ICP, "a5_dev_intf is invalid");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		return -EINVAL;
+	}
 	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 	rc = cam_icp_allocate_hfi_mem();
 	if (rc) {
@@ -955,11 +1080,12 @@
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		goto hfi_init_failed;
 	}
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	rc = cam_icp_mgr_send_fw_init(hw_mgr);
-	if (rc)
+	if (rc) {
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		goto fw_init_failed;
+	}
 
 	rc = a5_dev_intf->hw_ops.process_cmd(
 		a5_dev_intf->hw_priv,
@@ -967,6 +1093,7 @@
 		NULL, 0);
 	hw_mgr->fw_download = true;
 	hw_mgr->ctxt_cnt = 0;
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	CAM_DBG(CAM_ICP, "FW download done successfully");
 	if (!download_fw_args)
 		cam_icp_mgr_hw_close(hw_mgr, NULL);
@@ -990,7 +1117,6 @@
 {
 	struct cam_hw_done_event_data buf_data;
 
-	buf_data.num_handles = config_args->num_out_map_entries;
 	buf_data.request_id = *(uint64_t *)config_args->priv;
 	ctx_data->ctxt_event_cb(ctx_data->context_priv, true, &buf_data);
 
@@ -1047,22 +1173,22 @@
 		return -EINVAL;
 	}
 
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	ctx_data = config_args->ctxt_to_hw_map;
+	mutex_lock(&ctx_data->ctx_mutex);
 	if (!ctx_data->in_use) {
 		CAM_ERR(CAM_ICP, "ctx is not in use");
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		rc = -EINVAL;
 		goto config_err;
 	}
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args);
 	if (rc)
 		goto config_err;
+	mutex_unlock(&ctx_data->ctx_mutex);
 
 	return 0;
 config_err:
+	mutex_unlock(&ctx_data->ctx_mutex);
 	cam_icp_mgr_handle_config_err(config_args, ctx_data);
 	return rc;
 }
@@ -1177,16 +1303,13 @@
 {
 	int32_t index;
 
-	mutex_lock(&ctx_data->hfi_frame_process.lock);
 	index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap,
 		ctx_data->hfi_frame_process.bits);
 	if (index < 0 || index >= CAM_FRAME_CMD_MAX) {
 		CAM_ERR(CAM_ICP, "request idx is wrong: %d", index);
-		mutex_unlock(&ctx_data->hfi_frame_process.lock);
 		return -EINVAL;
 	}
 	set_bit(index, ctx_data->hfi_frame_process.bitmap);
-	mutex_unlock(&ctx_data->hfi_frame_process.lock);
 
 	ctx_data->hfi_frame_process.request_id[index] =
 		packet->header.request_id;
@@ -1215,29 +1338,34 @@
 	}
 
 	ctx_data = prepare_args->ctxt_to_hw_map;
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	mutex_lock(&ctx_data->ctx_mutex);
 	if (!ctx_data->in_use) {
-		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		mutex_unlock(&ctx_data->ctx_mutex);
 		CAM_ERR(CAM_ICP, "ctx is not in use");
 		return -EINVAL;
 	}
-	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	packet = prepare_args->packet;
 
 	rc = cam_icp_mgr_pkt_validation(packet);
-	if (rc)
+	if (rc) {
+		mutex_unlock(&ctx_data->ctx_mutex);
 		return rc;
+	}
 
 	rc = cam_icp_mgr_process_cmd_desc(hw_mgr, packet,
 		&fw_cmd_buf_iova_addr);
-	if (rc)
+	if (rc) {
+		mutex_unlock(&ctx_data->ctx_mutex);
 		return rc;
+	}
 
 	/* Update Buffer Address from handles and patch information */
 	rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl);
-	if (rc)
+	if (rc) {
+		mutex_unlock(&ctx_data->ctx_mutex);
 		return rc;
+	}
 
 	cam_icp_mgr_process_io_cfg(hw_mgr, ctx_data,
 		packet, prepare_args);
@@ -1248,12 +1376,12 @@
 		if (prepare_args->in_map_entries[0].sync_id > 0)
 			cam_sync_destroy(
 				prepare_args->in_map_entries[0].sync_id);
+		mutex_unlock(&ctx_data->ctx_mutex);
 		return rc;
 	}
 
 	hfi_cmd = (struct hfi_cmd_ipebps_async *)
 			&ctx_data->hfi_frame_process.hfi_frame_cmd[idx];
-
 	cam_icp_mgr_prepare_frame_process_cmd(
 		ctx_data, hfi_cmd, packet->header.request_id,
 		fw_cmd_buf_iova_addr);
@@ -1262,6 +1390,7 @@
 	prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd;
 	prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx];
 
+	mutex_unlock(&ctx_data->ctx_mutex);
 	return rc;
 }
 
@@ -1270,7 +1399,7 @@
 	struct hfi_frame_process_info *hfi_frame_process;
 	int idx;
 
-	mutex_lock(&ctx_data->hfi_frame_process.lock);
+	mutex_lock(&ctx_data->ctx_mutex);
 	hfi_frame_process = &ctx_data->hfi_frame_process;
 	for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) {
 		if (!hfi_frame_process->request_id[idx])
@@ -1283,7 +1412,7 @@
 		hfi_frame_process->request_id[idx] = 0;
 		clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
 	}
-	mutex_unlock(&ctx_data->hfi_frame_process.lock);
+	mutex_unlock(&ctx_data->ctx_mutex);
 
 	return 0;
 }
@@ -1303,10 +1432,16 @@
 
 	ctx_data = release_hw->ctxt_to_hw_map;
 	ctx_id = ctx_data->ctx_id;
-	if (ctx_id < 0 || ctx_id >= CAM_ICP_CTX_MAX) {
+	if (ctx_id < 0 || ctx_id >= CAM_ICP_CTX_MAX)
 		CAM_ERR(CAM_ICP, "Invalid ctx id: %d", ctx_id);
+
+	mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+	if (!hw_mgr->ctx_data[ctx_id].in_use) {
+		CAM_DBG(CAM_ICP, "ctx is not in use: %d", ctx_id);
+		mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 		return -EINVAL;
 	}
+	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 
 	if (release_hw->active_req) {
 		cam_icp_mgr_abort_handle(ctx_data);
@@ -1314,8 +1449,11 @@
 	}
 
 	rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
-	if (!hw_mgr->ctxt_cnt)
+	if (!hw_mgr->ctxt_cnt) {
+		cam_icp_mgr_ipe_bps_power_collapse(hw_mgr,
+			NULL, 0);
 		cam_icp_mgr_hw_close(hw_mgr, NULL);
+	}
 
 	return rc;
 }
@@ -1342,7 +1480,6 @@
 		ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
 
 	reinit_completion(&ctx_data->wait_complete);
-
 	ioconfig_cmd.num_fw_handles = 1;
 	ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle;
 	ioconfig_cmd.payload.indirect = io_buf_addr;
@@ -1386,7 +1523,6 @@
 	create_handle.pkt_type = HFI_CMD_IPEBPS_CREATE_HANDLE;
 	create_handle.handle_type = dev_type;
 	create_handle.user_data1 = (uint64_t)ctx_data;
-
 	reinit_completion(&ctx_data->wait_complete);
 	task_data = (struct hfi_cmd_work_data *)task->payload;
 	task_data->data = (void *)&create_handle;
@@ -1426,7 +1562,6 @@
 	ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt);
 	ping_pkt.pkt_type = HFI_CMD_SYS_PING;
 	ping_pkt.user_data = (uint64_t)ctx_data;
-
 	init_completion(&ctx_data->wait_complete);
 	task_data = (struct hfi_cmd_work_data *)task->payload;
 	task_data->data = (void *)&ping_pkt;
@@ -1469,6 +1604,12 @@
 		return -EINVAL;
 	}
 
+	if (icp_dev_acquire_info.dev_type >= CAM_ICP_RES_TYPE_MAX) {
+		CAM_ERR(CAM_ICP, "Invalid device type: %d",
+			icp_dev_acquire_info.dev_type);
+		return -EFAULT;
+	}
+
 	acquire_size = sizeof(struct cam_icp_acquire_dev_info) +
 		(icp_dev_acquire_info.num_out_res *
 		sizeof(struct cam_icp_res_info));
@@ -1493,7 +1634,7 @@
 		ctx_data->icp_dev_acquire_info->scratch_mem_size);
 
 	p_icp_out = ctx_data->icp_dev_acquire_info->out_res;
-	for (i = 0; i < ctx_data->icp_dev_acquire_info->num_out_res; i++)
+	for (i = 0; i < icp_dev_acquire_info.num_out_res; i++)
 		CAM_DBG(CAM_ICP, "out[i] %x %x %x %x",
 			p_icp_out[i].format,
 			p_icp_out[i].width,
@@ -1539,12 +1680,9 @@
 
 	mutex_lock(&ctx_data->ctx_mutex);
 	rc = cam_icp_get_acquire_info(hw_mgr, args, ctx_data);
-	if (rc) {
-		mutex_unlock(&ctx_data->ctx_mutex);
+	if (rc)
 		goto acquire_info_failed;
-	}
 	icp_dev_acquire_info = ctx_data->icp_dev_acquire_info;
-	mutex_unlock(&ctx_data->ctx_mutex);
 
 	/* Get IOCONFIG command info */
 	if (icp_dev_acquire_info->secure_mode)
@@ -1573,6 +1711,9 @@
 		rc = cam_icp_mgr_download_fw(hw_mgr, ctx_data);
 		if (rc)
 			goto get_io_buf_failed;
+		rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data);
+		if (rc)
+			goto ipe_bps_resume_failed;
 		mutex_lock(&hw_mgr->hw_mgr_mutex);
 	}
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
@@ -1596,7 +1737,6 @@
 		goto ioconfig_failed;
 	}
 
-	mutex_lock(&ctx_data->ctx_mutex);
 	ctx_data->context_priv = args->context_data;
 	args->ctxt_to_hw_map = ctx_data;
 
@@ -1606,15 +1746,14 @@
 	if (!ctx_data->hfi_frame_process.bitmap)
 		goto ioconfig_failed;
 	ctx_data->hfi_frame_process.bits = bitmap_size * BITS_PER_BYTE;
-	mutex_init(&ctx_data->hfi_frame_process.lock);
 	hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb;
 	icp_dev_acquire_info->scratch_mem_size = ctx_data->scratch_mem_size;
-	mutex_unlock(&ctx_data->ctx_mutex);
 
 	if (copy_to_user((void __user *)args->acquire_info,
 		icp_dev_acquire_info, sizeof(struct cam_icp_acquire_dev_info)))
 		goto copy_to_user_failed;
 
+	mutex_unlock(&ctx_data->ctx_mutex);
 	CAM_DBG(CAM_ICP, "scratch size = %x fw_handle = %x",
 			(unsigned int)icp_dev_acquire_info->scratch_mem_size,
 			(unsigned int)ctx_data->fw_handle);
@@ -1629,8 +1768,10 @@
 	ctx_data->hfi_frame_process.bitmap = NULL;
 ioconfig_failed:
 	cam_icp_mgr_destroy_handle(ctx_data);
-send_ping_failed:
 create_handle_failed:
+send_ping_failed:
+	cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, ctx_data, 0);
+ipe_bps_resume_failed:
 	if (!hw_mgr->ctxt_cnt)
 		cam_icp_mgr_hw_close(hw_mgr, NULL);
 get_io_buf_failed:
@@ -1638,6 +1779,7 @@
 	hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL;
 acquire_info_failed:
 	cam_icp_mgr_put_ctx(ctx_data);
+	mutex_unlock(&ctx_data->ctx_mutex);
 	return rc;
 }
 
@@ -1653,17 +1795,18 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	if (copy_from_user(&icp_hw_mgr.icp_caps,
 		(void __user *)query_cap->caps_handle,
 		sizeof(struct cam_icp_query_cap_cmd))) {
 		CAM_ERR(CAM_ICP, "copy_from_user failed");
-		return -EFAULT;
+		rc = -EFAULT;
+		goto end;
 	}
 
-	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	rc = hfi_get_hw_caps(&icp_hw_mgr.icp_caps);
 	if (rc)
-		goto hfi_get_caps_fail;
+		goto end;
 
 	icp_hw_mgr.icp_caps.dev_iommu_handle.non_secure = hw_mgr->iommu_hdl;
 	icp_hw_mgr.icp_caps.dev_iommu_handle.secure = hw_mgr->iommu_sec_hdl;
@@ -1672,70 +1815,30 @@
 		&icp_hw_mgr.icp_caps, sizeof(struct cam_icp_query_cap_cmd))) {
 		CAM_ERR(CAM_ICP, "copy_to_user failed");
 		rc = -EFAULT;
-		goto hfi_get_caps_fail;
 	}
-
-hfi_get_caps_fail:
+end:
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 	return rc;
 }
 
-int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl)
+static int cam_icp_mgr_alloc_devs(struct device_node *of_node)
 {
-	int count, i, rc = 0;
+	int rc;
 	uint32_t num_dev;
-	const char *name = NULL;
-	struct device_node *child_node = NULL;
-	struct platform_device *child_pdev = NULL;
-	struct cam_hw_intf *child_dev_intf = NULL;
-	struct cam_hw_mgr_intf *hw_mgr_intf;
 
-
-	hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl;
-	if (!of_node || !hw_mgr_intf) {
-		CAM_ERR(CAM_ICP, "Invalid args of_node %pK hw_mgr %pK",
-			of_node, hw_mgr_intf);
-		return -EINVAL;
-	}
-
-	hw_mgr_intf->hw_mgr_priv = &icp_hw_mgr;
-	hw_mgr_intf->hw_get_caps = cam_icp_mgr_get_hw_caps;
-	hw_mgr_intf->hw_acquire = cam_icp_mgr_acquire_hw;
-	hw_mgr_intf->hw_release = cam_icp_mgr_release_hw;
-	hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update;
-	hw_mgr_intf->hw_config = cam_icp_mgr_config_hw;
-	hw_mgr_intf->download_fw = cam_icp_mgr_download_fw;
-	hw_mgr_intf->hw_close = cam_icp_mgr_hw_close;
-
-	mutex_init(&icp_hw_mgr.hw_mgr_mutex);
-	spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
-
-	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
-		mutex_init(&icp_hw_mgr.ctx_data[i].ctx_mutex);
-
-	/* Get number of device objects */
-	count = of_property_count_strings(of_node, "compat-hw-name");
-	if (!count) {
-		CAM_ERR(CAM_ICP, "no compat hw found, count = %d", count);
-		rc = -EINVAL;
-		goto num_dev_failed;
-	}
-
-	/* Get number of a5 device nodes and a5 mem allocation */
 	rc = of_property_read_u32(of_node, "num-a5", &num_dev);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "getting num of a5 failed");
-		goto num_dev_failed;
+		goto num_a5_failed;
 	}
 
 	icp_hw_mgr.devices[CAM_ICP_DEV_A5] = kzalloc(
 		sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL);
 	if (!icp_hw_mgr.devices[CAM_ICP_DEV_A5]) {
 		rc = -ENOMEM;
-		goto num_dev_failed;
+		goto num_a5_failed;
 	}
 
-	/* Get number of ipe device nodes and ipe mem allocation */
 	rc = of_property_read_u32(of_node, "num-ipe", &num_dev);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "getting number of ipe dev nodes failed");
@@ -1749,7 +1852,6 @@
 		goto num_ipe_failed;
 	}
 
-	/* Get number of bps device nodes and bps mem allocation */
 	rc = of_property_read_u32(of_node, "num-bps", &num_dev);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "read num bps devices failed");
@@ -1762,6 +1864,36 @@
 		goto num_bps_failed;
 	}
 
+	return 0;
+num_bps_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]);
+num_ipe_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]);
+num_a5_failed:
+	return rc;
+}
+
+static int cam_icp_mgr_init_devs(struct device_node *of_node)
+{
+	int rc = 0;
+	int count, i;
+	const char *name = NULL;
+	struct device_node *child_node = NULL;
+	struct platform_device *child_pdev = NULL;
+	struct cam_hw_intf *child_dev_intf = NULL;
+
+	rc = cam_icp_mgr_alloc_devs(of_node);
+	if (rc)
+		return rc;
+
+	count = of_property_count_strings(of_node, "compat-hw-name");
+	if (!count) {
+		CAM_ERR(CAM_ICP, "no compat hw found in dev tree, cnt = %d",
+			count);
+		rc = -EINVAL;
+		goto compat_hw_name_failed;
+	}
+
 	for (i = 0; i < count; i++) {
 		rc = of_property_read_string_index(of_node, "compat-hw-name",
 			i, &name);
@@ -1797,20 +1929,24 @@
 		icp_hw_mgr.devices[child_dev_intf->hw_type]
 			[child_dev_intf->hw_idx] = child_dev_intf;
 
+		if (!child_dev_intf->hw_ops.process_cmd)
+			goto compat_hw_name_failed;
+
 		of_node_put(child_node);
 	}
 
-	rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl);
-	if (rc) {
-		CAM_ERR(CAM_ICP, "icp get iommu handle failed: %d", rc);
-		goto compat_hw_name_failed;
-	}
+	return 0;
+compat_hw_name_failed:
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]);
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]);
+	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]);
+	return rc;
+}
 
-	rc = cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH);
-	if (rc) {
-		CAM_ERR(CAM_ICP, "icp attach failed: %d", rc);
-		goto icp_attach_failed;
-	}
+static int cam_icp_mgr_create_wq(void)
+{
+	int rc;
+	int i;
 
 	rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK,
 		&icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ);
@@ -1850,10 +1986,7 @@
 		icp_hw_mgr.cmd_work->task.pool[i].payload =
 				&icp_hw_mgr.cmd_work_data[i];
 
-	init_completion(&icp_hw_mgr.a5_complete);
-
-	return rc;
-
+	return 0;
 msg_work_data_failed:
 	kfree(icp_hw_mgr.cmd_work_data);
 cmd_work_data_failed:
@@ -1861,17 +1994,70 @@
 msg_work_failed:
 	cam_req_mgr_workq_destroy(&icp_hw_mgr.cmd_work);
 cmd_work_failed:
+	return rc;
+}
+
+int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl)
+{
+	int i, rc = 0;
+	struct cam_hw_mgr_intf *hw_mgr_intf;
+
+	hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl;
+	if (!of_node || !hw_mgr_intf) {
+		CAM_ERR(CAM_ICP, "Invalid args of_node %pK hw_mgr %pK",
+			of_node, hw_mgr_intf);
+		return -EINVAL;
+	}
+
+	hw_mgr_intf->hw_mgr_priv = &icp_hw_mgr;
+	hw_mgr_intf->hw_get_caps = cam_icp_mgr_get_hw_caps;
+	hw_mgr_intf->hw_acquire = cam_icp_mgr_acquire_hw;
+	hw_mgr_intf->hw_release = cam_icp_mgr_release_hw;
+	hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update;
+	hw_mgr_intf->hw_config = cam_icp_mgr_config_hw;
+	hw_mgr_intf->download_fw = cam_icp_mgr_download_fw;
+	hw_mgr_intf->hw_close = cam_icp_mgr_hw_close;
+
+	mutex_init(&icp_hw_mgr.hw_mgr_mutex);
+	spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
+
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
+		mutex_init(&icp_hw_mgr.ctx_data[i].ctx_mutex);
+
+	rc = cam_icp_mgr_init_devs(of_node);
+	if (rc)
+		goto dev_init_failed;
+
+	rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl);
+	if (rc) {
+		CAM_ERR(CAM_ICP, "icp get iommu handle failed: %d", rc);
+		goto icp_get_hdl_failed;
+	}
+
+	rc = cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH);
+	if (rc) {
+		CAM_ERR(CAM_ICP, "icp attach failed: %d", rc);
+		goto icp_attach_failed;
+	}
+
+	rc = cam_icp_mgr_create_wq();
+	if (rc)
+		goto icp_wq_create_failed;
+
+	init_completion(&icp_hw_mgr.a5_complete);
+
+	return rc;
+
+icp_wq_create_failed:
 	cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_DETACH);
 icp_attach_failed:
 	cam_smmu_destroy_handle(icp_hw_mgr.iommu_hdl);
-	icp_hw_mgr.iommu_hdl = 0;
-compat_hw_name_failed:
+	icp_hw_mgr.iommu_hdl = -1;
+icp_get_hdl_failed:
 	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]);
-num_bps_failed:
 	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]);
-num_ipe_failed:
 	kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]);
-num_dev_failed:
+dev_init_failed:
 	mutex_destroy(&icp_hw_mgr.hw_mgr_mutex);
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
 		mutex_destroy(&icp_hw_mgr.ctx_data[i].ctx_mutex);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index 6fa32fa..27a86b2 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -42,6 +42,9 @@
 #define ICP_PACKET_OPCODE       2
 #define ICP_MAX_OUTPUT_SUPPORTED 6
 
+#define ICP_FRAME_PROCESS_SUCCESS 0
+#define ICP_FRAME_PROCESS_FAILURE 1
+
 /**
  * struct icp_hfi_mem_info
  * @qtbl: Memory info of queue table
@@ -158,6 +161,11 @@
  * @cmd_work_data: Pointer to command work queue task
  * @msg_work_data: Pointer to message work queue task
  * @ctxt_cnt: Active context count
+ * @ipe_ctxt_cnt: IPE Active context count
+ * @bps_ctxt_cnt: BPS Active context count
+ * @dentry: Debugfs entry
+ * @a5_debug: A5 debug flag
+ * @icp_pc_flag: Flag to enable/disable power collapse
  */
 struct cam_icp_hw_mgr {
 	struct mutex hw_mgr_mutex;
@@ -179,8 +187,11 @@
 	struct hfi_cmd_work_data *cmd_work_data;
 	struct hfi_msg_work_data *msg_work_data;
 	uint32_t ctxt_cnt;
+	uint32_t ipe_ctxt_cnt;
+	uint32_t bps_ctxt_cnt;
 	struct dentry *dentry;
 	bool a5_debug;
+	bool icp_pc_flag;
 };
 
 static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
index b7b3d7b..79c3388 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
@@ -131,6 +131,78 @@
 	return rc;
 }
 
+static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev)
+{
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_ipe_device_core_info *core_info = NULL;
+	struct cam_ipe_device_hw_info *hw_info = NULL;
+	int pwr_ctrl;
+	int pwr_status;
+
+	soc_info = &ipe_dev->soc_info;
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+	hw_info = core_info->ipe_hw_info;
+
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl,
+		true, &pwr_ctrl);
+	if (!(pwr_ctrl & IPE_COLLAPSE_MASK)) {
+		cam_cpas_reg_read(core_info->cpas_handle,
+			CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+			true, &pwr_status);
+		cam_cpas_reg_write(core_info->cpas_handle,
+			CAM_CPAS_REG_CPASTOP,
+			hw_info->pwr_ctrl, true, 0x1);
+
+		if (pwr_status >> IPE_PWR_ON_MASK)
+			return -EINVAL;
+
+	}
+	cam_ipe_get_gdsc_control(soc_info);
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl,
+		true, &pwr_ctrl);
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+		true, &pwr_status);
+	CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x",
+		pwr_ctrl, pwr_status);
+
+	return 0;
+}
+
+static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev)
+{
+	struct cam_hw_soc_info *soc_info = NULL;
+	struct cam_ipe_device_core_info *core_info = NULL;
+	struct cam_ipe_device_hw_info *hw_info = NULL;
+	int pwr_ctrl;
+	int pwr_status;
+	int rc = 0;
+
+	soc_info = &ipe_dev->soc_info;
+	core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info;
+	hw_info = core_info->ipe_hw_info;
+
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl,
+		true, &pwr_ctrl);
+	if (pwr_ctrl & IPE_COLLAPSE_MASK) {
+		CAM_ERR(CAM_ICP, "IPE: resume failed : %d", pwr_ctrl);
+		return -EINVAL;
+	}
+	rc = cam_ipe_transfer_gdsc_control(soc_info);
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl);
+	cam_cpas_reg_read(core_info->cpas_handle,
+		CAM_CPAS_REG_CPASTOP, hw_info->pwr_status,
+		true, &pwr_status);
+	CAM_DBG(CAM_ICP, "pwr_ctrl = %x pwr_status = %x",
+		pwr_ctrl, pwr_status);
+
+	return rc;
+}
+
 int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type,
 	void *cmd_args, uint32_t arg_size)
 {
@@ -185,6 +257,12 @@
 			core_info->cpas_start = false;
 		}
 		break;
+	case CAM_ICP_IPE_CMD_POWER_COLLAPSE:
+		rc = cam_ipe_handle_pc(ipe_dev);
+		break;
+	case CAM_ICP_IPE_CMD_POWER_RESUME:
+		rc = cam_ipe_handle_resume(ipe_dev);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.h
index 8f0e882..bd83972 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.h
@@ -19,7 +19,13 @@
 #include <linux/platform_device.h>
 #include <linux/dma-buf.h>
 
+#define IPE_COLLAPSE_MASK 0x1
+#define IPE_PWR_ON_MASK   0x2
+
 struct cam_ipe_device_hw_info {
+	uint32_t hw_idx;
+	uint32_t pwr_ctrl;
+	uint32_t pwr_status;
 	uint32_t reserved;
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c
index d95246f..d13363e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c
@@ -25,8 +25,19 @@
 #include "cam_cpas_api.h"
 #include "cam_debug_util.h"
 
-struct cam_ipe_device_hw_info cam_ipe_hw_info = {
-	.reserved = 0,
+static struct cam_ipe_device_hw_info cam_ipe_hw_info[] = {
+	{
+		.hw_idx = 0,
+		.pwr_ctrl = 0x4c,
+		.pwr_status = 0x48,
+		.reserved = 0,
+	},
+	{
+		.hw_idx = 1,
+		.pwr_ctrl = 0x54,
+		.pwr_status = 0x50,
+		.reserved = 0,
+	},
 };
 EXPORT_SYMBOL(cam_ipe_hw_info);
 
@@ -106,7 +117,7 @@
 		rc = -EINVAL;
 		return rc;
 	}
-	hw_info = (struct cam_ipe_device_hw_info *)match_dev->data;
+	hw_info = &cam_ipe_hw_info[ipe_dev_intf->hw_idx];
 	core_info->ipe_hw_info = hw_info;
 
 	rc = cam_ipe_init_soc_resources(&ipe_dev->soc_info, cam_ipe_irq,
@@ -142,7 +153,7 @@
 
 static const struct of_device_id cam_ipe_dt_match[] = {
 	{
-		.compatible = "qcom,cam_ipe",
+		.compatible = "qcom,cam-ipe",
 		.data = &cam_ipe_hw_info,
 	},
 	{}
@@ -152,7 +163,7 @@
 static struct platform_driver cam_ipe_driver = {
 	.probe = cam_ipe_probe,
 	.driver = {
-		.name = "cam_ipe",
+		.name = "cam-ipe",
 		.owner = THIS_MODULE,
 		.of_match_table = cam_ipe_dt_match,
 	},
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
index 26dd6d2..e7b2733f 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
@@ -20,6 +20,57 @@
 #include "cam_soc_util.h"
 #include "cam_debug_util.h"
 
+
+int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info)
+{
+	int i;
+	int rc;
+
+	for (i = 0; i < soc_info->num_rgltr; i++) {
+		rc = regulator_set_mode(soc_info->rgltr[i],
+			REGULATOR_MODE_FAST);
+		if (rc) {
+			CAM_ERR(CAM_ICP, "Regulator set mode %s failed",
+				soc_info->rgltr_name[i]);
+			goto rgltr_set_mode_failed;
+		}
+	}
+	return 0;
+
+rgltr_set_mode_failed:
+	for (i = i - 1; i >= 0; i--)
+		if (soc_info->rgltr[i])
+			regulator_set_mode(soc_info->rgltr[i],
+				REGULATOR_MODE_NORMAL);
+
+	return rc;
+}
+
+int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info)
+{
+	int i;
+	int rc;
+
+	for (i = 0; i < soc_info->num_rgltr; i++) {
+		rc = regulator_set_mode(soc_info->rgltr[i],
+					REGULATOR_MODE_NORMAL);
+		if (rc) {
+			CAM_ERR(CAM_ICP, "Regulator set mode %s failed",
+				soc_info->rgltr_name[i]);
+			goto rgltr_set_mode_failed;
+		}
+	}
+	return 0;
+
+rgltr_set_mode_failed:
+	for (i = i - 1; i >= 0; i--)
+		if (soc_info->rgltr[i])
+			regulator_set_mode(soc_info->rgltr[i],
+					REGULATOR_MODE_FAST);
+
+	return rc;
+}
+
 static int cam_ipe_get_dt_properties(struct cam_hw_soc_info *soc_info)
 {
 	int rc = 0;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
index 12ab444..ed8bb6e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
@@ -22,4 +22,7 @@
 
 int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info);
 
+int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info);
+
+int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info);
 #endif /* CAM_IPE_SOC_H */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index 4a5b1c3..4893960 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1961,6 +1961,16 @@
 			fill_fence = false;
 	}
 
+	/*
+	 * reg update will be done later for the initial configure.
+	 * need to plus one to the op_code and only take the lower
+	 * bits to get the type of operation since UMD definition
+	 * of op_code has some difference from KMD.
+	 */
+	if (((prepare->packet->header.op_code + 1) & 0xF) ==
+					CAM_ISP_PACKET_INIT_DEV)
+		return rc;
+
 	/* add reg update commands */
 	for (i = 0; i < ctx->num_base; i++) {
 		/* Add change base */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index 3fd42f7..efdda4f 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -833,6 +833,7 @@
 	for (i = 0; i < link->num_devs; i++) {
 		dev = &link->l_dev[i];
 		if (dev != NULL) {
+			link_data.dev_hdl = dev->dev_hdl;
 			if (dev->ops && dev->ops->link_setup)
 				dev->ops->link_setup(&link_data);
 			dev->dev_hdl = 0;
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index 644cb63..3fe7b00 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -790,21 +790,43 @@
 		for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) {
 			struct sync_table_row *row =
 			sync_dev->sync_table + i;
-			if (row->state == CAM_SYNC_STATE_INVALID)
-				continue;
 
-			/* Signal all remaining objects as ERR,but we don't care
-			 * about the return status here apart from logging it
+			/*
+			 * Signal all ACTIVE objects as ERR, but we don't
+			 * care about the return status here apart from logging
+			 * it.
 			 */
-			rc = cam_sync_signal(i, CAM_SYNC_STATE_SIGNALED_ERROR);
-			if (rc < 0)
-				CAM_ERR(CAM_SYNC,
-					"Cleanup signal failed: idx = %d", i);
+			if (row->state == CAM_SYNC_STATE_ACTIVE) {
+				rc = cam_sync_signal(i,
+					CAM_SYNC_STATE_SIGNALED_ERROR);
+				if (rc < 0)
+					CAM_ERR(CAM_SYNC,
+					  "Cleanup signal fail idx:%d\n",
+					  i);
+			}
+		}
 
-			rc = cam_sync_destroy(i);
-			if (rc < 0)
-				CAM_ERR(CAM_SYNC,
-					"Cleanup destroy failed: idx = %d", i);
+		/*
+		 * Flush the work queue to wait for pending signal callbacks to
+		 * finish
+		 */
+		flush_workqueue(sync_dev->work_queue);
+
+		/*
+		 * Now that all callbacks worker threads have finished,
+		 * destroy the sync objects
+		 */
+		for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) {
+			struct sync_table_row *row =
+			sync_dev->sync_table + i;
+
+			if (row->state != CAM_SYNC_STATE_INVALID) {
+				rc = cam_sync_destroy(i);
+				if (rc < 0)
+					CAM_ERR(CAM_SYNC,
+					  "Cleanup destroy fail:idx:%d\n",
+					  i);
+			}
 		}
 	}
 	mutex_unlock(&sync_dev->table_lock);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
index da7ecce..a075ed9 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_tspp_v1.c
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/vmalloc.h>
+#include <linux/dma-buf.h>
 #include <linux/qcom_tspp.h>
 #include "mpq_dvb_debug.h"
 #include "mpq_dmx_plugin_common.h"
@@ -189,6 +190,10 @@
 
 		/* Mutex protecting the data-structure */
 		struct mutex mutex;
+
+		/* ion dma buffer mapping structure */
+		struct tspp_ion_dma_buf_info ch_ion_dma_buf;
+
 	} tsif[TSIF_COUNT];
 
 	/* ION client used for TSPP data buffer allocation */
@@ -196,7 +201,8 @@
 } mpq_dmx_tspp_info;
 
 static void *tspp_mem_allocator(int channel_id, u32 size,
-				phys_addr_t *phys_base, void *user)
+				phys_addr_t *phys_base, dma_addr_t *dma_base,
+				void *user)
 {
 	void *virt_addr = NULL;
 	int i = TSPP_GET_TSIF_NUM(channel_id);
@@ -213,6 +219,10 @@
 		(mpq_dmx_tspp_info.tsif[i].ch_mem_heap_phys_base +
 		(mpq_dmx_tspp_info.tsif[i].buff_index * size));
 
+	*dma_base =
+		(mpq_dmx_tspp_info.tsif[i].ch_ion_dma_buf.dma_map_base +
+		(mpq_dmx_tspp_info.tsif[i].buff_index * size));
+
 	mpq_dmx_tspp_info.tsif[i].buff_index++;
 
 	return virt_addr;
@@ -539,6 +549,9 @@
 
 	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_virt_base = NULL;
 	mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle = NULL;
+
+	tspp_detach_ion_dma_buff(0,
+		&mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf);
 }
 
 /**
@@ -589,6 +602,24 @@
 		return -ENOMEM;
 	}
 
+	mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf.dbuf = ion_share_dma_buf(
+			mpq_dmx_tspp_info.ion_client,
+			mpq_dmx_tspp_info.tsif[tsif].ch_mem_heap_handle);
+	if (IS_ERR_OR_NULL(mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf.dbuf)) {
+		MPQ_DVB_ERR_PRINT("%s: ion_share_dma_buf failed\n", __func__);
+		mpq_dmx_channel_mem_free(tsif);
+		return -ENOMEM;
+	}
+
+	result = tspp_attach_ion_dma_buff(0,
+				&mpq_dmx_tspp_info.tsif[tsif].ch_ion_dma_buf);
+	if (result) {
+		MPQ_DVB_ERR_PRINT("%s: tspp_attach_ion_dma_buff failed\n",
+					 __func__);
+		mpq_dmx_channel_mem_free(tsif);
+		return result;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 9d10b06..b0fe8db 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -11,7 +11,7 @@
  *
  */
 
-#define pr_fmt(fmt)	"%s: " fmt, __func__
+#define pr_fmt(fmt)	"%s:%d: " fmt, __func__, __LINE__
 
 #include <linux/platform_device.h>
 #include <linux/module.h>
@@ -325,7 +325,7 @@
 	if (mgr->rsc_client)
 		ret = sde_rsc_client_state_update(mgr->rsc_client,
 				on ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE,
-				NULL, -1);
+				NULL, SDE_RSC_INVALID_CRTC_ID, NULL);
 	else
 		ret = sde_rot_enable_vreg(mgr->module_power.vreg_config,
 			mgr->module_power.num_vreg, on);
@@ -341,8 +341,6 @@
 	if (!on) {
 		mgr->minimum_bw_vote = 0;
 		sde_rotator_update_perf(mgr);
-	} else {
-		sde_mdp_init_vbif();
 	}
 
 	mgr->regulator_enable = on;
@@ -426,6 +424,9 @@
 			if (ret)
 				goto error_rot_sub;
 
+			/* reinitialize static vbif setting */
+			sde_mdp_init_vbif();
+
 			/* Active+Sleep */
 			msm_bus_scale_client_update_context(
 				mgr->data_bus.bus_hdl, false,
@@ -945,6 +946,11 @@
 				"timeout waiting for hw resource, a:%d p:%d\n",
 				atomic_read(&hw->num_active),
 				hw->pending_count);
+			SDEROT_EVTLOG(entry->item.session_id,
+					entry->item.sequence_id,
+					atomic_read(&hw->num_active),
+					hw->pending_count,
+					SDE_ROT_EVTLOG_ERROR);
 			return NULL;
 		}
 	}
@@ -1603,9 +1609,14 @@
 		entry->item.flags,
 		entry->dnsc_factor_w, entry->dnsc_factor_h);
 
-	wait_for_completion_timeout(
+	ret = wait_for_completion_timeout(
 			&entry->item.inline_start,
 			msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS));
+	if (!ret) {
+		SDEROT_WARN("timeout waiting for inline start\n");
+		SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
+				SDE_ROT_EVTLOG_ERROR);
+	}
 
 	if (entry->item.ts)
 		entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get();
@@ -1652,18 +1663,20 @@
 
 static bool sde_rotator_verify_format(struct sde_rot_mgr *mgr,
 	struct sde_mdp_format_params *in_fmt,
-	struct sde_mdp_format_params *out_fmt, bool rotation)
+	struct sde_mdp_format_params *out_fmt, bool rotation, u32 mode)
 {
 	u8 in_v_subsample, in_h_subsample;
 	u8 out_v_subsample, out_h_subsample;
 
-	if (!sde_rotator_is_valid_pixfmt(mgr, in_fmt->format, true)) {
-		SDEROT_ERR("Invalid input format %x\n", in_fmt->format);
+	if (!sde_rotator_is_valid_pixfmt(mgr, in_fmt->format, true, mode)) {
+		SDEROT_ERR("Invalid input format 0x%x (%4.4s)\n",
+				in_fmt->format, (char *)&in_fmt->format);
 		goto verify_error;
 	}
 
-	if (!sde_rotator_is_valid_pixfmt(mgr, out_fmt->format, false)) {
-		SDEROT_ERR("Invalid output format %x\n", out_fmt->format);
+	if (!sde_rotator_is_valid_pixfmt(mgr, out_fmt->format, false, mode)) {
+		SDEROT_ERR("Invalid output format 0x%x (%4.4s)\n",
+				out_fmt->format, (char *)&out_fmt->format);
 		goto verify_error;
 	}
 
@@ -1712,8 +1725,10 @@
 	return true;
 
 verify_error:
-	SDEROT_ERR("in_fmt=0x%x, out_fmt=0x%x\n",
-			in_fmt->format, out_fmt->format);
+	SDEROT_ERR("in_fmt=0x%x (%4.4s), out_fmt=0x%x (%4.4s), mode=%d\n",
+			in_fmt->format, (char *)&in_fmt->format,
+			out_fmt->format, (char *)&out_fmt->format,
+			mode);
 	return false;
 }
 
@@ -1832,6 +1847,7 @@
 {
 	struct sde_mdp_format_params *in_fmt, *out_fmt;
 	bool rotation;
+	u32 mode;
 
 	if (!mgr || !config) {
 		SDEROT_ERR("null parameters\n");
@@ -1840,6 +1856,9 @@
 
 	rotation = (config->flags & SDE_ROTATION_90) ? true : false;
 
+	mode = config->output.sbuf ? SDE_ROTATOR_MODE_SBUF :
+				SDE_ROTATOR_MODE_OFFLINE;
+
 	in_fmt = __verify_input_config(mgr, config);
 	if (!in_fmt)
 		return -EINVAL;
@@ -1848,7 +1867,7 @@
 	if (!out_fmt)
 		return -EINVAL;
 
-	if (!sde_rotator_verify_format(mgr, in_fmt, out_fmt, rotation)) {
+	if (!sde_rotator_verify_format(mgr, in_fmt, out_fmt, rotation, mode)) {
 		SDEROT_ERR(
 			"Rot format pairing invalid, in_fmt:0x%x, out_fmt:0x%x\n",
 					config->input.format,
@@ -2335,6 +2354,7 @@
 
 	if (config->output.sbuf && mgr->sbuf_ctx != private && mgr->sbuf_ctx) {
 		SDEROT_ERR("too many sbuf sessions\n");
+		ret = -EBUSY;
 		goto done;
 	}
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 731ff1e..3d368a1 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -141,6 +141,12 @@
 	SDE_ROTATOR_TRIGGER_COMMAND,
 };
 
+enum sde_rotator_mode {
+	SDE_ROTATOR_MODE_OFFLINE,
+	SDE_ROTATOR_MODE_SBUF,
+	SDE_ROTATOR_MODE_MAX,
+};
+
 struct sde_rotation_item {
 	/* rotation request flag */
 	uint32_t	flags;
@@ -463,9 +469,9 @@
 	int (*ops_hw_validate_entry)(struct sde_rot_mgr *mgr,
 			struct sde_rot_entry *entry);
 	u32 (*ops_hw_get_pixfmt)(struct sde_rot_mgr *mgr, int index,
-			bool input);
+			bool input, u32 mode);
 	int (*ops_hw_is_valid_pixfmt)(struct sde_rot_mgr *mgr, u32 pixfmt,
-			bool input);
+			bool input, u32 mode);
 	int (*ops_hw_get_downscale_caps)(struct sde_rot_mgr *mgr, char *caps,
 			int len);
 	int (*ops_hw_get_maxlinewidth)(struct sde_rot_mgr *mgr);
@@ -474,19 +480,19 @@
 };
 
 static inline int sde_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr,
-		u32 pixfmt, bool input)
+		u32 pixfmt, bool input, u32 mode)
 {
 	if (mgr && mgr->ops_hw_is_valid_pixfmt)
-		return mgr->ops_hw_is_valid_pixfmt(mgr, pixfmt, input);
+		return mgr->ops_hw_is_valid_pixfmt(mgr, pixfmt, input, mode);
 
 	return false;
 }
 
 static inline u32 sde_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
-		int index, bool input)
+		int index, bool input, u32 mode)
 {
 	if (mgr && mgr->ops_hw_get_pixfmt)
-		return mgr->ops_hw_get_pixfmt(mgr, index, input);
+		return mgr->ops_hw_get_pixfmt(mgr, index, input, mode);
 
 	return 0;
 }
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index da36e38..2a9573d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -21,6 +21,7 @@
 #include "sde_rotator_base.h"
 #include "sde_rotator_core.h"
 #include "sde_rotator_dev.h"
+#include "sde_rotator_trace.h"
 
 #ifdef CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG
 #define SDE_EVTLOG_DEFAULT_ENABLE 1
@@ -639,12 +640,13 @@
 /*
  * sde_rot_dump_panic - Issue evtlog dump and generic panic
  */
-void sde_rot_dump_panic(void)
+void sde_rot_dump_panic(bool do_panic)
 {
 	sde_rot_evtlog_dump_all();
 	sde_rot_dump_reg_all();
 
-	panic("sde_rotator");
+	if (do_panic)
+		panic("sde_rotator");
 }
 
 /*
@@ -740,6 +742,8 @@
 		(sde_rot_dbg_evtlog.curr + 1) % SDE_ROT_EVTLOG_ENTRY;
 	sde_rot_dbg_evtlog.last++;
 
+	trace_sde_rot_evtlog(name, line, log->data_cnt, log->data);
+
 	spin_unlock_irqrestore(&sde_rot_xlock, flags);
 }
 
@@ -1434,6 +1438,13 @@
 		return NULL;
 	}
 
+	if (!debugfs_create_u32("open_timeout", 0644,
+			debugfs_root, &rot_dev->open_timeout)) {
+		SDEROT_ERR("fail create open_timeout\n");
+		debugfs_remove_recursive(debugfs_root);
+		return NULL;
+	}
+
 	if (!debugfs_create_u32("disable_syscache", 0644,
 			debugfs_root, &rot_dev->disable_syscache)) {
 		SDEROT_ERR("fail create disable_syscache\n");
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
index c6d0151..2fc8e3f 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
@@ -18,6 +18,9 @@
 
 #define SDE_ROT_DATA_LIMITER (-1)
 #define SDE_ROT_EVTLOG_TOUT_DATA_LIMITER (NULL)
+#define SDE_ROT_EVTLOG_PANIC		0xdead
+#define SDE_ROT_EVTLOG_FATAL		0xbad
+#define SDE_ROT_EVTLOG_ERROR		0xebad
 
 enum sde_rot_dbg_reg_dump_flag {
 	SDE_ROT_DBG_DUMP_IN_LOG = BIT(0),
@@ -39,7 +42,7 @@
 		SDE_ROT_EVTLOG_TOUT_DATA_LIMITER)
 
 void sde_rot_evtlog(const char *name, int line, int flag, ...);
-void sde_rot_dump_panic(void);
+void sde_rot_dump_panic(bool do_panic);
 void sde_rot_evtlog_tout_handler(bool queue, const char *name, ...);
 
 struct sde_rotator_device;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index 8727535..acd4b7d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -9,7 +9,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-#define pr_fmt(fmt)	"%s: " fmt, __func__
+#define pr_fmt(fmt)	"%s:%d: " fmt, __func__, __LINE__
 
 #include <linux/vmalloc.h>
 #include <linux/kernel.h>
@@ -46,6 +46,9 @@
 /* acquire fence time out, following other driver fence time out practice */
 #define SDE_ROTATOR_FENCE_TIMEOUT	MSEC_PER_SEC
 
+/* Timeout (msec) waiting for ctx open */
+#define SDE_ROTATOR_CTX_OPEN_TIMEOUT	500
+
 /* Rotator default fps */
 #define SDE_ROTATOR_DEFAULT_FPS	60
 
@@ -457,6 +460,9 @@
 				"timeout to stream off s:%d t:%d p:%d\n",
 				ctx->session_id, q->type,
 				!list_empty(&ctx->pending_list));
+		SDEROT_EVTLOG(ctx->session_id, q->type,
+				!list_empty(&ctx->pending_list),
+				SDE_ROT_EVTLOG_ERROR);
 		sde_rot_mgr_lock(rot_dev->mgr);
 		sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private);
 		sde_rot_mgr_unlock(rot_dev->mgr);
@@ -893,6 +899,29 @@
 		goto error_lock;
 	}
 
+	/* wait until exclusive ctx, if exists, finishes or timeout */
+	while (rot_dev->excl_ctx) {
+		SDEROT_DBG("waiting to open %s session %d ...\n",
+				file ? "v4l2" : "excl",	rot_dev->session_id);
+		mutex_unlock(&rot_dev->lock);
+		ret = wait_event_interruptible_timeout(rot_dev->open_wq,
+				!rot_dev->excl_ctx,
+				msecs_to_jiffies(rot_dev->open_timeout));
+		if (ret < 0) {
+			goto error_lock;
+		} else if (!ret) {
+			SDEROT_WARN("timeout to open session %d\n",
+					rot_dev->session_id);
+			SDEROT_EVTLOG(rot_dev->session_id,
+					SDE_ROT_EVTLOG_ERROR);
+			ret = -EBUSY;
+			goto error_lock;
+		} else if (mutex_lock_interruptible(&rot_dev->lock)) {
+			ret = -ERESTARTSYS;
+			goto error_lock;
+		}
+	}
+
 	ctx->rot_dev = rot_dev;
 	ctx->file = file;
 
@@ -991,8 +1020,8 @@
 	}
 	sde_rot_mgr_unlock(rot_dev->mgr);
 
-	/* Create control */
 	if (ctx->file) {
+		/* Create control */
 		ctrl_handler = &ctx->ctrl_handler;
 		v4l2_ctrl_handler_init(ctrl_handler, 4);
 		v4l2_ctrl_new_std(ctrl_handler,
@@ -1012,7 +1041,14 @@
 		}
 		ctx->fh.ctrl_handler = ctrl_handler;
 		v4l2_ctrl_handler_setup(ctrl_handler);
+	} else {
+		/* acquire exclusive context */
+		SDEDEV_DBG(rot_dev->dev, "acquire exclusive session id:%u\n",
+				ctx->session_id);
+		SDEROT_EVTLOG(ctx->session_id);
+		rot_dev->excl_ctx = ctx;
 	}
+
 	mutex_unlock(&rot_dev->lock);
 
 	SDEDEV_DBG(ctx->rot_dev->dev, "SDE v4l2 rotator open success\n");
@@ -1059,6 +1095,12 @@
 
 	SDEDEV_DBG(rot_dev->dev, "release s:%d\n", session_id);
 	mutex_lock(&rot_dev->lock);
+	if (rot_dev->excl_ctx == ctx) {
+		SDEDEV_DBG(rot_dev->dev, "release exclusive session id:%u\n",
+				session_id);
+		SDEROT_EVTLOG(session_id);
+		rot_dev->excl_ctx = NULL;
+	}
 	if (ctx->file) {
 		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
 		SDEDEV_DBG(rot_dev->dev, "release streams s:%d\n", session_id);
@@ -1105,6 +1147,7 @@
 	kfree(ctx->vbinfo_out);
 	kfree(ctx->vbinfo_cap);
 	kfree(ctx);
+	wake_up_interruptible(&rot_dev->open_wq);
 	mutex_unlock(&rot_dev->lock);
 	SDEDEV_DBG(rot_dev->dev, "release complete s:%d\n", session_id);
 	return 0;
@@ -1390,7 +1433,8 @@
 
 	sde_rot_mgr_lock(rot_dev->mgr);
 	for (i = 0;; i++) {
-		pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input);
+		pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input,
+				SDE_ROTATOR_MODE_SBUF);
 		if (!pixfmt)
 			break;
 		if (pixfmts && i < len)
@@ -1451,15 +1495,14 @@
 	SDEROT_EVTLOG(ctx->session_id, cmd->sequence_id,
 		cmd->src_rect_x, cmd->src_rect_y,
 		cmd->src_rect_w, cmd->src_rect_h,
-		cmd->src_width, cmd->src_height,
 		cmd->src_pixfmt,
-		cmd->dst_rect_x, cmd->dst_rect_y,
 		cmd->dst_rect_w, cmd->dst_rect_h,
 		cmd->dst_pixfmt,
-		cmd->rot90, cmd->hflip, cmd->vflip, cmd->secure, cmd->fps,
-		cmd->clkrate, cmd->data_bw,
-		cmd->dst_writeback, cmd->video_mode, cmd_type);
-
+		(cmd->rot90 << 0) | (cmd->hflip << 1) | (cmd->vflip << 2) |
+		(cmd->secure << 3) | (cmd->dst_writeback << 4) |
+		(cmd->video_mode << 5),
+		cmd->fps, cmd->clkrate, cmd->data_bw,
+		cmd_type);
 
 	sde_rot_mgr_lock(rot_dev->mgr);
 
@@ -1568,7 +1611,7 @@
 			ret = sde_rotator_session_config(rot_dev->mgr,
 					ctx->private, &rotcfg);
 			if (ret) {
-				SDEROT_ERR("fail session config s:%d\n",
+				SDEROT_WARN("fail session config s:%d\n",
 						ctx->session_id);
 				goto error_session_config;
 			}
@@ -1579,7 +1622,7 @@
 		ret = sde_rotator_validate_request(rot_dev->mgr, ctx->private,
 				req);
 		if (ret) {
-			SDEROT_ERR("fail validate request s:%d\n",
+			SDEROT_WARN("fail validate request s:%d\n",
 					ctx->session_id);
 			goto error_validate_request;
 		}
@@ -1677,13 +1720,17 @@
 			ret = wait_event_timeout(ctx->wait_queue,
 				sde_rotator_is_request_retired(request),
 				msecs_to_jiffies(rot_dev->streamoff_timeout));
-			if (!ret)
+			if (!ret) {
 				SDEROT_ERR("timeout w/o retire s:%d\n",
 						ctx->session_id);
-			else if (ret == 1)
+				SDEROT_EVTLOG(ctx->session_id,
+						SDE_ROT_EVTLOG_ERROR);
+			} else if (ret == 1) {
 				SDEROT_ERR("timeout w/ retire s:%d\n",
 						ctx->session_id);
-
+				SDEROT_EVTLOG(ctx->session_id,
+						SDE_ROT_EVTLOG_ERROR);
+			}
 			sde_rot_mgr_lock(rot_dev->mgr);
 		}
 
@@ -1708,6 +1755,12 @@
 }
 EXPORT_SYMBOL(sde_rotator_inline_commit);
 
+void sde_rotator_inline_reg_dump(struct platform_device *pdev)
+{
+	sde_rot_dump_panic(false);
+}
+EXPORT_SYMBOL(sde_rotator_inline_reg_dump);
+
 /*
  * sde_rotator_open - Rotator device open method.
  * @file: Pointer to file struct.
@@ -1805,7 +1858,8 @@
 	bool found = false;
 
 	for (i = 0, index = 0; index <= f->index; i++) {
-		pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false);
+		pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false,
+				SDE_ROTATOR_MODE_OFFLINE);
 		if (!pixfmt)
 			return -EINVAL;
 
@@ -1849,7 +1903,8 @@
 	bool found = false;
 
 	for (i = 0, index = 0; index <= f->index; i++) {
-		pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true);
+		pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true,
+				SDE_ROTATOR_MODE_OFFLINE);
 		if (!pixfmt)
 			return -EINVAL;
 
@@ -2899,6 +2954,9 @@
 				"error waiting for fence s:%d.%d fd:%d r:%d\n",
 				ctx->session_id,
 				vbinfo_cap->fence_ts, vbinfo_out->fd, ret);
+			SDEROT_EVTLOG(ctx->session_id, vbinfo_cap->fence_ts,
+					vbinfo_out->fd, ret,
+					SDE_ROT_EVTLOG_ERROR);
 			goto error_fence_wait;
 		} else {
 			SDEDEV_DBG(rot_dev->dev, "fence exit s:%d.%d fd:%d\n",
@@ -3299,6 +3357,8 @@
 	rot_dev->min_bw = 0;
 	rot_dev->min_overhead_us = 0;
 	rot_dev->drvdata = sde_rotator_get_drv_data(&pdev->dev);
+	rot_dev->open_timeout = SDE_ROTATOR_CTX_OPEN_TIMEOUT;
+	init_waitqueue_head(&rot_dev->open_wq);
 
 	rot_dev->pdev = pdev;
 	rot_dev->dev = &pdev->dev;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
index 627ea86..5ea9e15 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h
@@ -205,6 +205,9 @@
  * @min_overhead_us: Override the minimum overhead in us from perf calculation
  * @debugfs_root: Pointer to debugfs directory entry.
  * @stats: placeholder for rotator statistics
+ * @open_timeout: maximum wait time for ctx open in msec
+ * @open_wq: wait queue for ctx open
+ * @excl_ctx: Pointer to exclusive ctx
  */
 struct sde_rotator_device {
 	struct mutex lock;
@@ -227,6 +230,9 @@
 	struct sde_rotator_statistics stats;
 	struct dentry *debugfs_root;
 	struct dentry *perf_root;
+	u32 open_timeout;
+	wait_queue_head_t open_wq;
+	struct sde_rotator_ctx *excl_ctx;
 };
 
 static inline
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
index 27e9ba6..7585a6b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
@@ -850,6 +850,11 @@
 	case SDE_PIX_FMT_Y_CRCB_H2V2_TILE:
 		*dst_pixfmt = SDE_PIX_FMT_Y_CRCB_H2V2_TILE;
 		break;
+	case V4L2_PIX_FMT_RGB565:
+	case SDE_PIX_FMT_RGB_565_UBWC:
+	case SDE_PIX_FMT_RGB_565_TILE:
+		*dst_pixfmt = SDE_PIX_FMT_RGB_565_TILE;
+		break;
 	case SDE_PIX_FMT_RGBA_8888:
 	case SDE_PIX_FMT_RGBA_8888_UBWC:
 	case SDE_PIX_FMT_RGBA_8888_TILE:
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
index 5bb6198..545dcfc 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.h
@@ -37,6 +37,7 @@
 #define SDE_PIX_FMT_RGBA_1010102_TILE	v4l2_fourcc('Q', 'T', '1', '0')
 #define SDE_PIX_FMT_RGBX_1010102_TILE	v4l2_fourcc('Q', 'T', '1', '1')
 #define SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE	v4l2_fourcc('Q', 'T', '1', '2')
+#define SDE_PIX_FMT_RGB_565_TILE	v4l2_fourcc('Q', 'T', '1', '3')
 
 #define SDE_ROT_MAX_PLANES		4
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_inline.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_inline.h
index 705eb27..474662e 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_inline.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_inline.h
@@ -112,5 +112,6 @@
 int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd,
 		enum sde_rotator_inline_cmd_type cmd_type);
 int sde_rotator_inline_release(void *handle);
+void sde_rotator_inline_reg_dump(struct platform_device *pdev);
 
 #endif /* __SDE_ROTATOR_INLINE_H__ */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
index 9f4a854..1b4913b 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
@@ -501,9 +501,10 @@
  * @mgr: Pointer to rotator manager
  * @index: index of pixel format
  * @input: true for input port; false for output port
+ * @mode: operating mode
  */
 static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
-		int index, bool input)
+		int index, bool input, u32 mode)
 {
 	if (input) {
 		if (index < ARRAY_SIZE(sde_hw_rotator_input_pixfmts))
@@ -523,9 +524,10 @@
  * @mgr: Pointer to rotator manager
  * @pixfmt: pixel format to be verified
  * @input: true for input port; false for output port
+ * @mode: operating mode
  */
 static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
-		bool input)
+		bool input, u32 mode)
 {
 	int i;
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 205eeef..3c47dd7 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -11,7 +11,7 @@
  *
  */
 
-#define pr_fmt(fmt)	"%s: " fmt, __func__
+#define pr_fmt(fmt)	"%s:%d: " fmt, __func__, __LINE__
 
 #include <linux/platform_device.h>
 #include <linux/module.h>
@@ -107,7 +107,7 @@
 #define SDE_ROTREG_READ(base, off) \
 	readl_relaxed(base + (off))
 
-static u32 sde_hw_rotator_v3_inpixfmts[] = {
+static const u32 sde_hw_rotator_v3_inpixfmts[] = {
 	SDE_PIX_FMT_XRGB_8888,
 	SDE_PIX_FMT_ARGB_8888,
 	SDE_PIX_FMT_ABGR_8888,
@@ -167,7 +167,7 @@
 	SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
 };
 
-static u32 sde_hw_rotator_v3_outpixfmts[] = {
+static const u32 sde_hw_rotator_v3_outpixfmts[] = {
 	SDE_PIX_FMT_XRGB_8888,
 	SDE_PIX_FMT_ARGB_8888,
 	SDE_PIX_FMT_ABGR_8888,
@@ -227,7 +227,7 @@
 	SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
 };
 
-static u32 sde_hw_rotator_v4_inpixfmts[] = {
+static const u32 sde_hw_rotator_v4_inpixfmts[] = {
 	SDE_PIX_FMT_XRGB_8888,
 	SDE_PIX_FMT_ARGB_8888,
 	SDE_PIX_FMT_ABGR_8888,
@@ -307,7 +307,7 @@
 	SDE_PIX_FMT_XBGR_2101010_TILE,
 };
 
-static u32 sde_hw_rotator_v4_outpixfmts[] = {
+static const u32 sde_hw_rotator_v4_outpixfmts[] = {
 	SDE_PIX_FMT_XRGB_8888,
 	SDE_PIX_FMT_ARGB_8888,
 	SDE_PIX_FMT_ABGR_8888,
@@ -387,6 +387,23 @@
 	SDE_PIX_FMT_XBGR_2101010_TILE,
 };
 
+static const u32 sde_hw_rotator_v4_inpixfmts_sbuf[] = {
+	SDE_PIX_FMT_Y_CBCR_H2V2_P010,
+	SDE_PIX_FMT_Y_CBCR_H2V2,
+	SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
+	SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC,
+	SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
+	SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
+	SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE,
+	SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
+};
+
+static const u32 sde_hw_rotator_v4_outpixfmts_sbuf[] = {
+	SDE_PIX_FMT_Y_CBCR_H2V2_TP10,
+	SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE,
+	SDE_PIX_FMT_Y_CBCR_H2V2_TILE,
+};
+
 static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = {
 	{0x214, 0x21c, 16, 1, 0x200}, /* arb clients main */
 	{0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */
@@ -2637,17 +2654,33 @@
 		set_bit(SDE_CAPS_SBUF_1,  mdata->sde_caps_map);
 		set_bit(SDE_CAPS_UBWC_2,  mdata->sde_caps_map);
 		set_bit(SDE_CAPS_PARTIALWR,  mdata->sde_caps_map);
-		rot->inpixfmts = sde_hw_rotator_v4_inpixfmts;
-		rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts);
-		rot->outpixfmts = sde_hw_rotator_v4_outpixfmts;
-		rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts);
+		rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+				sde_hw_rotator_v4_inpixfmts;
+		rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+				ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts);
+		rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+				sde_hw_rotator_v4_outpixfmts;
+		rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+				ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts);
+		rot->inpixfmts[SDE_ROTATOR_MODE_SBUF] =
+				sde_hw_rotator_v4_inpixfmts_sbuf;
+		rot->num_inpixfmt[SDE_ROTATOR_MODE_SBUF] =
+				ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts_sbuf);
+		rot->outpixfmts[SDE_ROTATOR_MODE_SBUF] =
+				sde_hw_rotator_v4_outpixfmts_sbuf;
+		rot->num_outpixfmt[SDE_ROTATOR_MODE_SBUF] =
+				ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts_sbuf);
 		rot->downscale_caps =
 			"LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
 	} else {
-		rot->inpixfmts = sde_hw_rotator_v3_inpixfmts;
-		rot->num_inpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts);
-		rot->outpixfmts = sde_hw_rotator_v3_outpixfmts;
-		rot->num_outpixfmt = ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts);
+		rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+				sde_hw_rotator_v3_inpixfmts;
+		rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+				ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts);
+		rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] =
+				sde_hw_rotator_v3_outpixfmts;
+		rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] =
+				ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts);
 		rot->downscale_caps = (hw_version == SDE_ROT_TYPE_V1_0) ?
 			"LINEAR/2/4/8/16/32/64 TILE/2/4 TP10/2" :
 			"LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2";
@@ -3055,9 +3088,10 @@
  * @mgr: Pointer to rotator manager
  * @index: index of pixel format
  * @input: true for input port; false for output port
+ * @mode: operating mode
  */
 static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr,
-		int index, bool input)
+		int index, bool input, u32 mode)
 {
 	struct sde_hw_rotator *rot;
 
@@ -3068,14 +3102,19 @@
 
 	rot = mgr->hw_data;
 
+	if (mode >= SDE_ROTATOR_MODE_MAX) {
+		SDEROT_ERR("invalid rotator mode %d\n", mode);
+		return 0;
+	}
+
 	if (input) {
-		if ((index < rot->num_inpixfmt) && rot->inpixfmts)
-			return rot->inpixfmts[index];
+		if ((index < rot->num_inpixfmt[mode]) && rot->inpixfmts[mode])
+			return rot->inpixfmts[mode][index];
 		else
 			return 0;
 	} else {
-		if ((index < rot->num_outpixfmt) && rot->outpixfmts)
-			return rot->outpixfmts[index];
+		if ((index < rot->num_outpixfmt[mode]) && rot->outpixfmts[mode])
+			return rot->outpixfmts[mode][index];
 		else
 			return 0;
 	}
@@ -3086,12 +3125,13 @@
  * @mgr: Pointer to rotator manager
  * @pixfmt: pixel format to be verified
  * @input: true for input port; false for output port
+ * @mode: operating mode
  */
 static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt,
-		bool input)
+		bool input, u32 mode)
 {
 	struct sde_hw_rotator *rot;
-	u32 *pixfmts;
+	const u32 *pixfmts;
 	u32 num_pixfmt;
 	int i;
 
@@ -3102,12 +3142,17 @@
 
 	rot = mgr->hw_data;
 
+	if (mode >= SDE_ROTATOR_MODE_MAX) {
+		SDEROT_ERR("invalid rotator mode %d\n", mode);
+		return false;
+	}
+
 	if (input) {
-		pixfmts = rot->inpixfmts;
-		num_pixfmt = rot->num_inpixfmt;
+		pixfmts = rot->inpixfmts[mode];
+		num_pixfmt = rot->num_inpixfmt[mode];
 	} else {
-		pixfmts = rot->outpixfmts;
-		num_pixfmt = rot->num_outpixfmt;
+		pixfmts = rot->outpixfmts[mode];
+		num_pixfmt = rot->num_outpixfmt[mode];
 	}
 
 	if (!pixfmts || !num_pixfmt) {
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
index 67f7f4b..4c1316c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
@@ -259,10 +259,10 @@
  * @sbuf_ctx: list of active sbuf context in FIFO order
  * @vid_trigger: video mode trigger select
  * @cmd_trigger: command mode trigger select
- * @inpixfmts: array of supported input pixel formats forucc
- * @num_inpixfmt: size of the supported input pixel format array
- * @outpixfmts: array of supported output pixel formats in fourcc
- * @num_outpixfmt: size of the supported output pixel formats array
+ * @inpixfmts: array of supported input pixel formats fourcc per mode
+ * @num_inpixfmt: size of the supported input pixel format array per mode
+ * @outpixfmts: array of supported output pixel formats in fourcc per mode
+ * @num_outpixfmt: size of the supported output pixel formats array per mode
  * @downscale_caps: capability string of scaling
  * @maxlinewidth: maximum line width supported
  */
@@ -320,10 +320,10 @@
 
 	struct list_head sbuf_ctx[ROT_QUEUE_MAX];
 
-	u32 *inpixfmts;
-	u32 num_inpixfmt;
-	u32 *outpixfmts;
-	u32 num_outpixfmt;
+	const u32 *inpixfmts[SDE_ROTATOR_MODE_MAX];
+	u32 num_inpixfmt[SDE_ROTATOR_MODE_MAX];
+	const u32 *outpixfmts[SDE_ROTATOR_MODE_MAX];
+	u32 num_outpixfmt[SDE_ROTATOR_MODE_MAX];
 	const char *downscale_caps;
 	u32 maxlinewidth;
 };
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_trace.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_trace.h
index 691e2ec..5ba37b3 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_trace.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, 2015-2017, 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
@@ -295,6 +295,40 @@
 
 );
 
+#define SDE_ROT_TRACE_EVTLOG_SIZE	15
+TRACE_EVENT(sde_rot_evtlog,
+	TP_PROTO(const char *tag, u32 tag_id, u32 cnt, u32 data[]),
+	TP_ARGS(tag, tag_id, cnt, data),
+	TP_STRUCT__entry(
+			__field(int, pid)
+			__string(evtlog_tag, tag)
+			__field(u32, tag_id)
+			__array(u32, data, SDE_ROT_TRACE_EVTLOG_SIZE)
+	),
+	TP_fast_assign(
+			__entry->pid = current->tgid;
+			__assign_str(evtlog_tag, tag);
+			__entry->tag_id = tag_id;
+			if (cnt > SDE_ROT_TRACE_EVTLOG_SIZE)
+				cnt = SDE_ROT_TRACE_EVTLOG_SIZE;
+			memcpy(__entry->data, data, cnt * sizeof(u32));
+			memset(&__entry->data[cnt], 0,
+				(SDE_ROT_TRACE_EVTLOG_SIZE - cnt) *
+				sizeof(u32));
+	),
+	TP_printk("%d|%s:%d|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x",
+			__entry->pid, __get_str(evtlog_tag),
+			__entry->tag_id,
+			__entry->data[0], __entry->data[1],
+			__entry->data[2], __entry->data[3],
+			__entry->data[4], __entry->data[5],
+			__entry->data[6], __entry->data[7],
+			__entry->data[8], __entry->data[9],
+			__entry->data[10], __entry->data[11],
+			__entry->data[12], __entry->data[13],
+			__entry->data[14])
+)
+
 #endif /* if !defined(TRACE_SDE_ROTATOR_H) ||
 	*		defined(TRACE_HEADER_MULTI_READ)
 	*/
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
index a93f054..45e8771 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c
@@ -901,6 +901,7 @@
 
 exit:
 	*freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX);
+	trace_msm_vidc_perf_bus_vote(gov->devfreq_gov.name, *freq);
 	return 0;
 }
 
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index e49ea72..4512409 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -164,6 +164,9 @@
 	case HFI_VIDEO_CODEC_VP9:
 		hal_codec = HAL_VIDEO_CODEC_VP9;
 		break;
+	case HFI_VIDEO_CODEC_TME:
+		hal_codec = HAL_VIDEO_CODEC_TME;
+		break;
 	default:
 		dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
 			__func__, hfi_codec);
@@ -220,6 +223,9 @@
 	case HAL_VIDEO_CODEC_VP9:
 		hfi_codec = HFI_VIDEO_CODEC_VP9;
 		break;
+	case HAL_VIDEO_CODEC_TME:
+		hfi_codec = HFI_VIDEO_CODEC_TME;
+		break;
 	default:
 		dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
 			__func__, hal_codec);
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index efe4ca3..52b9b32 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -997,6 +997,15 @@
 			num_properties--;
 			break;
 		}
+		case HFI_PROPERTY_TME_VERSION_SUPPORTED:
+		{
+			capabilities->tme_version =
+				*((u32 *)(data_ptr + next_offset));
+			next_offset +=
+				sizeof(u32);
+			num_properties--;
+			break;
+		}
 		default:
 			dprintk(VIDC_DBG,
 				"%s: default case - data_ptr %pK, prop_id 0x%x\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 988f79c..f17f3da 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -373,6 +373,15 @@
 		.default_value = 0,
 		.step = OPERATING_FRAME_RATE_STEP,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE,
+		.name = "Low Latency Mode",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+		.maximum = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE,
+		.default_value = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_DISABLE,
+		.step = 1,
+	},
 };
 
 #define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
@@ -1062,6 +1071,14 @@
 				ctrl->val >> 16);
 		inst->clk_data.operating_rate = ctrl->val;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
+		if (ctrl->val ==
+			V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE)
+			hal_property.enable = 1;
+		else
+			hal_property.enable = 0;
+		inst->clk_data.low_latency_mode = (bool) hal_property.enable;
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 69070d5..03b4e4d 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -117,6 +117,17 @@
 	"Level unknown",
 };
 
+static const char *const tme_profile[] = {
+	"0",
+	"1",
+	"2",
+	"3",
+};
+
+static const char *const tme_level[] = {
+	"Integer",
+};
+
 static const char *const hevc_profile[] = {
 	"Main",
 	"Main10",
@@ -486,6 +497,46 @@
 		.qmenu = hevc_tier_level,
 	},
 	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE,
+		.name = "TME Profile",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3,
+		.default_value =
+			V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0,
+		.menu_skip_mask = ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2) |
+		(1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3)
+		),
+		.qmenu = tme_profile,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL,
+		.name = "TME Level",
+		.type = V4L2_CTRL_TYPE_MENU,
+		.minimum = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+		.maximum = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+		.default_value = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER,
+		.menu_skip_mask =  ~(
+		(1 << V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER)
+		),
+		.qmenu = tme_level,
+	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION,
+		.name = "TME Payload Version",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 0,
+		.maximum = 0xFFFFFFF,
+		.default_value = 0,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.flags = V4L2_CTRL_FLAG_READ_ONLY,
+		.qmenu = NULL,
+	},
+	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
 		.name = "Rotation",
 		.type = V4L2_CTRL_TYPE_MENU,
@@ -1064,6 +1115,13 @@
 		.get_frame_size = get_frame_size_tp10_ubwc,
 		.type = OUTPUT_PORT,
 	},
+	{
+		.name = "TME",
+		.description = "TME MBI format",
+		.fourcc = V4L2_PIX_FMT_TME,
+		.get_frame_size = get_frame_size_compressed,
+		.type = CAPTURE_PORT,
+	},
 };
 
 static int msm_venc_set_csc(struct msm_vidc_inst *inst);
@@ -1345,6 +1403,29 @@
 				temp_ctrl->val);
 		pdata = &profile_level;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE:
+		temp_ctrl =
+			TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.level = msm_comm_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE);
+
+		property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
+		profile_level.level = msm_comm_v4l2_to_hal(ctrl->id,
+							ctrl->val);
+		profile_level.profile = msm_comm_v4l2_to_hal(
+				V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE,
+				temp_ctrl->val);
+		pdata = &profile_level;
+		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
 	{
 		property_id = HAL_PARAM_VPE_ROTATION;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 971e57a..d08d40f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1453,6 +1453,9 @@
 		}
 		ctrl->val = bufreq->buffer_count_min_host;
 		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION:
+		ctrl->val = inst->capability.tme_version;
+		break;
 	default:
 		/*
 		 * Other controls aren't really volatile, shouldn't need to
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 51023f0..d557959 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -510,7 +510,7 @@
 	u32 vpp_cycles_per_mb;
 	u32 mbs_per_second;
 
-	mbs_per_second = msm_comm_get_inst_load(inst,
+	mbs_per_second = msm_comm_get_inst_load_per_core(inst,
 		LOAD_CALC_NO_QUIRKS);
 
 	/*
@@ -524,6 +524,8 @@
 			inst->clk_data.entry->low_power_cycles :
 			inst->clk_data.entry->vpp_cycles;
 
+		vpp_cycles = mbs_per_second * vpp_cycles_per_mb;
+
 		vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
 
 		/* 10 / 7 is overhead factor */
@@ -533,7 +535,7 @@
 
 		vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
 		/* 10 / 7 is overhead factor */
-		vsp_cycles += ((inst->prop.fps * filled_len * 8) / 7) * 10;
+		vsp_cycles += ((inst->prop.fps * filled_len * 8) * 10) / 7;
 
 	} else {
 		dprintk(VIDC_ERR, "Unknown session type = %s\n", __func__);
@@ -619,7 +621,7 @@
 				temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)
 			continue;
 
-		mbs_per_second = msm_comm_get_inst_load(temp,
+		mbs_per_second = msm_comm_get_inst_load_per_core(temp,
 		LOAD_CALC_NO_QUIRKS);
 
 		cycles = temp->clk_data.entry->vpp_cycles;
@@ -820,7 +822,7 @@
 
 	core = inst->core;
 	dcvs = &inst->clk_data;
-	load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
+	load = msm_comm_get_inst_load_per_core(inst, LOAD_CALC_NO_QUIRKS);
 	cycles = inst->clk_data.entry->vpp_cycles;
 	allowed_clks_tbl = core->resources.allowed_clks_tbl;
 	if (inst->session_type == MSM_VIDC_ENCODER) {
@@ -1044,10 +1046,7 @@
 		} else {
 			continue;
 		}
-		if (inst->clk_data.core_id == 3)
-			cycles = cycles / 2;
-
-		current_inst_mbs_per_sec = msm_comm_get_inst_load(inst,
+		current_inst_mbs_per_sec = msm_comm_get_inst_load_per_core(inst,
 				LOAD_CALC_NO_QUIRKS);
 		load += current_inst_mbs_per_sec * cycles;
 	}
@@ -1122,9 +1121,11 @@
 	if (inst->session_type == MSM_VIDC_ENCODER && hier_mode) {
 		if (current_inst_load / 2 + core0_load <= max_freq &&
 			current_inst_load / 2 + core1_load <= max_freq) {
-			inst->clk_data.core_id = VIDC_CORE_ID_3;
-			msm_vidc_power_save_mode_enable(inst, false);
-			goto decision_done;
+			if (inst->clk_data.work_mode == VIDC_WORK_MODE_2) {
+				inst->clk_data.core_id = VIDC_CORE_ID_3;
+				msm_vidc_power_save_mode_enable(inst, false);
+				goto decision_done;
+			}
 		}
 	}
 
@@ -1133,9 +1134,11 @@
 				core0_lp_load <= max_freq &&
 			current_inst_lp_load / 2 +
 				core1_lp_load <= max_freq) {
-			inst->clk_data.core_id = VIDC_CORE_ID_3;
-			msm_vidc_power_save_mode_enable(inst, true);
-			goto decision_done;
+			if (inst->clk_data.work_mode == VIDC_WORK_MODE_2) {
+				inst->clk_data.core_id = VIDC_CORE_ID_3;
+				msm_vidc_power_save_mode_enable(inst, true);
+				goto decision_done;
+			}
 		}
 	}
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index e72c099..ac53d83 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -489,6 +489,26 @@
 		default:
 			goto unknown_value;
 		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0:
+			return HAL_TME_PROFILE_0;
+		case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1:
+			return HAL_TME_PROFILE_1;
+		case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2:
+			return HAL_TME_PROFILE_2;
+		case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3:
+			return HAL_TME_PROFILE_3;
+		default:
+			goto unknown_value;
+		}
+	case V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL:
+		switch (value) {
+		case V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER:
+			return HAL_TME_LEVEL_INTEGER;
+		default:
+			goto unknown_value;
+		}
 	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
 		switch (value) {
 		case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE:
@@ -533,6 +553,51 @@
 	return -EINVAL;
 }
 
+int msm_comm_get_v4l2_profile(int fourcc, int profile)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_H264:
+		return msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+			profile);
+	case V4L2_PIX_FMT_HEVC:
+		return msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE,
+			profile);
+	case V4L2_PIX_FMT_VP8:
+	case V4L2_PIX_FMT_VP9:
+	case V4L2_PIX_FMT_MPEG2:
+		return 0;
+	default:
+		dprintk(VIDC_WARN, "Unknown codec id %x\n", fourcc);
+		return 0;
+	}
+}
+
+int msm_comm_get_v4l2_level(int fourcc, int level)
+{
+	switch (fourcc) {
+	case V4L2_PIX_FMT_H264:
+		return msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+			level);
+	case V4L2_PIX_FMT_HEVC:
+		return msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL,
+			level);
+	case V4L2_PIX_FMT_VP8:
+		return msm_comm_hal_to_v4l2(
+			V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+			level);
+	case V4L2_PIX_FMT_VP9:
+	case V4L2_PIX_FMT_MPEG2:
+		return 0;
+	default:
+		dprintk(VIDC_WARN, "Unknown codec id %x\n", fourcc);
+		return 0;
+	}
+}
+
 int msm_comm_ctrl_init(struct msm_vidc_inst *inst,
 		struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls,
 		const struct v4l2_ctrl_ops *ctrl_ops)
@@ -737,6 +802,17 @@
 	return load;
 }
 
+int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst,
+		enum load_calc_quirks quirks)
+{
+	int load = msm_comm_get_inst_load(inst, quirks);
+
+	if (inst->clk_data.core_id == VIDC_CORE_ID_3)
+		load = load / 2;
+
+	return load;
+}
+
 int msm_comm_get_load(struct msm_vidc_core *core,
 	enum session_type type, enum load_calc_quirks quirks)
 {
@@ -792,7 +868,6 @@
 	case V4L2_PIX_FMT_H264_MVC:
 		codec = HAL_VIDEO_CODEC_MVC;
 		break;
-
 	case V4L2_PIX_FMT_MPEG1:
 		codec = HAL_VIDEO_CODEC_MPEG1;
 		break;
@@ -808,6 +883,9 @@
 	case V4L2_PIX_FMT_HEVC:
 		codec = HAL_VIDEO_CODEC_HEVC;
 		break;
+	case V4L2_PIX_FMT_TME:
+		codec = HAL_VIDEO_CODEC_TME;
+		break;
 	default:
 		dprintk(VIDC_ERR, "Wrong codec: %d\n", fourcc);
 		codec = HAL_UNUSED_CODEC;
@@ -1252,6 +1330,9 @@
 static void msm_vidc_comm_update_ctrl_limits(struct msm_vidc_inst *inst)
 {
 	if (inst->session_type == MSM_VIDC_ENCODER) {
+		if (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) ==
+			HAL_VIDEO_CODEC_TME)
+			return;
 		msm_vidc_comm_update_ctrl(inst,
 				V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE,
 				&inst->capability.hier_p_hybrid);
@@ -1529,6 +1610,12 @@
 	* ptr[2] = bit depth
 	* ptr[3] = pic struct (progressive or interlaced)
 	* ptr[4] = colour space
+	* ptr[5] = crop_data(top)
+	* ptr[6] = crop_data(left)
+	* ptr[7] = crop_data(height)
+	* ptr[8] = crop_data(width)
+	* ptr[9] = profile
+	* ptr[10] = level
 	*/
 
 	inst->entropy_mode = event_notify->entropy_mode;
@@ -1553,10 +1640,17 @@
 	ptr[6] = event_notify->crop_data.left;
 	ptr[7] = event_notify->crop_data.height;
 	ptr[8] = event_notify->crop_data.width;
+	ptr[9] = msm_comm_get_v4l2_profile(
+		inst->fmts[OUTPUT_PORT].fourcc,
+		event_notify->profile);
+	ptr[10] = msm_comm_get_v4l2_level(
+		inst->fmts[OUTPUT_PORT].fourcc,
+		event_notify->level);
 
 	dprintk(VIDC_DBG,
-		"Event payload: height = %d width = %d\n",
-		event_notify->height, event_notify->width);
+		"Event payload: height = %d width = %d profile = %d level = %d\n",
+			event_notify->height, event_notify->width,
+			ptr[9], ptr[10]);
 
 	dprintk(VIDC_DBG,
 		"Event payload: bit_depth = %d pic_struct = %d colour_space = %d\n",
@@ -2037,6 +2131,7 @@
 	}
 
 	dprintk(VIDC_WARN, "SYS_ERROR received for core %pK\n", core);
+	msm_vidc_noc_error_info(core);
 	call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
 	list_for_each_entry(inst, &core->instances, list) {
 		dprintk(VIDC_WARN,
@@ -5069,6 +5164,28 @@
 	return ret;
 };
 
+int msm_vidc_noc_error_info(struct msm_vidc_core *core)
+{
+	struct hfi_device *hdev;
+
+	if (!core || !core->device) {
+		dprintk(VIDC_WARN, "%s: Invalid parameters: %pK\n",
+			__func__, core);
+		return -EINVAL;
+	}
+
+	if (!core->resources.non_fatal_pagefaults)
+		return 0;
+
+	if (!core->smmu_fault_handled)
+		return 0;
+
+	hdev = core->device;
+	call_hfi_op(hdev, noc_error_info, hdev->hfi_device_data);
+
+	return 0;
+}
+
 int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
 	enum hal_ssr_trigger_type type)
 {
@@ -5221,6 +5338,8 @@
 	int rc = 0;
 	struct hfi_device *hdev;
 	struct msm_vidc_core *core;
+	u32 output_height, output_width;
+	u32 rotation;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__);
@@ -5242,34 +5361,47 @@
 		return -ENOTSUPP;
 	}
 
+	rotation =  msm_comm_g_ctrl_for_id(inst,
+					V4L2_CID_MPEG_VIDC_VIDEO_ROTATION);
+
+	output_height = inst->prop.height[CAPTURE_PORT];
+	output_width = inst->prop.width[CAPTURE_PORT];
+
+	if ((output_width != output_height) &&
+		(rotation == V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90 ||
+		rotation == V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)) {
+
+		output_width = inst->prop.height[CAPTURE_PORT];
+		output_height = inst->prop.width[CAPTURE_PORT];
+		dprintk(VIDC_DBG,
+			"Rotation=%u Swapped Output W=%u H=%u to check capability",
+			rotation, output_width, output_height);
+	}
+
 	if (!rc) {
-		if (inst->prop.width[CAPTURE_PORT] < capability->width.min ||
-			inst->prop.height[CAPTURE_PORT] <
-			capability->height.min) {
+		if (output_width < capability->width.min ||
+			output_height < capability->height.min) {
 			dprintk(VIDC_ERR,
 				"Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n",
-				inst->prop.width[CAPTURE_PORT],
-				inst->prop.height[CAPTURE_PORT],
+				output_width,
+				output_height,
 				capability->width.min,
 				capability->height.min);
 			rc = -ENOTSUPP;
 		}
-		if (!rc && inst->prop.width[CAPTURE_PORT] >
-			capability->width.max) {
+		if (!rc && output_width > capability->width.max) {
 			dprintk(VIDC_ERR,
 				"Unsupported width = %u supported max width = %u\n",
-				inst->prop.width[CAPTURE_PORT],
+				output_width,
 				capability->width.max);
 				rc = -ENOTSUPP;
 		}
 
-		if (!rc && inst->prop.height[CAPTURE_PORT]
-			* inst->prop.width[CAPTURE_PORT] >
+		if (!rc && output_height * output_width >
 			capability->width.max * capability->height.max) {
 			dprintk(VIDC_ERR,
 			"Unsupported WxH = (%u)x(%u), max supported is - (%u)x(%u)\n",
-			inst->prop.width[CAPTURE_PORT],
-			inst->prop.height[CAPTURE_PORT],
+			output_width, output_height,
 			capability->width.max, capability->height.max);
 			rc = -ENOTSUPP;
 		}
@@ -5660,7 +5792,9 @@
 	dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
 			inst, inst->prop.fps, fps);
 	inst->prop.fps = fps;
-	if (inst->session_type == MSM_VIDC_ENCODER) {
+	if (inst->session_type == MSM_VIDC_ENCODER &&
+		get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) !=
+			HAL_VIDEO_CODEC_TME) {
 		frame_rate.frame_rate = inst->prop.fps * BIT(16);
 		frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
 		pdata = &frame_rate;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 4a06f19..a272a10 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -85,6 +85,8 @@
 int msm_comm_check_core_init(struct msm_vidc_core *core);
 int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
 			enum load_calc_quirks quirks);
+int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst,
+			enum load_calc_quirks quirks);
 int msm_comm_get_load(struct msm_vidc_core *core,
 			enum session_type type, enum load_calc_quirks quirks);
 int msm_comm_set_color_format(struct msm_vidc_inst *inst,
@@ -102,6 +104,8 @@
 void msm_comm_print_inst_info(struct msm_vidc_inst *inst);
 int msm_comm_v4l2_to_hal(int id, int value);
 int msm_comm_hal_to_v4l2(int id, int value);
+int msm_comm_get_v4l2_profile(int fourcc, int profile);
+int msm_comm_get_v4l2_level(int fourcc, int level);
 int msm_comm_session_continue(void *instance);
 enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc);
 u32 get_frame_size_nv12(int plane, u32 height, u32 width);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 195410d..1ad28ba 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -395,6 +395,7 @@
 void handle_cmd_response(enum hal_command_response cmd, void *data);
 int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
 	enum hal_ssr_trigger_type type);
+int msm_vidc_noc_error_info(struct msm_vidc_core *core);
 int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
 int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
 void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index 8a701cb..7ca6ab0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -44,6 +44,7 @@
 	CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320),
 	CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320),
 	CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320),
+	CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 125, 675, 320),
 	CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200),
 	CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200),
 	CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200),
@@ -68,6 +69,10 @@
 		.value = 1,
 	},
 	{
+		.key = "qcom,domain-attr-non-fatal-faults",
+		.value = 1,
+	},
+	{
 		.key = "qcom,max-secure-instances",
 		.value = 5,
 	},
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 039b457..46fb75f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -785,6 +785,9 @@
 			"qcom,fw-unload-delay");
 	res->msm_vidc_hw_rsp_timeout = find_key_value(platform_data,
 			"qcom,hw-resp-timeout");
+	res->non_fatal_pagefaults = find_key_value(platform_data,
+			"qcom,domain-attr-non-fatal-faults");
+
 	return rc;
 
 }
@@ -980,8 +983,13 @@
 		return -EINVAL;
 	}
 
-	if (core->smmu_fault_handled)
+	if (core->smmu_fault_handled) {
+		if (core->resources.non_fatal_pagefaults) {
+			msm_vidc_noc_error_info(core);
+			MSM_VIDC_ERROR(true);
+		}
 		return -ENOSYS;
+	}
 
 	dprintk(VIDC_ERR, "%s - faulting address: %lx\n", __func__, iova);
 
@@ -1061,6 +1069,21 @@
 		goto err_setup_cb;
 	}
 
+	if (core->resources.non_fatal_pagefaults) {
+		int data = 1;
+
+		dprintk(VIDC_DBG, "set non-fatal-faults attribute on %s\n",
+				dev_name(dev));
+		rc = iommu_domain_set_attr(cb->mapping->domain,
+					DOMAIN_ATTR_NON_FATAL_FAULTS, &data);
+		if (rc) {
+			dprintk(VIDC_WARN,
+				"%s: set non fatal attribute failed: %s %d\n",
+				__func__, dev_name(dev), rc);
+			/* ignore the error */
+		}
+	}
+
 	iommu_set_fault_handler(cb->mapping->domain,
 		msm_vidc_smmu_fault_handler, (void *)core);
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 8888980..31d5a42 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -189,6 +189,7 @@
 	int msm_vidc_hw_rsp_timeout;
 	int msm_vidc_firmware_unload_delay;
 	uint32_t msm_vidc_pwr_collapse_delay;
+	bool non_fatal_pagefaults;
 	struct msm_vidc_codec_data *codec_data;
 	int codec_data_count;
 };
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 8064f4c..82c3ffc 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -102,6 +102,7 @@
 static int __set_subcaches(struct venus_hfi_device *device);
 static int __release_subcaches(struct venus_hfi_device *device);
 static int __disable_subcaches(struct venus_hfi_device *device);
+static int venus_hfi_noc_error_info(void *dev);
 
 /**
  * Utility function to enforce some of our assumptions.  Spam calls to this
@@ -1089,6 +1090,7 @@
 				return rc;
 			}
 
+			trace_msm_vidc_perf_clock_scale(cl->name, freq);
 			dprintk(VIDC_PROF, "Scaling clock %s to %u\n",
 					cl->name, freq);
 		}
@@ -4271,6 +4273,64 @@
 	return rc;
 }
 
+static int venus_hfi_noc_error_info(void *dev)
+{
+	struct venus_hfi_device *device;
+	u32 val = 0;
+
+	if (!dev) {
+		dprintk(VIDC_ERR, "%s: null device\n", __func__);
+		return -EINVAL;
+	}
+	device = dev;
+
+	mutex_lock(&device->lock);
+	dprintk(VIDC_ERR, "%s: non error information\n", __func__);
+
+	val = __read_register(device, 0x0C500);
+	dprintk(VIDC_ERR, "NOC_ERR_SWID_LOW(0x00AA0C500):     %#x\n", val);
+
+	val = __read_register(device, 0x0C504);
+	dprintk(VIDC_ERR, "NOC_ERR_SWID_HIGH(0x00AA0C504):    %#x\n", val);
+
+	val = __read_register(device, 0x0C508);
+	dprintk(VIDC_ERR, "NOC_ERR_MAINCTL_LOW(0x00AA0C508):  %#x\n", val);
+
+	val = __read_register(device, 0x0C510);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRVLD_LOW(0x00AA0C510):   %#x\n", val);
+
+	val = __read_register(device, 0x0C518);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRCLR_LOW(0x00AA0C518):   %#x\n", val);
+
+	val = __read_register(device, 0x0C520);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRLOG0_LOW(0x00AA0C520):  %#x\n", val);
+
+	val = __read_register(device, 0x0C524);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRLOG0_HIGH(0x00AA0C524): %#x\n", val);
+
+	val = __read_register(device, 0x0C528);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRLOG1_LOW(0x00AA0C528):  %#x\n", val);
+
+	val = __read_register(device, 0x0C52C);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRLOG1_HIGH(0x00AA0C52C): %#x\n", val);
+
+	val = __read_register(device, 0x0C530);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRLOG2_LOW(0x00AA0C530):  %#x\n", val);
+
+	val = __read_register(device, 0x0C534);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRLOG2_HIGH(0x00AA0C534): %#x\n", val);
+
+	val = __read_register(device, 0x0C538);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRLOG3_LOW(0x00AA0C538):  %#x\n", val);
+
+	val = __read_register(device, 0x0C53C);
+	dprintk(VIDC_ERR, "NOC_ERR_ERRLOG3_HIGH(0x00AA0C53C): %#x\n", val);
+
+	mutex_unlock(&device->lock);
+
+	return 0;
+}
+
 static int __initialize_packetization(struct venus_hfi_device *device)
 {
 	int rc = 0;
@@ -4442,6 +4502,7 @@
 	hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
 	hdev->suspend = venus_hfi_suspend;
 	hdev->flush_debug_queue = venus_hfi_flush_debug_queue;
+	hdev->noc_error_info = venus_hfi_noc_error_info;
 	hdev->get_default_properties = venus_hfi_get_default_properties;
 }
 
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index e854b43..f350f25 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -273,6 +273,7 @@
 	HAL_VIDEO_CODEC_VP8      = 0x00001000,
 	HAL_VIDEO_CODEC_HEVC     = 0x00002000,
 	HAL_VIDEO_CODEC_VP9      = 0x00004000,
+	HAL_VIDEO_CODEC_TME      = 0x00008000,
 	HAL_VIDEO_CODEC_HEVC_HYBRID     = 0x80000000,
 	HAL_UNUSED_CODEC = 0x10000000,
 };
@@ -385,6 +386,17 @@
 	HAL_VPX_LEVEL_VERSION_3 = 0x00000008,
 };
 
+enum hal_tme_profile {
+	HAL_TME_PROFILE_0 = 0x00000001,
+	HAL_TME_PROFILE_1 = 0x00000002,
+	HAL_TME_PROFILE_2 = 0x00000004,
+	HAL_TME_PROFILE_3 = 0x00000008,
+};
+
+enum hal_tme_level {
+	HAL_TME_LEVEL_INTEGER = 0x00000001,
+};
+
 struct hal_frame_rate {
 	enum hal_buffer buffer_type;
 	u32 frame_rate;
@@ -1203,6 +1215,7 @@
 	enum buffer_mode_type alloc_mode_out;
 	enum buffer_mode_type alloc_mode_in;
 	u32 pixelprocess_capabilities;
+	u32 tme_version;
 };
 
 struct vidc_hal_sys_init_done {
@@ -1411,6 +1424,7 @@
 	int (*get_core_capabilities)(void *dev);
 	int (*suspend)(void *dev);
 	int (*flush_debug_queue)(void *dev);
+	int (*noc_error_info)(void *dev);
 	enum hal_default_properties (*get_default_properties)(void *dev);
 };
 
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 1d1928a..5e7595c 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1367,6 +1367,8 @@
 			descr = "HEVC"; break;
 		case V4L2_PIX_FMT_VP9:
 			descr = "VP9"; break;
+		case V4L2_PIX_FMT_TME:
+			descr = "TME"; break;
 		default:
 			WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
 			if (fmt->description[0])
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index 2f927bd..501d4a4 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -1068,6 +1068,8 @@
 	struct audio_client *ac;
 	struct audio_aio_write_param param;
 
+	memset(&param, 0, sizeof(param));
+
 	if (!audio || !buf_node) {
 		pr_err("%s NULL pointer audio=[0x%pK], buf_node=[0x%pK]\n",
 			__func__, audio, buf_node);
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index e5fe6ba..aef0db2 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -178,4 +178,11 @@
 	  module is used to configure and read the configuration from the
 	  Serial Engines.
 
+config MSM_EXT_DISPLAY
+	bool "MSM External Display Driver"
+	help
+	  Enabling this option adds MSM External Display Driver.
+	  External Display driver was added to support the communication
+	  between external display driver and its counterparts.
+
 endmenu
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index ff1d0e2..27179b9 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -12,3 +12,4 @@
 obj-$(CONFIG_MSM_11AD) += msm_11ad/
 obj-$(CONFIG_SEEMP_CORE) += seemp_core/
 obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
+obj-$(CONFIG_MSM_EXT_DISPLAY) += msm_ext_display.o
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 9c133a8..7718257 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -1947,6 +1947,20 @@
 	res = wait_for_completion_timeout(&ctx->compl,
 			msecs_to_jiffies(GSI_STOP_CMD_TIMEOUT_MS));
 	if (res == 0) {
+		/*
+		 * check channel state here in case the channel is stopped but
+		 * the interrupt was not handled yet.
+		 */
+		val = gsi_readl(gsi_ctx->base +
+			GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(chan_hdl,
+			gsi_ctx->per.ee));
+		ctx->state = (val &
+			GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_BMSK) >>
+			GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT;
+		if (ctx->state == GSI_CHAN_STATE_STOPPED) {
+			res = GSI_STATUS_SUCCESS;
+			goto free_lock;
+		}
 		GSIDBG("chan_hdl=%lu timed out\n", chan_hdl);
 		res = -GSI_STATUS_TIMED_OUT;
 		goto free_lock;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
index a95547c..5a29cbc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
@@ -941,10 +941,10 @@
 
 	ipa3_dma_debugfs_destroy();
 	kmem_cache_destroy(ipa3_dma_ctx->ipa_dma_xfer_wrapper_cache);
-	kfree(ipa3_dma_ctx);
 	dma_free_coherent(ipa3_ctx->pdev, IPA_DMA_DUMMY_BUFF_SZ * 4,
 		ipa3_dma_ctx->ipa_dma_dummy_src_sync.base,
 		ipa3_dma_ctx->ipa_dma_dummy_src_sync.phys_base);
+	kfree(ipa3_dma_ctx);
 	ipa3_dma_ctx = NULL;
 
 	IPADMA_FUNC_EXIT();
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 018467a..02c5991 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -2574,6 +2574,7 @@
 		WARN_ON(1);
 		return;
 	}
+	spin_lock_bh(&sys->spinlock);
 	rx_pkt_expected = list_first_entry(&sys->head_desc_list,
 					   struct ipa3_rx_pkt_wrapper,
 					   link);
@@ -2581,6 +2582,7 @@
 	sys->len--;
 	if (size)
 		rx_pkt_expected->len = size;
+	spin_unlock_bh(&sys->spinlock);
 	rx_skb = rx_pkt_expected->data.skb;
 	dma_unmap_single(ipa3_ctx->pdev, rx_pkt_expected->data.dma_addr,
 			sys->rx_buff_sz, DMA_FROM_DEVICE);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index 122c541..cc29f8f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -66,12 +66,29 @@
 {
 	struct ipa3_hdr_proc_ctx_entry *entry;
 	int ret;
+	int ep;
 
 	list_for_each_entry(entry,
 			&ipa3_ctx->hdr_proc_ctx_tbl.head_proc_ctx_entry_list,
 			link) {
 		IPADBG_LOW("processing type %d ofst=%d\n",
 			entry->type, entry->offset_entry->offset);
+
+		if (entry->l2tp_params.is_dst_pipe_valid) {
+			ep = ipa3_get_ep_mapping(entry->l2tp_params.dst_pipe);
+			if (ep >= 0) {
+				entry->l2tp_params.hdr_remove_param.
+					hdr_ofst_pkt_size_valid = ipa3_ctx->
+					ep[ep].cfg.hdr.hdr_ofst_pkt_size_valid;
+				entry->l2tp_params.hdr_remove_param.
+					hdr_ofst_pkt_size = ipa3_ctx->ep[ep].
+					cfg.hdr.hdr_ofst_pkt_size;
+				entry->l2tp_params.hdr_remove_param.
+					hdr_endianness = ipa3_ctx->ep[ep].
+					cfg.hdr_ext.hdr_little_endian ? 0 : 1;
+			}
+		}
+
 		ret = ipahal_cp_proc_ctx_to_hw_buff(entry->type, mem->base,
 				entry->offset_entry->offset,
 				entry->hdr->hdr_len,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
index d8785ed..8a4d945 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hw_stats.c
@@ -599,7 +599,7 @@
 	if (!ipa3_ctx->hw_stats.enabled)
 		return 0;
 
-	if (!IPA_CLIENT_IS_PROD(prod) || IPA_CLIENT_IS_CONS(cons) == -1) {
+	if (!IPA_CLIENT_IS_PROD(prod) || !IPA_CLIENT_IS_CONS(cons)) {
 		IPAERR("invalid prod %d or cons %d\n", prod, cons);
 		return -EINVAL;
 	}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 96a022d..43fd4d1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -355,7 +355,7 @@
 	struct list_head link;
 	u32 cookie;
 	enum ipa_hdr_proc_type type;
-	union ipa_l2tp_hdr_proc_ctx_params l2tp_params;
+	struct ipa_l2tp_hdr_proc_ctx_params l2tp_params;
 	struct ipa3_hdr_proc_ctx_offset_entry *offset_entry;
 	struct ipa3_hdr_entry *hdr;
 	u32 ref_cnt;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
index c4b1f35..56fed2a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
@@ -1166,7 +1166,7 @@
 		u32 hdr_len, bool is_hdr_proc_ctx,
 		dma_addr_t phys_base, u32 hdr_base_addr,
 		struct ipa_hdr_offset_entry *offset_entry,
-		union ipa_l2tp_hdr_proc_ctx_params l2tp_params){
+		struct ipa_l2tp_hdr_proc_ctx_params l2tp_params){
 	if (type == IPA_HDR_PROC_NONE) {
 		struct ipa_hw_hdr_proc_ctx_add_hdr_seq *ctx;
 
@@ -1229,6 +1229,17 @@
 			l2tp_params.hdr_remove_param.hdr_len_remove;
 		ctx->l2tp_params.l2tp_params.eth_hdr_retained =
 			l2tp_params.hdr_remove_param.eth_hdr_retained;
+		ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size_valid =
+			l2tp_params.hdr_remove_param.hdr_ofst_pkt_size_valid;
+		ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size =
+			l2tp_params.hdr_remove_param.hdr_ofst_pkt_size;
+		ctx->l2tp_params.l2tp_params.hdr_endianness =
+			l2tp_params.hdr_remove_param.hdr_endianness;
+		IPAHAL_DBG("hdr ofst valid: %d, hdr ofst pkt size: %d\n",
+			ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size_valid,
+			ctx->l2tp_params.l2tp_params.hdr_ofst_pkt_size);
+		IPAHAL_DBG("endianness: %d\n",
+			ctx->l2tp_params.l2tp_params.hdr_endianness);
 
 		IPAHAL_DBG("command id %d\n", ctx->l2tp_params.tlv.value);
 		ctx->end.type = IPA_PROC_CTX_TLV_TYPE_END;
@@ -1303,7 +1314,7 @@
 			bool is_hdr_proc_ctx, dma_addr_t phys_base,
 			u32 hdr_base_addr,
 			struct ipa_hdr_offset_entry *offset_entry,
-			union ipa_l2tp_hdr_proc_ctx_params l2tp_params);
+			struct ipa_l2tp_hdr_proc_ctx_params l2tp_params);
 
 	int (*ipahal_get_proc_ctx_needed_len)(enum ipa_hdr_proc_type type);
 };
@@ -1374,7 +1385,7 @@
 		void *const base, u32 offset, u32 hdr_len,
 		bool is_hdr_proc_ctx, dma_addr_t phys_base,
 		u32 hdr_base_addr, struct ipa_hdr_offset_entry *offset_entry,
-		union ipa_l2tp_hdr_proc_ctx_params l2tp_params)
+		struct ipa_l2tp_hdr_proc_ctx_params l2tp_params)
 {
 	IPAHAL_DBG(
 		"type %d, base %p, offset %d, hdr_len %d, is_hdr_proc_ctx %d, hdr_base_addr %d, offset_entry %p\n"
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
index 0f322b5..56b884b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
@@ -637,7 +637,7 @@
 		bool is_hdr_proc_ctx, dma_addr_t phys_base,
 		u32 hdr_base_addr,
 		struct ipa_hdr_offset_entry *offset_entry,
-		union ipa_l2tp_hdr_proc_ctx_params l2tp_params);
+		struct ipa_l2tp_hdr_proc_ctx_params l2tp_params);
 
 /*
  * ipahal_get_proc_ctx_needed_len() - calculates the needed length for addition
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
new file mode 100644
index 0000000..3be414b
--- /dev/null
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -0,0 +1,525 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+#include <linux/of_platform.h>
+#include <linux/msm_ext_display.h>
+
+struct msm_ext_disp_list {
+	struct msm_ext_disp_init_data *data;
+	struct list_head list;
+};
+
+struct msm_ext_disp {
+	struct msm_ext_disp_data ext_disp_data;
+	struct platform_device *pdev;
+	enum msm_ext_disp_type current_disp;
+	struct msm_ext_disp_audio_codec_ops *ops;
+	struct extcon_dev audio_sdev;
+	bool audio_session_on;
+	struct list_head display_list;
+	struct mutex lock;
+};
+
+static const unsigned int msm_ext_disp_supported_cable[] = {
+	EXTCON_DISP_DP,
+	EXTCON_DISP_HDMI,
+	EXTCON_NONE,
+};
+
+static int msm_ext_disp_extcon_register(struct msm_ext_disp *ext_disp)
+{
+	int ret = 0;
+
+	if (!ext_disp) {
+		pr_err("invalid params\n");
+		return -EINVAL;
+	}
+
+	memset(&ext_disp->audio_sdev, 0x0, sizeof(ext_disp->audio_sdev));
+	ext_disp->audio_sdev.supported_cable = msm_ext_disp_supported_cable;
+	ext_disp->audio_sdev.dev.parent = &ext_disp->pdev->dev;
+	ret = extcon_dev_register(&ext_disp->audio_sdev);
+	if (ret) {
+		pr_err("audio registration failed");
+		return ret;
+	}
+
+	pr_debug("extcon registration done\n");
+
+	return ret;
+}
+
+static void msm_ext_disp_extcon_unregister(struct msm_ext_disp *ext_disp)
+{
+	if (!ext_disp) {
+		pr_err("Invalid params\n");
+		return;
+	}
+
+	extcon_dev_unregister(&ext_disp->audio_sdev);
+}
+
+static const char *msm_ext_disp_name(enum msm_ext_disp_type type)
+{
+	switch (type) {
+	case EXT_DISPLAY_TYPE_HDMI:	return "EXT_DISPLAY_TYPE_HDMI";
+	case EXT_DISPLAY_TYPE_DP:	return "EXT_DISPLAY_TYPE_DP";
+	default: return "???";
+	}
+}
+
+static int msm_ext_disp_add_intf_data(struct msm_ext_disp *ext_disp,
+		struct msm_ext_disp_init_data *data)
+{
+	struct msm_ext_disp_list *node;
+
+	if (!ext_disp && !data) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
+
+	node->data = data;
+	list_add(&node->list, &ext_disp->display_list);
+
+	pr_debug("Added new display (%s)\n", msm_ext_disp_name(data->type));
+
+	return 0;
+}
+
+static int msm_ext_disp_get_intf_data(struct msm_ext_disp *ext_disp,
+		enum msm_ext_disp_type type,
+		struct msm_ext_disp_init_data **data)
+{
+	int ret = 0;
+	struct msm_ext_disp_list *node;
+	struct list_head *position = NULL;
+
+	if (!ext_disp || !data || type < EXT_DISPLAY_TYPE_HDMI ||
+			type >=  EXT_DISPLAY_TYPE_MAX) {
+		pr_err("Invalid params\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	*data = NULL;
+	list_for_each(position, &ext_disp->display_list) {
+		node = list_entry(position, struct msm_ext_disp_list, list);
+		if (node->data->type == type) {
+			*data = node->data;
+			break;
+		}
+	}
+
+	if (!*data) {
+		pr_err("Display not found (%s)\n", msm_ext_disp_name(type));
+		ret = -ENODEV;
+	}
+end:
+	return ret;
+}
+
+static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
+		enum msm_ext_disp_type type,
+		enum msm_ext_disp_cable_state new_state)
+{
+	int ret = 0;
+	int state;
+
+	state = ext_disp->audio_sdev.state;
+	ret = extcon_set_state_sync(&ext_disp->audio_sdev,
+			ext_disp->current_disp, !!new_state);
+
+	pr_debug("Audio state %s %d\n",
+			ext_disp->audio_sdev.state == state ?
+			"is same" : "switched to",
+			ext_disp->audio_sdev.state);
+
+	return ret;
+}
+
+static struct msm_ext_disp *msm_ext_disp_validate_and_get(
+		struct platform_device *pdev,
+		enum msm_ext_disp_type type,
+		enum msm_ext_disp_cable_state state)
+{
+	struct msm_ext_disp_data *ext_disp_data;
+	struct msm_ext_disp *ext_disp;
+
+	if (!pdev) {
+		pr_err("invalid platform device\n");
+		goto err;
+	}
+
+	ext_disp_data = platform_get_drvdata(pdev);
+	if (!ext_disp_data) {
+		pr_err("invalid drvdata\n");
+		goto err;
+	}
+
+	ext_disp = container_of(ext_disp_data,
+			struct msm_ext_disp, ext_disp_data);
+
+	if (state < EXT_DISPLAY_CABLE_DISCONNECT ||
+			state >= EXT_DISPLAY_CABLE_STATE_MAX) {
+		pr_err("invalid HPD state (%d)\n", state);
+		goto err;
+	}
+
+	if (state == EXT_DISPLAY_CABLE_CONNECT) {
+		if (ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX &&
+		    ext_disp->current_disp != type) {
+			pr_err("invalid interface call\n");
+			goto err;
+		}
+	} else {
+		if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX ||
+		    ext_disp->current_disp != type) {
+			pr_err("invalid interface call\n");
+			goto err;
+		}
+	}
+	return ext_disp;
+err:
+	return ERR_PTR(-EINVAL);
+}
+
+static int msm_ext_disp_update_audio_ops(struct msm_ext_disp *ext_disp,
+		enum msm_ext_disp_type type,
+		enum msm_ext_disp_cable_state state)
+{
+	int ret = 0;
+	struct msm_ext_disp_init_data *data = NULL;
+
+	ret = msm_ext_disp_get_intf_data(ext_disp, type, &data);
+	if (ret || !data) {
+		pr_err("interface %s not found\n", msm_ext_disp_name(type));
+		goto end;
+	}
+
+	if (state == EXT_DISPLAY_CABLE_CONNECT) {
+		/* connect codec with interface */
+		*ext_disp->ops = data->codec_ops;
+
+		/* update pdev for interface to use */
+		ext_disp->ext_disp_data.intf_pdev = data->pdev;
+		ext_disp->ext_disp_data.intf_data = data->intf_data;
+
+		ext_disp->current_disp = type;
+
+		pr_debug("codec ops set for %s\n", msm_ext_disp_name(type));
+	} else if (state == EXT_DISPLAY_CABLE_DISCONNECT) {
+		*ext_disp->ops = (struct msm_ext_disp_audio_codec_ops){NULL};
+		ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
+
+		pr_debug("codec ops cleared for %s\n", msm_ext_disp_name(type));
+	}
+end:
+	return ret;
+}
+
+static int msm_ext_disp_audio_config(struct platform_device *pdev,
+		enum msm_ext_disp_type type,
+		enum msm_ext_disp_cable_state state)
+{
+	int ret = 0;
+	struct msm_ext_disp *ext_disp;
+
+	ext_disp = msm_ext_disp_validate_and_get(pdev, type, state);
+	if (IS_ERR(ext_disp)) {
+		ret = PTR_ERR(ext_disp);
+		goto end;
+	}
+
+	mutex_lock(&ext_disp->lock);
+	ret = msm_ext_disp_update_audio_ops(ext_disp, type, state);
+	mutex_unlock(&ext_disp->lock);
+end:
+	return ret;
+}
+
+static int msm_ext_disp_audio_notify(struct platform_device *pdev,
+		enum msm_ext_disp_type type,
+		enum msm_ext_disp_cable_state state)
+{
+	int ret = 0;
+	struct msm_ext_disp *ext_disp;
+
+	ext_disp = msm_ext_disp_validate_and_get(pdev, type, state);
+	if (IS_ERR(ext_disp)) {
+		ret = PTR_ERR(ext_disp);
+		goto end;
+	}
+
+	mutex_lock(&ext_disp->lock);
+	ret = msm_ext_disp_process_audio(ext_disp, type, state);
+	mutex_unlock(&ext_disp->lock);
+end:
+	return ret;
+}
+
+int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+		struct msm_ext_disp_audio_codec_ops *ops)
+{
+	return msm_ext_disp_register_audio_codec(pdev, ops);
+}
+
+int msm_ext_disp_register_audio_codec(struct platform_device *pdev,
+		struct msm_ext_disp_audio_codec_ops *ops)
+{
+	int ret = 0;
+	struct msm_ext_disp *ext_disp = NULL;
+	struct msm_ext_disp_data *ext_disp_data = NULL;
+
+	if (!pdev || !ops) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	ext_disp_data = platform_get_drvdata(pdev);
+	if (!ext_disp_data) {
+		pr_err("Invalid drvdata\n");
+		return -EINVAL;
+	}
+
+	ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+				ext_disp_data);
+
+	mutex_lock(&ext_disp->lock);
+
+	if ((ext_disp->current_disp != EXT_DISPLAY_TYPE_MAX)
+			&& ext_disp->ops) {
+		pr_err("Codec already registered\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	ext_disp->ops = ops;
+
+	pr_debug("audio codec registered\n");
+
+end:
+	mutex_unlock(&ext_disp->lock);
+
+	return ret;
+}
+
+static int msm_ext_disp_validate_intf(struct msm_ext_disp_init_data *init_data)
+{
+	if (!init_data) {
+		pr_err("Invalid init_data\n");
+		return -EINVAL;
+	}
+
+	if (!init_data->pdev) {
+		pr_err("Invalid display intf pdev\n");
+		return -EINVAL;
+	}
+
+	if (!init_data->codec_ops.get_audio_edid_blk ||
+			!init_data->codec_ops.cable_status ||
+			!init_data->codec_ops.audio_info_setup) {
+		pr_err("Invalid codec operation pointers\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int msm_ext_disp_register_intf(struct platform_device *pdev,
+		struct msm_ext_disp_init_data *init_data)
+{
+	int ret = 0;
+	struct msm_ext_disp_init_data *data = NULL;
+	struct msm_ext_disp *ext_disp = NULL;
+	struct msm_ext_disp_data *ext_disp_data = NULL;
+
+	if (!pdev || !init_data) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	ext_disp_data = platform_get_drvdata(pdev);
+	if (!ext_disp_data) {
+		pr_err("Invalid drvdata\n");
+		return -EINVAL;
+	}
+
+	ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+				ext_disp_data);
+
+	mutex_lock(&ext_disp->lock);
+
+	ret = msm_ext_disp_validate_intf(init_data);
+	if (ret)
+		goto end;
+
+	ret = msm_ext_disp_get_intf_data(ext_disp, init_data->type, &data);
+	if (!ret) {
+		pr_err("%s already registered\n",
+			msm_ext_disp_name(init_data->type));
+		goto end;
+	}
+
+	ret = msm_ext_disp_add_intf_data(ext_disp, init_data);
+	if (ret)
+		goto end;
+
+	init_data->intf_ops.audio_config = msm_ext_disp_audio_config;
+	init_data->intf_ops.audio_notify = msm_ext_disp_audio_notify;
+
+	pr_debug("%s registered\n", msm_ext_disp_name(init_data->type));
+
+	mutex_unlock(&ext_disp->lock);
+
+	return ret;
+
+end:
+	mutex_unlock(&ext_disp->lock);
+
+	return ret;
+}
+
+static int msm_ext_disp_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct device_node *of_node = NULL;
+	struct msm_ext_disp *ext_disp = NULL;
+
+	if (!pdev) {
+		pr_err("No platform device found\n");
+		ret = -ENODEV;
+		goto end;
+	}
+
+	of_node = pdev->dev.of_node;
+	if (!of_node) {
+		pr_err("No device node found\n");
+		ret = -ENODEV;
+		goto end;
+	}
+
+	ext_disp = devm_kzalloc(&pdev->dev, sizeof(*ext_disp), GFP_KERNEL);
+	if (!ext_disp) {
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	platform_set_drvdata(pdev, &ext_disp->ext_disp_data);
+	ext_disp->pdev = pdev;
+
+	ret = msm_ext_disp_extcon_register(ext_disp);
+	if (ret)
+		goto extcon_dev_failure;
+
+	ret = of_platform_populate(of_node, NULL, NULL, &pdev->dev);
+	if (ret) {
+		pr_err("Failed to add child devices. Error = %d\n", ret);
+		goto child_node_failure;
+	} else {
+		pr_debug("%s: Added child devices.\n", __func__);
+	}
+
+	mutex_init(&ext_disp->lock);
+
+	INIT_LIST_HEAD(&ext_disp->display_list);
+	ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
+
+	return ret;
+
+child_node_failure:
+	msm_ext_disp_extcon_unregister(ext_disp);
+extcon_dev_failure:
+	devm_kfree(&ext_disp->pdev->dev, ext_disp);
+end:
+	return ret;
+}
+
+static int msm_ext_disp_remove(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct msm_ext_disp *ext_disp = NULL;
+	struct msm_ext_disp_data *ext_disp_data = NULL;
+
+	if (!pdev) {
+		pr_err("No platform device\n");
+		ret = -ENODEV;
+		goto end;
+	}
+
+	ext_disp_data = platform_get_drvdata(pdev);
+	if (!ext_disp_data) {
+		pr_err("No drvdata found\n");
+		ret = -ENODEV;
+		goto end;
+	}
+
+	ext_disp = container_of(ext_disp_data, struct msm_ext_disp,
+				ext_disp_data);
+
+	msm_ext_disp_extcon_unregister(ext_disp);
+
+	mutex_destroy(&ext_disp->lock);
+	devm_kfree(&ext_disp->pdev->dev, ext_disp);
+
+end:
+	return ret;
+}
+
+static const struct of_device_id msm_ext_dt_match[] = {
+	{.compatible = "qcom,msm-ext-disp",},
+	{ /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, msm_ext_dt_match);
+
+static struct platform_driver this_driver = {
+	.probe = msm_ext_disp_probe,
+	.remove = msm_ext_disp_remove,
+	.driver = {
+		.name = "msm-ext-disp",
+		.of_match_table = msm_ext_dt_match,
+	},
+};
+
+static int __init msm_ext_disp_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&this_driver);
+	if (ret)
+		pr_err("failed, ret = %d\n", ret);
+
+	return ret;
+}
+
+static void __exit msm_ext_disp_exit(void)
+{
+	platform_driver_unregister(&this_driver);
+}
+
+subsys_initcall(msm_ext_disp_init);
+module_exit(msm_ext_disp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM External Display");
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 7c77280..2818d56 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -293,20 +293,31 @@
 
 static int geni_se_select_gsi_mode(void __iomem *base)
 {
-	unsigned int io_mode = 0;
 	unsigned int geni_dma_mode = 0;
 	unsigned int gsi_event_en = 0;
+	unsigned int common_geni_m_irq_en = 0;
+	unsigned int common_geni_s_irq_en = 0;
 
+	common_geni_m_irq_en = geni_read_reg(base, SE_GENI_M_IRQ_EN);
+	common_geni_s_irq_en = geni_read_reg(base, SE_GENI_S_IRQ_EN);
+	common_geni_m_irq_en &=
+			~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN |
+			M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+	common_geni_s_irq_en &= ~S_CMD_DONE_EN;
 	geni_dma_mode = geni_read_reg(base, SE_GENI_DMA_MODE_EN);
 	gsi_event_en = geni_read_reg(base, SE_GSI_EVENT_EN);
-	io_mode = geni_read_reg(base, SE_IRQ_EN);
 
 	geni_dma_mode |= GENI_DMA_MODE_EN;
-	io_mode &= ~(DMA_TX_IRQ_EN | DMA_RX_IRQ_EN);
 	gsi_event_en |= (DMA_RX_EVENT_EN | DMA_TX_EVENT_EN |
 				GENI_M_EVENT_EN | GENI_S_EVENT_EN);
 
-	geni_write_reg(io_mode, base, SE_IRQ_EN);
+	geni_write_reg(0, base, SE_IRQ_EN);
+	geni_write_reg(common_geni_s_irq_en, base, SE_GENI_S_IRQ_EN);
+	geni_write_reg(common_geni_m_irq_en, base, SE_GENI_M_IRQ_EN);
+	geni_write_reg(0xFFFFFFFF, base, SE_GENI_M_IRQ_CLEAR);
+	geni_write_reg(0xFFFFFFFF, base, SE_GENI_S_IRQ_CLEAR);
+	geni_write_reg(0xFFFFFFFF, base, SE_DMA_TX_IRQ_CLR);
+	geni_write_reg(0xFFFFFFFF, base, SE_DMA_RX_IRQ_CLR);
 	geni_write_reg(geni_dma_mode, base, SE_GENI_DMA_MODE_EN);
 	geni_write_reg(gsi_event_en, base, SE_GSI_EVENT_EN);
 	return 0;
@@ -691,7 +702,7 @@
 			     struct se_geni_rsc *rsc)
 {
 	unsigned long flags;
-	struct se_geni_rsc *tmp;
+	struct se_geni_rsc *tmp = NULL;
 	struct list_head *ins_list_head;
 	bool bus_bw_update = false;
 	int ret = 0;
@@ -709,7 +720,7 @@
 	list_add(&rsc->ib_list, ins_list_head);
 	/* Currently inserted node has greater average BW value */
 	if (ins_list_head == &geni_se_dev->ib_list_head)
-		geni_se_dev->cur_ib = tmp->ib;
+		geni_se_dev->cur_ib = rsc->ib;
 
 	bus_bw_update = geni_se_check_bus_bw(geni_se_dev);
 	spin_unlock_irqrestore(&geni_se_dev->ab_ib_lock, flags);
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 486e8c3..7f6d346 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -1082,6 +1082,8 @@
 		goto unreg_notifier;
 	}
 
+	chip->taper_pct = 100;
+
 	the_chip = chip;
 
 	return 0;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 56f3b1e..7c94744 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -75,6 +75,8 @@
 #define ESR_TIMER_CHG_MAX_OFFSET	0
 #define ESR_TIMER_CHG_INIT_WORD		18
 #define ESR_TIMER_CHG_INIT_OFFSET	2
+#define ESR_EXTRACTION_ENABLE_WORD	19
+#define ESR_EXTRACTION_ENABLE_OFFSET	0
 #define PROFILE_LOAD_WORD		24
 #define PROFILE_LOAD_OFFSET		0
 #define ESR_RSLOW_DISCHG_WORD		34
@@ -3033,6 +3035,89 @@
 	return 0;
 }
 
+static int fg_force_esr_meas(struct fg_chip *chip)
+{
+	int rc;
+	int esr_uohms;
+
+	/* force esr extraction enable */
+	rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
+			ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0),
+			FG_IMA_DEFAULT);
+	if (rc < 0) {
+		pr_err("failed to enable esr extn rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
+			LD_REG_CTRL_BIT, 0);
+	if (rc < 0) {
+		pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
+			ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
+			ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT);
+	if (rc < 0) {
+		pr_err("Error in configuring force ESR rc=%d\n", rc);
+		return rc;
+	}
+
+	/* wait 1.5 seconds for hw to measure ESR */
+	msleep(1500);
+	rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
+			ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
+			0);
+	if (rc < 0) {
+		pr_err("Error in restoring force ESR rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
+			LD_REG_CTRL_BIT, LD_REG_CTRL_BIT);
+	if (rc < 0) {
+		pr_err("Error in restoring qnovo_cfg rc=%d\n", rc);
+		return rc;
+	}
+
+	/* force esr extraction disable */
+	rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
+			ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), 0,
+			FG_IMA_DEFAULT);
+	if (rc < 0) {
+		pr_err("failed to disable esr extn rc=%d\n", rc);
+		return rc;
+	}
+
+	fg_get_battery_resistance(chip, &esr_uohms);
+	fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms);
+
+	return rc;
+}
+
+static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable)
+{
+	int rc;
+
+	/* force esr extraction disable when qnovo enables */
+	rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
+			ESR_EXTRACTION_ENABLE_OFFSET,
+			BIT(0), qnovo_enable ? 0 : BIT(0),
+			FG_IMA_DEFAULT);
+	if (rc < 0)
+		pr_err("Error in configuring esr extraction rc=%d\n", rc);
+
+	rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
+			LD_REG_CTRL_BIT,
+			qnovo_enable ? LD_REG_CTRL_BIT : 0);
+	if (rc < 0) {
+		pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
+		return rc;
+	}
+	fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n");
+	return 0;
+}
 /* PSY CALLBACKS STAY HERE */
 
 static int fg_psy_get_property(struct power_supply *psy,
@@ -3141,6 +3226,12 @@
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 		rc = fg_set_constant_chg_voltage(chip, pval->intval);
 		break;
+	case POWER_SUPPLY_PROP_RESISTANCE:
+		rc = fg_force_esr_meas(chip);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
+		rc = fg_prepare_for_qnovo(chip, pval->intval);
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index eb97eb0..cf90f90 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -20,6 +20,7 @@
 #include <linux/of_irq.h>
 #include <linux/qpnp/qpnp-revid.h>
 #include <linux/pmic-voter.h>
+#include <linux/delay.h>
 
 #define QNOVO_REVISION1		0x00
 #define QNOVO_REVISION2		0x01
@@ -114,6 +115,17 @@
 #define OK_TO_QNOVO_VOTER	"ok_to_qnovo_voter"
 
 #define QNOVO_VOTER		"qnovo_voter"
+#define FG_AVAILABLE_VOTER	"FG_AVAILABLE_VOTER"
+#define QNOVO_OVERALL_VOTER	"QNOVO_OVERALL_VOTER"
+#define QNI_PT_VOTER		"QNI_PT_VOTER"
+#define ESR_VOTER		"ESR_VOTER"
+
+#define HW_OK_TO_QNOVO_VOTER	"HW_OK_TO_QNOVO_VOTER"
+#define CHG_READY_VOTER		"CHG_READY_VOTER"
+#define USB_READY_VOTER		"USB_READY_VOTER"
+#define DC_READY_VOTER		"DC_READY_VOTER"
+
+#define PT_RESTART_VOTER	"PT_RESTART_VOTER"
 
 struct qnovo_dt_props {
 	bool			external_rsense;
@@ -127,6 +139,10 @@
 	struct qnovo_dt_props	dt;
 	struct device		*dev;
 	struct votable		*disable_votable;
+	struct votable		*pt_dis_votable;
+	struct votable		*not_ok_to_qnovo_votable;
+	struct votable		*chg_ready_votable;
+	struct votable		*awake_votable;
 	struct class		qnovo_class;
 	struct pmic_revid_data	*pmic_rev_id;
 	u32			wa_flags;
@@ -138,10 +154,18 @@
 	s64			v_gain_mega;
 	struct notifier_block	nb;
 	struct power_supply	*batt_psy;
+	struct power_supply	*bms_psy;
+	struct power_supply	*usb_psy;
+	struct power_supply	*dc_psy;
 	struct work_struct	status_change_work;
 	int			fv_uV_request;
 	int			fcc_uA_request;
-	bool			ok_to_qnovo;
+	int			usb_present;
+	int			dc_present;
+	struct delayed_work	usb_debounce_work;
+	struct delayed_work	dc_debounce_work;
+
+	struct delayed_work	ptrain_restart_work;
 };
 
 static int debug_mask;
@@ -229,6 +253,39 @@
 	return true;
 }
 
+static bool is_fg_available(struct qnovo *chip)
+{
+	if (!chip->bms_psy)
+		chip->bms_psy = power_supply_get_by_name("bms");
+
+	if (!chip->bms_psy)
+		return false;
+
+	return true;
+}
+
+static bool is_usb_available(struct qnovo *chip)
+{
+	if (!chip->usb_psy)
+		chip->usb_psy = power_supply_get_by_name("usb");
+
+	if (!chip->usb_psy)
+		return false;
+
+	return true;
+}
+
+static bool is_dc_available(struct qnovo *chip)
+{
+	if (!chip->dc_psy)
+		chip->dc_psy = power_supply_get_by_name("dc");
+
+	if (!chip->dc_psy)
+		return false;
+
+	return true;
+}
+
 static int qnovo_batt_psy_update(struct qnovo *chip, bool disable)
 {
 	union power_supply_propval pval = {0};
@@ -281,10 +338,86 @@
 		return -EINVAL;
 	}
 
+	/*
+	 * fg must be available for enable FG_AVAILABLE_VOTER
+	 * won't enable it otherwise
+	 */
+
+	if (is_fg_available(chip))
+		power_supply_set_property(chip->bms_psy,
+				POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE,
+				&pval);
+
+	vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, disable, 0);
 	rc = qnovo_batt_psy_update(chip, disable);
 	return rc;
 }
 
+static int pt_dis_votable_cb(struct votable *votable, void *data, int disable,
+					const char *client)
+{
+	struct qnovo *chip = data;
+	int rc;
+
+	if (disable) {
+		cancel_delayed_work_sync(&chip->ptrain_restart_work);
+		vote(chip->awake_votable, PT_RESTART_VOTER, false, 0);
+	}
+
+	rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
+				 (bool)disable ? 0 : QNOVO_PTRAIN_EN_BIT);
+	if (rc < 0) {
+		dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n",
+			(bool)disable ? "disable" : "enable", rc);
+		return rc;
+	}
+
+	if (!disable) {
+		vote(chip->awake_votable, PT_RESTART_VOTER, true, 0);
+		schedule_delayed_work(&chip->ptrain_restart_work,
+				msecs_to_jiffies(20));
+	}
+
+	return 0;
+}
+
+static int not_ok_to_qnovo_cb(struct votable *votable, void *data,
+					int not_ok_to_qnovo,
+					const char *client)
+{
+	struct qnovo *chip = data;
+
+	vote(chip->disable_votable, OK_TO_QNOVO_VOTER, not_ok_to_qnovo, 0);
+	if (not_ok_to_qnovo)
+		vote(chip->disable_votable, USER_VOTER, true, 0);
+
+	kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
+	return 0;
+}
+
+static int chg_ready_cb(struct votable *votable, void *data, int ready,
+					const char *client)
+{
+	struct qnovo *chip = data;
+
+	vote(chip->not_ok_to_qnovo_votable, CHG_READY_VOTER, !ready, 0);
+
+	return 0;
+}
+
+static int awake_cb(struct votable *votable, void *data, int awake,
+					const char *client)
+{
+	struct qnovo *chip = data;
+
+	if (awake)
+		pm_stay_awake(chip->dev);
+	else
+		pm_relax(chip->dev);
+
+	return 0;
+}
+
 static int qnovo_parse_dt(struct qnovo *chip)
 {
 	struct device_node *node = chip->dev->of_node;
@@ -626,8 +759,9 @@
 			char *buf)
 {
 	struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
+	int val = get_effective_result(chip->not_ok_to_qnovo_votable);
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", chip->ok_to_qnovo);
+	return snprintf(buf, PAGE_SIZE, "%d\n", !val);
 }
 
 static ssize_t qnovo_enable_show(struct class *c, struct class_attribute *attr,
@@ -656,21 +790,10 @@
 static ssize_t pt_enable_show(struct class *c, struct class_attribute *attr,
 			char *ubuf)
 {
-	int i = attr - qnovo_attributes;
 	struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
-	u8 buf[2] = {0, 0};
-	u16 regval;
-	int rc;
+	int val = get_effective_result(chip->pt_dis_votable);
 
-	rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs);
-	if (rc < 0) {
-		pr_err("Couldn't read %s rc = %d\n", params[i].name, rc);
-		return -EINVAL;
-	}
-	regval = buf[1] << 8 | buf[0];
-
-	return snprintf(ubuf, PAGE_SIZE, "%d\n",
-				(int)(regval & QNOVO_PTRAIN_EN_BIT));
+	return snprintf(ubuf, PAGE_SIZE, "%d\n", !val);
 }
 
 static ssize_t pt_enable_store(struct class *c, struct class_attribute *attr,
@@ -678,21 +801,12 @@
 {
 	struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
 	unsigned long val;
-	int rc = 0;
-
-	if (get_effective_result(chip->disable_votable))
-		return -EINVAL;
 
 	if (kstrtoul(ubuf, 0, &val))
 		return -EINVAL;
 
-	rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
-				 (bool)val ? QNOVO_PTRAIN_EN_BIT : 0);
-	if (rc < 0) {
-		dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n",
-			(bool)val ? "enable" : "disable", rc);
-		return rc;
-	}
+	/* val being 0, userspace wishes to disable pt so vote true */
+	vote(chip->pt_dis_votable, QNI_PT_VOTER, val ? false : true, 0);
 
 	return count;
 }
@@ -1116,41 +1230,146 @@
 {
 	u8 val = 0;
 	int rc;
-	bool ok_to_qnovo;
-	bool changed = false;
+	bool hw_ok_to_qnovo;
 
 	rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1);
 	if (rc < 0) {
 		pr_err("Couldn't read error sts rc = %d\n", rc);
-		ok_to_qnovo = false;
+		hw_ok_to_qnovo = false;
 	} else {
 		/*
 		 * For CV mode keep qnovo enabled, userspace is expected to
 		 * disable it after few runs
 		 */
-		ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? true : false;
+		hw_ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ?
+			true : false;
 	}
 
-	if (chip->ok_to_qnovo ^ ok_to_qnovo) {
-
-		vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !ok_to_qnovo, 0);
-		if (!ok_to_qnovo)
-			vote(chip->disable_votable, USER_VOTER, true, 0);
-
-		chip->ok_to_qnovo = ok_to_qnovo;
-		changed = true;
-	}
-
-	return changed;
+	vote(chip->not_ok_to_qnovo_votable, HW_OK_TO_QNOVO_VOTER,
+					!hw_ok_to_qnovo, 0);
+	return 0;
 }
 
+static void usb_debounce_work(struct work_struct *work)
+{
+	struct qnovo *chip = container_of(work,
+				struct qnovo, usb_debounce_work.work);
+
+	vote(chip->chg_ready_votable, USB_READY_VOTER, true, 0);
+	vote(chip->awake_votable, USB_READY_VOTER, false, 0);
+}
+
+static void dc_debounce_work(struct work_struct *work)
+{
+	struct qnovo *chip = container_of(work,
+				struct qnovo, dc_debounce_work.work);
+
+	vote(chip->chg_ready_votable, DC_READY_VOTER, true, 0);
+	vote(chip->awake_votable, DC_READY_VOTER, false, 0);
+}
+
+#define DEBOUNCE_MS 15000  /* 15 seconds */
 static void status_change_work(struct work_struct *work)
 {
 	struct qnovo *chip = container_of(work,
 			struct qnovo, status_change_work);
+	union power_supply_propval pval;
+	bool usb_present = false, dc_present = false;
+	int rc;
 
-	if (qnovo_update_status(chip))
-		kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
+	if (is_fg_available(chip))
+		vote(chip->disable_votable, FG_AVAILABLE_VOTER, false, 0);
+
+	if (is_usb_available(chip)) {
+		rc = power_supply_get_property(chip->usb_psy,
+				POWER_SUPPLY_PROP_PRESENT, &pval);
+		usb_present = (rc < 0) ? 0 : pval.intval;
+	}
+
+	if (chip->usb_present && !usb_present) {
+		/* removal */
+		chip->usb_present = 0;
+		cancel_delayed_work_sync(&chip->usb_debounce_work);
+		vote(chip->awake_votable, USB_READY_VOTER, false, 0);
+		vote(chip->chg_ready_votable, USB_READY_VOTER, false, 0);
+	} else if (!chip->usb_present && usb_present) {
+		/* insertion */
+		chip->usb_present = 1;
+		vote(chip->awake_votable, USB_READY_VOTER, true, 0);
+		schedule_delayed_work(&chip->usb_debounce_work,
+				msecs_to_jiffies(DEBOUNCE_MS));
+	}
+
+	if (is_dc_available(chip)) {
+		rc = power_supply_get_property(chip->dc_psy,
+			POWER_SUPPLY_PROP_PRESENT,
+			&pval);
+		dc_present = (rc < 0) ? 0 : pval.intval;
+	}
+
+	if (usb_present)
+		dc_present = 0;
+
+	if (chip->dc_present && !dc_present) {
+		/* removal */
+		chip->dc_present = 0;
+		cancel_delayed_work_sync(&chip->dc_debounce_work);
+		vote(chip->awake_votable, DC_READY_VOTER, false, 0);
+		vote(chip->chg_ready_votable, DC_READY_VOTER, false, 0);
+	} else if (!chip->dc_present && dc_present) {
+		/* insertion */
+		chip->dc_present = 1;
+		vote(chip->awake_votable, DC_READY_VOTER, true, 0);
+		schedule_delayed_work(&chip->dc_debounce_work,
+				msecs_to_jiffies(DEBOUNCE_MS));
+	}
+
+	qnovo_update_status(chip);
+}
+
+static void ptrain_restart_work(struct work_struct *work)
+{
+	struct qnovo *chip = container_of(work,
+				struct qnovo, ptrain_restart_work.work);
+	u8 pt_t1, pt_t2;
+	int rc;
+
+	rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t1, 1);
+	if (rc < 0) {
+		dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n",
+			rc);
+		goto clean_up;
+	}
+
+	/* pttime increments every 2 seconds */
+	msleep(2100);
+
+	rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t2, 1);
+	if (rc < 0) {
+		dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n",
+			rc);
+		goto clean_up;
+	}
+
+	if (pt_t1 != pt_t2)
+		goto clean_up;
+
+	/* Toggle pt enable to restart pulse train */
+	rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, 0);
+	if (rc < 0) {
+		dev_err(chip->dev, "Couldn't disable pulse train rc=%d\n", rc);
+		goto clean_up;
+	}
+	msleep(1000);
+	rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
+				QNOVO_PTRAIN_EN_BIT);
+	if (rc < 0) {
+		dev_err(chip->dev, "Couldn't enable pulse train rc=%d\n", rc);
+		goto clean_up;
+	}
+
+clean_up:
+	vote(chip->awake_votable, PT_RESTART_VOTER, false, 0);
 }
 
 static int qnovo_notifier_call(struct notifier_block *nb,
@@ -1162,7 +1381,10 @@
 	if (ev != PSY_EVENT_PROP_CHANGED)
 		return NOTIFY_OK;
 
-	if (strcmp(psy->desc->name, "battery") == 0)
+	if (strcmp(psy->desc->name, "battery") == 0
+		|| strcmp(psy->desc->name, "bms") == 0
+		|| strcmp(psy->desc->name, "usb") == 0
+		|| strcmp(psy->desc->name, "dc") == 0)
 		schedule_work(&chip->status_change_work);
 
 	return NOTIFY_OK;
@@ -1171,7 +1393,23 @@
 static irqreturn_t handle_ptrain_done(int irq, void *data)
 {
 	struct qnovo *chip = data;
+	union power_supply_propval pval = {0};
 
+	/*
+	 * hw resets pt_en bit once ptrain_done triggers.
+	 * vote on behalf of QNI to disable it such that
+	 * once QNI enables it, the votable state changes
+	 * and the callback that sets it is indeed invoked
+	 */
+	vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0);
+
+	vote(chip->pt_dis_votable, ESR_VOTER, true, 0);
+	if (is_fg_available(chip))
+		power_supply_set_property(chip->bms_psy,
+				POWER_SUPPLY_PROP_RESISTANCE,
+				&pval);
+
+	vote(chip->pt_dis_votable, ESR_VOTER, false, 0);
 	qnovo_update_status(chip);
 	kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
 	return IRQ_HANDLED;
@@ -1186,6 +1424,11 @@
 	u8 val;
 
 	vote(chip->disable_votable, USER_VOTER, true, 0);
+	vote(chip->disable_votable, FG_AVAILABLE_VOTER, true, 0);
+
+	vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0);
+	vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, true, 0);
+	vote(chip->pt_dis_votable, ESR_VOTER, false, 0);
 
 	val = 0;
 	rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1);
@@ -1349,12 +1592,45 @@
 		goto cleanup;
 	}
 
+	chip->pt_dis_votable = create_votable("QNOVO_PT_DIS", VOTE_SET_ANY,
+					pt_dis_votable_cb, chip);
+	if (IS_ERR(chip->pt_dis_votable)) {
+		rc = PTR_ERR(chip->pt_dis_votable);
+		goto destroy_disable_votable;
+	}
+
+	chip->not_ok_to_qnovo_votable = create_votable("QNOVO_NOT_OK",
+					VOTE_SET_ANY,
+					not_ok_to_qnovo_cb, chip);
+	if (IS_ERR(chip->not_ok_to_qnovo_votable)) {
+		rc = PTR_ERR(chip->not_ok_to_qnovo_votable);
+		goto destroy_pt_dis_votable;
+	}
+
+	chip->chg_ready_votable = create_votable("QNOVO_CHG_READY",
+					VOTE_SET_ANY,
+					chg_ready_cb, chip);
+	if (IS_ERR(chip->chg_ready_votable)) {
+		rc = PTR_ERR(chip->chg_ready_votable);
+		goto destroy_not_ok_to_qnovo_votable;
+	}
+
+	chip->awake_votable = create_votable("QNOVO_AWAKE", VOTE_SET_ANY,
+					awake_cb, chip);
+	if (IS_ERR(chip->awake_votable)) {
+		rc = PTR_ERR(chip->awake_votable);
+		goto destroy_chg_ready_votable;
+	}
+
 	INIT_WORK(&chip->status_change_work, status_change_work);
+	INIT_DELAYED_WORK(&chip->dc_debounce_work, dc_debounce_work);
+	INIT_DELAYED_WORK(&chip->usb_debounce_work, usb_debounce_work);
+	INIT_DELAYED_WORK(&chip->ptrain_restart_work, ptrain_restart_work);
 
 	rc = qnovo_hw_init(chip);
 	if (rc < 0) {
 		pr_err("Couldn't initialize hardware rc=%d\n", rc);
-		goto destroy_votable;
+		goto destroy_awake_votable;
 	}
 
 	rc = qnovo_register_notifier(chip);
@@ -1390,7 +1666,15 @@
 
 unreg_notifier:
 	power_supply_unreg_notifier(&chip->nb);
-destroy_votable:
+destroy_awake_votable:
+	destroy_votable(chip->awake_votable);
+destroy_chg_ready_votable:
+	destroy_votable(chip->chg_ready_votable);
+destroy_not_ok_to_qnovo_votable:
+	destroy_votable(chip->not_ok_to_qnovo_votable);
+destroy_pt_dis_votable:
+	destroy_votable(chip->pt_dis_votable);
+destroy_disable_votable:
 	destroy_votable(chip->disable_votable);
 cleanup:
 	platform_set_drvdata(pdev, NULL);
@@ -1403,6 +1687,9 @@
 
 	class_unregister(&chip->qnovo_class);
 	power_supply_unreg_notifier(&chip->nb);
+	destroy_votable(chip->chg_ready_votable);
+	destroy_votable(chip->not_ok_to_qnovo_votable);
+	destroy_votable(chip->pt_dis_votable);
 	destroy_votable(chip->disable_votable);
 	platform_set_drvdata(pdev, NULL);
 	return 0;
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 5605c8a..faca084 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -210,6 +210,9 @@
 	chg->step_chg_enabled = of_property_read_bool(node,
 				"qcom,step-charging-enable");
 
+	chg->sw_jeita_enabled = of_property_read_bool(node,
+				"qcom,sw-jeita-enable");
+
 	rc = of_property_read_u32(node, "qcom,wd-bark-time-secs",
 					&chip->dt.wd_bark_time);
 	if (rc < 0 || chip->dt.wd_bark_time < MIN_WD_BARK_TIME)
@@ -1031,6 +1034,9 @@
 	struct smb_charger *chg = power_supply_get_drvdata(psy);
 
 	switch (prop) {
+	case POWER_SUPPLY_PROP_STATUS:
+		rc = smblib_set_prop_batt_status(chg, val);
+		break;
 	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
 		rc = smblib_set_prop_input_suspend(chg, val);
 		break;
@@ -1108,6 +1114,7 @@
 		enum power_supply_property psp)
 {
 	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
 	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
 	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
 	case POWER_SUPPLY_PROP_CAPACITY:
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 57a85de..c57f7ef 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -1570,8 +1570,8 @@
 				union power_supply_propval *val)
 {
 	union power_supply_propval pval = {0, };
-	bool usb_online, dc_online;
-	u8 stat;
+	bool usb_online, dc_online, qnovo_en;
+	u8 stat, pt_en_cmd;
 	int rc;
 
 	rc = smblib_get_prop_usb_online(chg, &pval);
@@ -1634,16 +1634,33 @@
 	if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
 		return 0;
 
+	if (!usb_online && dc_online
+		&& chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) {
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		return 0;
+	}
+
 	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
 	if (rc < 0) {
 		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
 				rc);
 			return rc;
-		}
+	}
 
 	stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
 		 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
-	if (!stat)
+
+	rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &pt_en_cmd);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD_REG rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	qnovo_en = (bool)(pt_en_cmd & QNOVO_PT_ENABLE_CMD_BIT);
+
+	/* ignore stat7 when qnovo is enabled */
+	if (!qnovo_en && !stat)
 		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
 
 	return 0;
@@ -1876,6 +1893,20 @@
 	return 0;
 }
 
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+				  const union power_supply_propval *val)
+{
+	/* Faking battery full */
+	if (val->intval == POWER_SUPPLY_STATUS_FULL)
+		chg->fake_batt_status = val->intval;
+	else
+		chg->fake_batt_status = -EINVAL;
+
+	power_supply_changed(chg->batt_psy);
+
+	return 0;
+}
+
 int smblib_set_prop_system_temp_level(struct smb_charger *chg,
 				const union power_supply_propval *val)
 {
@@ -2370,16 +2401,9 @@
 int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
 						union power_supply_propval *val)
 {
-	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
 	int rc, pulses;
 
-	val->intval = MICRO_5V;
-	if (apsd_result == NULL) {
-		smblib_err(chg, "APSD result is NULL\n");
-		return 0;
-	}
-
-	switch (apsd_result->pst) {
+	switch (chg->real_charger_type) {
 	case POWER_SUPPLY_TYPE_USB_HVDCP_3:
 		rc = smblib_get_pulse_cnt(chg, &pulses);
 		if (rc < 0) {
@@ -2389,6 +2413,9 @@
 		}
 		val->intval = MICRO_5V + HVDCP3_STEP_UV * pulses;
 		break;
+	case POWER_SUPPLY_TYPE_USB_PD:
+		val->intval = chg->voltage_min_uv;
+		break;
 	default:
 		val->intval = MICRO_5V;
 		break;
@@ -2636,6 +2663,7 @@
 	}
 
 	chg->voltage_min_uv = min_uv;
+	power_supply_changed(chg->usb_main_psy);
 	return rc;
 }
 
@@ -4083,7 +4111,7 @@
 	if (rc < 0)
 		smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc);
 
-	if (chg->step_chg_enabled)
+	if (chg->step_chg_enabled || chg->sw_jeita_enabled)
 		power_supply_changed(chg->batt_psy);
 
 	return IRQ_HANDLED;
@@ -4711,6 +4739,7 @@
 	INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
 	chg->fake_capacity = -EINVAL;
 	chg->fake_input_current_limited = -EINVAL;
+	chg->fake_batt_status = -EINVAL;
 
 	switch (chg->mode) {
 	case PARALLEL_MASTER:
@@ -4721,7 +4750,8 @@
 			return rc;
 		}
 
-		rc = qcom_step_chg_init(chg->step_chg_enabled);
+		rc = qcom_step_chg_init(chg->step_chg_enabled,
+						chg->sw_jeita_enabled);
 		if (rc < 0) {
 			smblib_err(chg, "Couldn't init qcom_step_chg_init rc=%d\n",
 				rc);
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 4ffbeb6..2746555 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -307,7 +307,9 @@
 	int			*thermal_mitigation;
 	int			dcp_icl_ua;
 	int			fake_capacity;
+	int			fake_batt_status;
 	bool			step_chg_enabled;
+	bool			sw_jeita_enabled;
 	bool			is_hdc;
 	bool			chg_done;
 	bool			micro_usb_mode;
@@ -426,6 +428,8 @@
 				const union power_supply_propval *val);
 int smblib_set_prop_batt_capacity(struct smb_charger *chg,
 				const union power_supply_propval *val);
+int smblib_set_prop_batt_status(struct smb_charger *chg,
+				const union power_supply_propval *val);
 int smblib_set_prop_system_temp_level(struct smb_charger *chg,
 				const union power_supply_propval *val);
 int smblib_set_prop_input_current_limited(struct smb_charger *chg,
diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c
index a2c08be..053aac3 100644
--- a/drivers/power/supply/qcom/step-chg-jeita.c
+++ b/drivers/power/supply/qcom/step-chg-jeita.c
@@ -20,7 +20,7 @@
 
 #define MAX_STEP_CHG_ENTRIES	8
 #define STEP_CHG_VOTER		"STEP_CHG_VOTER"
-#define STATUS_CHANGE_VOTER	"STATUS_CHANGE_VOTER"
+#define JEITA_VOTER		"JEITA_VOTER"
 
 #define is_between(left, right, value) \
 		(((left) >= (right) && (left) >= (value) \
@@ -28,23 +28,44 @@
 		|| ((left) <= (right) && (left) <= (value) \
 			&& (value) <= (right)))
 
-struct step_chg_data {
-	u32 vbatt_soc_low;
-	u32 vbatt_soc_high;
-	u32 fcc_ua;
+struct range_data {
+	u32 low_threshold;
+	u32 high_threshold;
+	u32 value;
 };
 
 struct step_chg_cfg {
-	u32 psy_prop;
-	char *prop_name;
-	struct step_chg_data cfg[MAX_STEP_CHG_ENTRIES];
+	u32			psy_prop;
+	char			*prop_name;
+	int			hysteresis;
+	struct range_data	fcc_cfg[MAX_STEP_CHG_ENTRIES];
+};
+
+struct jeita_fcc_cfg {
+	u32			psy_prop;
+	char			*prop_name;
+	int			hysteresis;
+	struct range_data	fcc_cfg[MAX_STEP_CHG_ENTRIES];
+};
+
+struct jeita_fv_cfg {
+	u32			psy_prop;
+	char			*prop_name;
+	int			hysteresis;
+	struct range_data	fv_cfg[MAX_STEP_CHG_ENTRIES];
 };
 
 struct step_chg_info {
-	ktime_t			last_update_time;
+	ktime_t			step_last_update_time;
+	ktime_t			jeita_last_update_time;
 	bool			step_chg_enable;
+	bool			sw_jeita_enable;
+	int			jeita_fcc_index;
+	int			jeita_fv_index;
+	int			step_index;
 
 	struct votable		*fcc_votable;
+	struct votable		*fv_votable;
 	struct wakeup_source	*step_chg_ws;
 	struct power_supply	*batt_psy;
 	struct delayed_work	status_change_work;
@@ -53,32 +74,70 @@
 
 static struct step_chg_info *the_chip;
 
+#define STEP_CHG_HYSTERISIS_DELAY_US		5000000 /* 5 secs */
+
 /*
  * Step Charging Configuration
  * Update the table based on the battery profile
  * Supports VBATT and SOC based source
+ * range data must be in increasing ranges and shouldn't overlap
  */
 static struct step_chg_cfg step_chg_config = {
-	.psy_prop  = POWER_SUPPLY_PROP_VOLTAGE_NOW,
-	.prop_name = "VBATT",
-	.cfg	 = {
+	.psy_prop	= POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	.prop_name	= "VBATT",
+	.hysteresis	= 100000, /* 100mV */
+	.fcc_cfg	= {
 		/* VBAT_LOW	VBAT_HIGH	FCC */
 		{3600000,	4000000,	3000000},
-		{4000000,	4200000,	2800000},
-		{4200000,	4400000,	2000000},
+		{4001000,	4200000,	2800000},
+		{4201000,	4400000,	2000000},
 	},
+	/*
+	 *	SOC STEP-CHG configuration example.
+	 *
+	 *	.psy_prop = POWER_SUPPLY_PROP_CAPACITY,
+	 *	.prop_name = "SOC",
+	 *	.fcc_cfg	= {
+	 *		//SOC_LOW	SOC_HIGH	FCC
+	 *		{20,		70,		3000000},
+	 *		{70,		90,		2750000},
+	 *		{90,		100,		2500000},
+	 *	},
+	 */
+};
+
 /*
- *	SOC STEP-CHG configuration example.
- *
- *	.psy_prop = POWER_SUPPLY_PROP_CAPACITY,
- *	.prop_name = "SOC",
- *	.cfg	= {
- *		//SOC_LOW	SOC_HIGH	FCC
- *		{20,		70,		3000000},
- *		{70,		90,		2750000},
- *		{90,		100,		2500000},
- *	},
+ * Jeita Charging Configuration
+ * Update the table based on the battery profile
+ * Please ensure that the TEMP ranges are programmed in the hw so that
+ * an interrupt is issued and a consequent psy changed will cause us to
+ * react immediately.
+ * range data must be in increasing ranges and shouldn't overlap.
+ * Gaps are okay
  */
+static struct jeita_fcc_cfg jeita_fcc_config = {
+	.psy_prop	= POWER_SUPPLY_PROP_TEMP,
+	.prop_name	= "BATT_TEMP",
+	.hysteresis	= 10, /* 1degC hysteresis */
+	.fcc_cfg	= {
+		/* TEMP_LOW	TEMP_HIGH	FCC */
+		{0,		100,		600000},
+		{101,		200,		2000000},
+		{201,		450,		3000000},
+		{451,		550,		600000},
+	},
+};
+
+static struct jeita_fv_cfg jeita_fv_config = {
+	.psy_prop	= POWER_SUPPLY_PROP_TEMP,
+	.prop_name	= "BATT_TEMP",
+	.hysteresis	= 10, /* 1degC hysteresis */
+	.fv_cfg		= {
+		/* TEMP_LOW	TEMP_HIGH	FCC */
+		{0,		100,		4200000},
+		{101,		450,		4400000},
+		{451,		550,		4200000},
+	},
 };
 
 static bool is_batt_available(struct step_chg_info *chip)
@@ -92,22 +151,67 @@
 	return true;
 }
 
-static int get_fcc(int threshold)
+static int get_val(struct range_data *range, int hysteresis, int current_index,
+		int threshold,
+		int *new_index, int *val)
 {
 	int i;
 
+	*new_index = -EINVAL;
+	/* first find the matching index without hysteresis */
 	for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
-		if (is_between(step_chg_config.cfg[i].vbatt_soc_low,
-			step_chg_config.cfg[i].vbatt_soc_high, threshold))
-			return step_chg_config.cfg[i].fcc_ua;
+		if (is_between(range[i].low_threshold,
+			range[i].high_threshold, threshold)) {
+			*new_index = i;
+			*val = range[i].value;
+		}
 
-	return -ENODATA;
+	/* if nothing was found, return -ENODATA */
+	if (*new_index == -EINVAL)
+		return -ENODATA;
+	/*
+	 * If we don't have a current_index return this
+	 * newfound value. There is no hysterisis from out of range
+	 * to in range transition
+	 */
+	if (current_index == -EINVAL)
+		return 0;
+
+	/*
+	 * Check for hysteresis if it in the neighbourhood
+	 * of our current index.
+	 */
+	if (*new_index == current_index + 1) {
+		if (threshold < range[*new_index].low_threshold + hysteresis) {
+			/*
+			 * Stay in the current index, threshold is not higher
+			 * by hysteresis amount
+			 */
+			*new_index = current_index;
+			*val = range[current_index].value;
+		}
+	} else if (*new_index == current_index - 1) {
+		if (threshold > range[*new_index].high_threshold - hysteresis) {
+			/*
+			 * stay in the current index, threshold is not lower
+			 * by hysteresis amount
+			 */
+			*new_index = current_index;
+			*val = range[current_index].value;
+		}
+	}
+	return 0;
 }
 
 static int handle_step_chg_config(struct step_chg_info *chip)
 {
 	union power_supply_propval pval = {0, };
 	int rc = 0, fcc_ua = 0;
+	u64 elapsed_us;
+
+	elapsed_us = ktime_us_delta(ktime_get(), chip->step_last_update_time);
+	if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
+		goto reschedule;
 
 	rc = power_supply_get_property(chip->batt_psy,
 		POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, &pval);
@@ -119,7 +223,7 @@
 	if (!chip->step_chg_enable) {
 		if (chip->fcc_votable)
 			vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
-		return 0;
+		goto update_time;
 	}
 
 	rc = power_supply_get_property(chip->batt_psy,
@@ -130,48 +234,144 @@
 		return rc;
 	}
 
-	chip->fcc_votable = find_votable("FCC");
+	rc = get_val(step_chg_config.fcc_cfg, step_chg_config.hysteresis,
+			chip->step_index,
+			pval.intval,
+			&chip->step_index,
+			&fcc_ua);
+	if (rc < 0) {
+		/* remove the vote if no step-based fcc is found */
+		if (chip->fcc_votable)
+			vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
+		goto update_time;
+	}
+
+	if (!chip->fcc_votable)
+		chip->fcc_votable = find_votable("FCC");
 	if (!chip->fcc_votable)
 		return -EINVAL;
 
-	fcc_ua = get_fcc(pval.intval);
-	if (fcc_ua < 0) {
-		/* remove the vote if no step-based fcc is found */
-		vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
-		return 0;
-	}
-
 	vote(chip->fcc_votable, STEP_CHG_VOTER, true, fcc_ua);
 
 	pr_debug("%s = %d Step-FCC = %duA\n",
 		step_chg_config.prop_name, pval.intval, fcc_ua);
 
+update_time:
+	chip->step_last_update_time = ktime_get();
 	return 0;
+
+reschedule:
+	/* reschedule 1000uS after the remaining time */
+	return (STEP_CHG_HYSTERISIS_DELAY_US - elapsed_us + 1000);
 }
 
-#define STEP_CHG_HYSTERISIS_DELAY_US		5000000 /* 5 secs */
+static int handle_jeita(struct step_chg_info *chip)
+{
+	union power_supply_propval pval = {0, };
+	int rc = 0, fcc_ua = 0, fv_uv = 0;
+	u64 elapsed_us;
+
+	if (!chip->sw_jeita_enable) {
+		if (chip->fcc_votable)
+			vote(chip->fcc_votable, JEITA_VOTER, false, 0);
+		if (chip->fv_votable)
+			vote(chip->fv_votable, JEITA_VOTER, false, 0);
+		return 0;
+	}
+
+	elapsed_us = ktime_us_delta(ktime_get(), chip->jeita_last_update_time);
+	if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
+		goto reschedule;
+
+	rc = power_supply_get_property(chip->batt_psy,
+				jeita_fcc_config.psy_prop, &pval);
+	if (rc < 0) {
+		pr_err("Couldn't read %s property rc=%d\n",
+				step_chg_config.prop_name, rc);
+		return rc;
+	}
+
+	rc = get_val(jeita_fcc_config.fcc_cfg, jeita_fcc_config.hysteresis,
+			chip->jeita_fcc_index,
+			pval.intval,
+			&chip->jeita_fcc_index,
+			&fcc_ua);
+	if (rc < 0) {
+		/* remove the vote if no step-based fcc is found */
+		if (chip->fcc_votable)
+			vote(chip->fcc_votable, JEITA_VOTER, false, 0);
+		goto update_time;
+	}
+
+	if (!chip->fcc_votable)
+		chip->fcc_votable = find_votable("FCC");
+	if (!chip->fcc_votable)
+		/* changing FCC is a must */
+		return -EINVAL;
+
+	vote(chip->fcc_votable, JEITA_VOTER, true, fcc_ua);
+
+	rc = get_val(jeita_fv_config.fv_cfg, jeita_fv_config.hysteresis,
+			chip->jeita_fv_index,
+			pval.intval,
+			&chip->jeita_fv_index,
+			&fv_uv);
+	if (rc < 0) {
+		/* remove the vote if no step-based fcc is found */
+		if (chip->fv_votable)
+			vote(chip->fv_votable, JEITA_VOTER, false, 0);
+		goto update_time;
+	}
+
+	chip->fv_votable = find_votable("FV");
+	if (!chip->fv_votable)
+		goto update_time;
+
+	vote(chip->fv_votable, JEITA_VOTER, true, fv_uv);
+
+	pr_debug("%s = %d FCC = %duA FV = %duV\n",
+		step_chg_config.prop_name, pval.intval, fcc_ua, fv_uv);
+
+update_time:
+	chip->jeita_last_update_time = ktime_get();
+	return 0;
+
+reschedule:
+	/* reschedule 1000uS after the remaining time */
+	return (STEP_CHG_HYSTERISIS_DELAY_US - elapsed_us + 1000);
+}
+
 static void status_change_work(struct work_struct *work)
 {
 	struct step_chg_info *chip = container_of(work,
 			struct step_chg_info, status_change_work.work);
 	int rc = 0;
-	u64 elapsed_us;
-
-	elapsed_us = ktime_us_delta(ktime_get(), chip->last_update_time);
-	if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
-		goto release_ws;
+	int reschedule_us;
+	int reschedule_jeita_work_us = 0;
+	int reschedule_step_work_us = 0;
 
 	if (!is_batt_available(chip))
-		goto release_ws;
+		return;
+
+	/* skip elapsed_us debounce for handling battery temperature */
+	rc = handle_jeita(chip);
+	if (rc > 0)
+		reschedule_jeita_work_us = rc;
+	else if (rc < 0)
+		pr_err("Couldn't handle sw jeita rc = %d\n", rc);
 
 	rc = handle_step_chg_config(chip);
+	if (rc > 0)
+		reschedule_step_work_us = rc;
 	if (rc < 0)
-		goto release_ws;
+		pr_err("Couldn't handle step rc = %d\n", rc);
 
-	chip->last_update_time = ktime_get();
-
-release_ws:
-	__pm_relax(chip->step_chg_ws);
+	reschedule_us = min(reschedule_jeita_work_us, reschedule_step_work_us);
+	if (reschedule_us == 0)
+		__pm_relax(chip->step_chg_ws);
+	else
+		schedule_delayed_work(&chip->status_change_work,
+				usecs_to_jiffies(reschedule_us));
 }
 
 static int step_chg_notifier_call(struct notifier_block *nb,
@@ -205,7 +405,7 @@
 	return 0;
 }
 
-int qcom_step_chg_init(bool step_chg_enable)
+int qcom_step_chg_init(bool step_chg_enable, bool sw_jeita_enable)
 {
 	int rc;
 	struct step_chg_info *chip;
@@ -226,12 +426,34 @@
 	}
 
 	chip->step_chg_enable = step_chg_enable;
+	chip->sw_jeita_enable = sw_jeita_enable;
+
+	chip->step_index = -EINVAL;
+	chip->jeita_fcc_index = -EINVAL;
+	chip->jeita_fv_index = -EINVAL;
 
 	if (step_chg_enable && (!step_chg_config.psy_prop ||
 				!step_chg_config.prop_name)) {
 		/* fail if step-chg configuration is invalid */
 		pr_err("Step-chg configuration not defined - fail\n");
-		return -ENODATA;
+		rc = -ENODATA;
+		goto release_wakeup_source;
+	}
+
+	if (sw_jeita_enable && (!jeita_fcc_config.psy_prop ||
+				!jeita_fcc_config.prop_name)) {
+		/* fail if step-chg configuration is invalid */
+		pr_err("Jeita TEMP configuration not defined - fail\n");
+		rc = -ENODATA;
+		goto release_wakeup_source;
+	}
+
+	if (sw_jeita_enable && (!jeita_fv_config.psy_prop ||
+				!jeita_fv_config.prop_name)) {
+		/* fail if step-chg configuration is invalid */
+		pr_err("Jeita TEMP configuration not defined - fail\n");
+		rc = -ENODATA;
+		goto release_wakeup_source;
 	}
 
 	INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h
index 236877a..5bb2b99 100644
--- a/drivers/power/supply/qcom/step-chg-jeita.h
+++ b/drivers/power/supply/qcom/step-chg-jeita.h
@@ -12,6 +12,6 @@
 
 #ifndef __STEP_CHG_H__
 #define __STEP_CHG_H__
-int qcom_step_chg_init(bool step_chg_enable);
+int qcom_step_chg_init(bool step_chg_enable, bool sw_jeita_enable);
 void qcom_step_chg_deinit(void);
 #endif /* __STEP_CHG_H__ */
diff --git a/drivers/soc/qcom/eud.c b/drivers/soc/qcom/eud.c
index 92dbd48..51c08c6 100644
--- a/drivers/soc/qcom/eud.c
+++ b/drivers/soc/qcom/eud.c
@@ -70,6 +70,7 @@
 	struct extcon_dev		*extcon;
 	struct uart_port		port;
 	struct work_struct		eud_work;
+	struct power_supply		*batt_psy;
 };
 
 static const unsigned int eud_extcon_cable[] = {
@@ -176,17 +177,33 @@
 
 module_param_cb(enable, &eud_param_ops, &enable, 0644);
 
+static bool is_batt_available(struct eud_chip *chip)
+{
+	if (!chip->batt_psy)
+		chip->batt_psy = power_supply_get_by_name("battery");
+
+	if (!chip->batt_psy)
+		return false;
+
+	return true;
+}
+
 static void eud_event_notifier(struct work_struct *eud_work)
 {
 	struct eud_chip *chip = container_of(eud_work, struct eud_chip,
 					eud_work);
+	union power_supply_propval pval;
 
 	if (chip->int_status == EUD_INT_VBUS)
 		extcon_set_state_sync(chip->extcon, chip->extcon_id,
 					chip->usb_attach);
-	else if (chip->int_status == EUD_INT_CHGR)
-		extcon_set_state_sync(chip->extcon, chip->extcon_id,
-					chip->chgr_enable);
+	else if (chip->int_status == EUD_INT_CHGR) {
+		if (is_batt_available(chip)) {
+			pval.intval = !chip->chgr_enable;
+			power_supply_set_property(chip->batt_psy,
+				POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
+		}
+	}
 }
 
 static void usb_attach_detach(struct eud_chip *chip)
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_dbg.c b/drivers/soc/qcom/msm_bus/msm_bus_dbg.c
index 015edb3..df29233 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_dbg.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_dbg.c
@@ -38,6 +38,7 @@
 static struct dentry *clients;
 static struct dentry *dir;
 static DEFINE_MUTEX(msm_bus_dbg_fablist_lock);
+static DEFINE_RT_MUTEX(msm_bus_dbg_cllist_lock);
 struct msm_bus_dbg_state {
 	uint32_t cl;
 	uint8_t enable;
@@ -289,7 +290,9 @@
 	struct msm_bus_cldata *cldata = NULL;
 	const struct msm_bus_client_handle *handle = file->private_data;
 	int found = 0;
+	ssize_t ret;
 
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry(cldata, &cl_list, list) {
 		if ((cldata->clid == cl) ||
 			(cldata->handle && (cldata->handle == handle))) {
@@ -298,12 +301,17 @@
 		}
 	}
 
-	if (!found)
+	if (!found) {
+		rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 		return 0;
+	}
 
 	bsize = cldata->size;
-	return simple_read_from_buffer(buf, count, ppos,
+	ret = simple_read_from_buffer(buf, count, ppos,
 		cldata->buffer, bsize);
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
+
+	return ret;
 }
 
 static int client_data_open(struct inode *inode, struct file *file)
@@ -339,7 +347,9 @@
 		return -ENOMEM;
 	}
 	cldata->handle = pdata;
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_add_tail(&cldata->list, &cl_list);
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 	return 0;
 }
 
@@ -352,6 +362,7 @@
 	bool found = false;
 	char *buf = NULL;
 
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry(cldata, &cl_list, list) {
 		if (cldata->handle == pdata) {
 			found = true;
@@ -359,12 +370,15 @@
 		}
 	}
 
-	if (!found)
+	if (!found) {
+		rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 		return -ENOENT;
+	}
 
 	if (cldata->file == NULL) {
 		if (pdata->name == NULL) {
 			MSM_BUS_DBG("Client doesn't have a name\n");
+			rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 			return -EINVAL;
 		}
 		cldata->file = debugfs_create_file(pdata->name, S_IRUGO,
@@ -393,6 +407,7 @@
 	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu  ", ib);
 	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
 	cldata->size = i;
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 
 	trace_bus_update_request((int)ts.tv_sec, (int)ts.tv_nsec,
 		pdata->name, pdata->mas, pdata->slv, ab, ib);
@@ -404,6 +419,7 @@
 {
 	struct msm_bus_cldata *cldata = NULL;
 
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry(cldata, &cl_list, list) {
 		if (cldata->handle == pdata) {
 			debugfs_remove(cldata->file);
@@ -412,6 +428,7 @@
 			break;
 		}
 	}
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 }
 
 static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata,
@@ -429,7 +446,9 @@
 	cldata->clid = clid;
 	cldata->file = file;
 	cldata->size = 0;
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_add_tail(&cldata->list, &cl_list);
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 	return 0;
 }
 
@@ -437,13 +456,16 @@
 {
 	struct msm_bus_cldata *cldata = NULL;
 
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry(cldata, &cl_list, list) {
 		if (cldata->clid == clid) {
+			debugfs_remove(cldata->file);
 			list_del(&cldata->list);
 			kfree(cldata);
 			break;
 		}
 	}
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 }
 
 static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata,
@@ -455,6 +477,7 @@
 	struct timespec ts;
 	int found = 0;
 
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry(cldata, &cl_list, list) {
 		if (cldata->clid == clid) {
 			found = 1;
@@ -462,11 +485,14 @@
 		}
 	}
 
-	if (!found)
+	if (!found) {
+		rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 		return -ENOENT;
+	}
 
 	if (cldata->file == NULL) {
 		if (pdata->name == NULL) {
+			rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 			MSM_BUS_DBG("Client doesn't have a name\n");
 			return -EINVAL;
 		}
@@ -514,21 +540,11 @@
 
 	cldata->index = index;
 	cldata->size = i;
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
+
 	return i;
 }
 
-static int msm_bus_dbg_update_request(struct msm_bus_cldata *cldata, int index)
-{
-	int ret = 0;
-
-	if ((index < 0) || (index > cldata->pdata->num_usecases)) {
-		MSM_BUS_DBG("Invalid index!\n");
-		return -EINVAL;
-	}
-	ret = msm_bus_scale_client_update_request(cldata->clid, index);
-	return ret;
-}
-
 static ssize_t  msm_bus_dbg_update_request_write(struct file *file,
 	const char __user *ubuf, size_t cnt, loff_t *ppos)
 {
@@ -538,19 +554,26 @@
 	char *chid;
 	char *buf = kmalloc((sizeof(char) * (cnt + 1)), GFP_KERNEL);
 	int found = 0;
+	uint32_t clid;
+	ssize_t res = cnt;
 
 	if (!buf || IS_ERR(buf)) {
 		MSM_BUS_ERR("Memory allocation for buffer failed\n");
 		return -ENOMEM;
 	}
-	if (cnt == 0)
-		return 0;
-	if (copy_from_user(buf, ubuf, cnt))
-		return -EFAULT;
+	if (cnt == 0) {
+		res = 0;
+		goto out;
+	}
+	if (copy_from_user(buf, ubuf, cnt)) {
+		res = -EFAULT;
+		goto out;
+	}
 	buf[cnt] = '\0';
 	chid = buf;
 	MSM_BUS_DBG("buffer: %s\n size: %zu\n", buf, sizeof(ubuf));
 
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry(cldata, &cl_list, list) {
 		if (strnstr(chid, cldata->pdata->name, cnt)) {
 			found = 1;
@@ -559,23 +582,37 @@
 			if (chid) {
 				ret = kstrtoul(chid, 10, &index);
 				if (ret) {
-					MSM_BUS_DBG("Index conversion failed\n"
-							);
-					return -EFAULT;
+					MSM_BUS_DBG("Index conversion\n"
+						" failed\n");
+					rt_mutex_unlock(
+						&msm_bus_dbg_cllist_lock);
+					res = -EFAULT;
+					goto out;
 				}
 			} else {
-				MSM_BUS_DBG("Error parsing input.\n"
-						"Index not found\n");
+				MSM_BUS_DBG("Error parsing input. Index not\n"
+					" found\n");
 				found = 0;
 			}
+			if ((index < 0) ||
+					(index > cldata->pdata->num_usecases)) {
+				MSM_BUS_DBG("Invalid index!\n");
+				rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
+				res = -EINVAL;
+				goto out;
+			}
+			clid = cldata->clid;
 			break;
 		}
 	}
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 
 	if (found)
-		msm_bus_dbg_update_request(cldata, index);
+		msm_bus_scale_client_update_request(clid, index);
+
+out:
 	kfree(buf);
-	return cnt;
+	return res;
 }
 
 /**
@@ -598,8 +635,10 @@
 			break;
 		}
 	}
-	if (!found)
+	if (!found) {
+		mutex_unlock(&msm_bus_dbg_fablist_lock);
 		return -ENOENT;
+	}
 	bsize = fablist->size;
 	ret = simple_read_from_buffer(buf, count, ppos,
 		fablist->buffer, bsize);
@@ -689,8 +728,10 @@
 			break;
 		}
 	}
-	if (!found)
+	if (!found) {
+		mutex_unlock(&msm_bus_dbg_fablist_lock);
 		return -ENOENT;
+	}
 
 	if (fablist->file == NULL) {
 		MSM_BUS_DBG("Fabric dbg entry does not exist\n");
@@ -741,6 +782,8 @@
 		"\nDumping curent client votes to trace log\n");
 	if (*ppos)
 		goto exit_dump_clients_read;
+
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry(cldata, &cl_list, list) {
 		if (IS_ERR_OR_NULL(cldata->pdata))
 			continue;
@@ -756,6 +799,7 @@
 			cldata->pdata->active_only);
 		}
 	}
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 exit_dump_clients_read:
 	return simple_read_from_buffer(buf, count, ppos, msg, cnt);
 }
@@ -880,6 +924,7 @@
 		goto err;
 	}
 
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry(cldata, &cl_list, list) {
 		if (cldata->pdata) {
 			if (cldata->pdata->name == NULL) {
@@ -899,6 +944,7 @@
 							&client_data_fops);
 		}
 	}
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
 
 	if (debugfs_create_file("dump_clients", S_IRUGO | S_IWUSR,
 		clients, NULL, &msm_bus_dbg_dump_clients_fops) == NULL)
@@ -911,6 +957,7 @@
 		if (fablist->file == NULL) {
 			MSM_BUS_DBG("Cannot create files for commit data\n");
 			kfree(rules_buf);
+			mutex_unlock(&msm_bus_dbg_fablist_lock);
 			goto err;
 		}
 	}
@@ -930,10 +977,14 @@
 	struct msm_bus_cldata *cldata = NULL, *cldata_temp;
 
 	debugfs_remove_recursive(dir);
+
+	rt_mutex_lock(&msm_bus_dbg_cllist_lock);
 	list_for_each_entry_safe(cldata, cldata_temp, &cl_list, list) {
 		list_del(&cldata->list);
 		kfree(cldata);
 	}
+	rt_mutex_unlock(&msm_bus_dbg_cllist_lock);
+
 	mutex_lock(&msm_bus_dbg_fablist_lock);
 	list_for_each_entry_safe(fablist, fablist_temp, &fabdata_list, list) {
 		list_del(&fablist->list);
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 007b353..0e5ead0 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -595,6 +595,9 @@
 		cnt_vcd++;
 	}
 
+	if (!cnt_active)
+		goto exit_msm_bus_commit_data;
+
 	n_active = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
 	if (!n_active)
 		return -ENOMEM;
@@ -643,32 +646,35 @@
 			MSM_BUS_ERR("%s: error sending active/awake sets: %d\n",
 						__func__, ret);
 	}
-
-	ret = rpmh_write_passthru(cur_mbox, RPMH_WAKE_ONLY_STATE,
-						cmdlist_wake, n_wake);
-	if (ret)
-		MSM_BUS_ERR("%s: error sending wake sets: %d\n",
-						__func__, ret);
-
-	ret = rpmh_write_passthru(cur_mbox, RPMH_SLEEP_STATE,
-						cmdlist_sleep, n_sleep);
-	if (ret)
-		MSM_BUS_ERR("%s: error sending sleep sets: %d\n",
-						__func__, ret);
-
-	list_for_each_entry_safe(node, node_tmp, clist, link) {
-		bcm_clist_clean(node);
-		node->dirty = false;
-		list_del_init(&node->link);
+	if (cnt_wake) {
+		ret = rpmh_write_passthru(cur_mbox, RPMH_WAKE_ONLY_STATE,
+							cmdlist_wake, n_wake);
+		if (ret)
+			MSM_BUS_ERR("%s: error sending wake sets: %d\n",
+							__func__, ret);
+	}
+	if (cnt_sleep) {
+		ret = rpmh_write_passthru(cur_mbox, RPMH_SLEEP_STATE,
+							cmdlist_sleep, n_sleep);
+		if (ret)
+			MSM_BUS_ERR("%s: error sending sleep sets: %d\n",
+							__func__, ret);
 	}
 
-	cur_rsc = NULL;
 	kfree(cmdlist_active);
 	kfree(cmdlist_wake);
 	kfree(cmdlist_sleep);
 	kfree(n_active);
 	kfree(n_wake);
 	kfree(n_sleep);
+
+exit_msm_bus_commit_data:
+	list_for_each_entry_safe(node, node_tmp, clist, link) {
+		bcm_clist_clean(node);
+		node->dirty = false;
+		list_del_init(&node->link);
+	}
+	cur_rsc = NULL;
 	return ret;
 }
 
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 1b41269..8580484 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -207,6 +207,7 @@
 			dev_err(rc->dev,
 				"RPMH waiting for interrupt from AOSS\n");
 			mbox_chan_debug(rc->chan);
+			BUG();
 		} else {
 			dev_err(rc->dev,
 			"RPMH response timeout (%d) addr=0x%x,data=0x%x\n",
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 37766d29..6acb731 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -12,13 +12,17 @@
  *
  */
 #include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
+#include <linux/ipc_logging.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
 #include <linux/qcom-geni-se.h>
+#include <linux/msm_gpi.h>
 #include <linux/spi/spi.h>
 
 #define SPI_NUM_CHIPSELECT	(4)
@@ -79,6 +83,36 @@
 #define POST_CMD_DELAY		BIT(4)
 
 #define SPI_CORE2X_VOTE		(10000)
+/* GSI CONFIG0 TRE Params */
+/* Flags bit fields */
+#define GSI_LOOPBACK_EN		(BIT(0))
+#define GSI_CS_TOGGLE		(BIT(3))
+#define GSI_CPHA		(BIT(4))
+#define GSI_CPOL		(BIT(5))
+
+#define MAX_TX_SG		(3)
+#define NUM_SPI_XFER		(8)
+
+struct gsi_desc_cb {
+	struct spi_master *spi;
+	struct spi_transfer *xfer;
+};
+
+struct spi_geni_gsi {
+	struct msm_gpi_tre config0_tre;
+	struct msm_gpi_tre go_tre;
+	struct msm_gpi_tre tx_dma_tre;
+	struct msm_gpi_tre rx_dma_tre;
+	struct scatterlist tx_sg[MAX_TX_SG];
+	struct scatterlist rx_sg;
+	dma_cookie_t tx_cookie;
+	dma_cookie_t rx_cookie;
+	struct msm_gpi_dma_async_tx_cb_param tx_cb_param;
+	struct msm_gpi_dma_async_tx_cb_param rx_cb_param;
+	struct dma_async_tx_descriptor *tx_desc;
+	struct dma_async_tx_descriptor *rx_desc;
+	struct gsi_desc_cb desc_cb;
+};
 
 struct spi_geni_master {
 	struct se_geni_rsc spi_rsc;
@@ -100,6 +134,19 @@
 	struct completion xfer_done;
 	struct device *wrapper_dev;
 	int oversampling;
+	struct spi_geni_gsi *gsi;
+	struct dma_chan *tx;
+	struct dma_chan *rx;
+	struct msm_gpi_ctrl tx_event;
+	struct msm_gpi_ctrl rx_event;
+	struct completion tx_cb;
+	struct completion rx_cb;
+	bool qn_err;
+	int cur_xfer_mode;
+	int num_tx_eot;
+	int num_rx_eot;
+	int num_xfers;
+	void *ipc;
 };
 
 static struct spi_master *get_spi_master(struct device *dev)
@@ -110,76 +157,68 @@
 	return spi;
 }
 
-static int do_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas)
+static int get_spi_clk_cfg(u32 speed_hz, struct spi_geni_master *mas,
+			int *clk_idx, int *clk_div)
 {
 	unsigned long sclk_freq;
-	int div = 0;
-	int idx;
 	struct se_geni_rsc *rsc = &mas->spi_rsc;
-	u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
-	u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
-	int ret;
-
-	clk_sel &= ~CLK_SEL_MSK;
-	m_clk_cfg &= ~CLK_DIV_MSK;
+	int ret = 0;
 
 	ret = geni_se_clk_freq_match(&mas->spi_rsc,
-					(speed_hz * mas->oversampling), &idx,
-					&sclk_freq, true);
+				(speed_hz * mas->oversampling), clk_idx,
+				&sclk_freq, true);
 	if (ret) {
 		dev_err(mas->dev, "%s: Failed(%d) to find src clk for 0x%x\n",
 						__func__, ret, speed_hz);
 		return ret;
 	}
 
-	div = ((sclk_freq / mas->oversampling) / speed_hz);
-	if (!div) {
+	*clk_div = ((sclk_freq / mas->oversampling) / speed_hz);
+	if (!(*clk_div)) {
 		dev_err(mas->dev, "%s:Err:sclk:%lu oversampling:%d speed:%u\n",
 			__func__, sclk_freq, mas->oversampling, speed_hz);
 		return -EINVAL;
 	}
 
 	dev_dbg(mas->dev, "%s: req %u sclk %lu, idx %d, div %d\n", __func__,
-						speed_hz, sclk_freq, idx, div);
-	clk_sel |= (idx & CLK_SEL_MSK);
-	m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
+				speed_hz, sclk_freq, *clk_idx, *clk_div);
 	ret = clk_set_rate(rsc->se_clk, sclk_freq);
-	if (ret) {
+	if (ret)
 		dev_err(mas->dev, "%s: clk_set_rate failed %d\n",
 							__func__, ret);
-		return ret;
-	}
-
-	geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
-	geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
-	return 0;
+	return ret;
 }
 
 static void spi_setup_word_len(struct spi_geni_master *mas, u32 mode,
 						int bits_per_word)
 {
-	int pack_words = mas->tx_fifo_width / bits_per_word;
+	int pack_words = 0;
 	bool msb_first = (mode & SPI_LSB_FIRST) ? false : true;
 	u32 word_len = geni_read_reg(mas->base, SE_SPI_WORD_LEN);
 
+	if (!(mas->tx_fifo_width % bits_per_word))
+		pack_words = mas->tx_fifo_width / bits_per_word;
 	word_len &= ~WORD_LEN_MSK;
 	word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK);
 	se_config_packing(mas->base, bits_per_word, pack_words, msb_first);
 	geni_write_reg(word_len, mas->base, SE_SPI_WORD_LEN);
 }
 
-static int spi_geni_prepare_message(struct spi_master *spi_mas,
-					struct spi_message *spi_msg)
+static int setup_fifo_params(struct spi_device *spi_slv,
+					struct spi_master *spi)
 {
-	struct spi_device *spi_slv = spi_msg->spi;
-	struct spi_geni_master *mas = spi_master_get_devdata(spi_mas);
+	struct spi_geni_master *mas = spi_master_get_devdata(spi);
 	u16 mode = spi_slv->mode;
 	u32 loopback_cfg = geni_read_reg(mas->base, SE_SPI_LOOPBACK);
 	u32 cpol = geni_read_reg(mas->base, SE_SPI_CPOL);
 	u32 cpha = geni_read_reg(mas->base, SE_SPI_CPHA);
 	u32 demux_sel = 0;
 	u32 demux_output_inv = 0;
+	u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
+	u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
 	int ret = 0;
+	int idx;
+	int div;
 
 	loopback_cfg &= ~LOOPBACK_MSK;
 	cpol &= ~CPOL;
@@ -201,21 +240,434 @@
 	mas->cur_speed_hz = spi_slv->max_speed_hz;
 	mas->cur_word_len = spi_slv->bits_per_word;
 
-	ret = do_spi_clk_cfg(mas->cur_speed_hz, mas);
+	ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
 	if (ret) {
-		dev_err(&spi_mas->dev, "Err setting clks ret(%d) for %d\n",
+		dev_err(mas->dev, "Err setting clks ret(%d) for %d\n",
 							ret, mas->cur_speed_hz);
-		goto prepare_message_exit;
+		goto setup_fifo_params_exit;
 	}
+
+	clk_sel |= (idx & CLK_SEL_MSK);
+	m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
 	spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word);
 	geni_write_reg(loopback_cfg, mas->base, SE_SPI_LOOPBACK);
 	geni_write_reg(demux_sel, mas->base, SE_SPI_DEMUX_SEL);
 	geni_write_reg(cpha, mas->base, SE_SPI_CPHA);
 	geni_write_reg(cpol, mas->base, SE_SPI_CPOL);
 	geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV);
+	geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
+	geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
 	/* Ensure message level attributes are written before returning */
 	mb();
-prepare_message_exit:
+setup_fifo_params_exit:
+	return ret;
+}
+
+
+static int select_xfer_mode(struct spi_master *spi,
+				struct spi_message *spi_msg)
+{
+	struct spi_geni_master *mas = spi_master_get_devdata(spi);
+	int mode = FIFO_MODE;
+	int fifo_disable = (geni_read_reg(mas->base, GENI_IF_FIFO_DISABLE_RO) &
+							FIFO_IF_DISABLE);
+	bool dma_chan_valid =
+		!(IS_ERR_OR_NULL(mas->tx) || IS_ERR_OR_NULL(mas->rx));
+
+	/*
+	 * If FIFO Interface is disabled and there are no DMA channels then we
+	 * can't do this transfer.
+	 * If FIFO interface is disabled, we can do GSI only,
+	 * else pick FIFO mode.
+	 */
+	if (fifo_disable && !dma_chan_valid)
+		mode = -EINVAL;
+	else if (fifo_disable)
+		mode = GSI_DMA;
+	else
+		mode = FIFO_MODE;
+	return mode;
+}
+
+static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer,
+				struct spi_geni_master *mas, u16 mode)
+{
+	struct msm_gpi_tre *c0_tre = &mas->gsi[mas->num_xfers].config0_tre;
+	u8 flags = 0;
+	u8 word_len = 0;
+	u8 pack = 0;
+	int div = 0;
+	int idx = 0;
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(c0_tre))
+		return c0_tre;
+
+	if (mode & SPI_LOOP)
+		flags |= GSI_LOOPBACK_EN;
+
+	if (mode & SPI_CPOL)
+		flags |= GSI_CPOL;
+
+	if (mode & SPI_CPHA)
+		flags |= GSI_CPHA;
+
+	if (xfer->cs_change)
+		flags |= GSI_CS_TOGGLE;
+
+	word_len = xfer->bits_per_word - MIN_WORD_LEN;
+	if (mas->tx_fifo_width % xfer->bits_per_word)
+		pack = 0;
+	else
+		pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
+	ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
+	if (ret) {
+		dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret);
+		return ERR_PTR(ret);
+	}
+	c0_tre->dword[0] = MSM_GPI_SPI_CONFIG0_TRE_DWORD0(pack, flags,
+								word_len);
+	c0_tre->dword[1] = MSM_GPI_SPI_CONFIG0_TRE_DWORD1(0, 0, 0);
+	c0_tre->dword[2] = MSM_GPI_SPI_CONFIG0_TRE_DWORD2(idx, div);
+	c0_tre->dword[3] = MSM_GPI_SPI_CONFIG0_TRE_DWORD3(0, 0, 0, 1);
+	GENI_SE_DBG(mas->ipc, false, mas->dev,
+		"%s: flags 0x%x word %d pack %d idx %d div %d\n",
+		__func__, flags, word_len, pack, idx, div);
+	return c0_tre;
+}
+
+static struct msm_gpi_tre *setup_go_tre(int cmd, int cs, int rx_len, int flags,
+				struct spi_geni_master *mas)
+{
+	struct msm_gpi_tre *go_tre = &mas->gsi[mas->num_xfers].go_tre;
+	int chain;
+	int eot;
+	int eob;
+
+	if (IS_ERR_OR_NULL(go_tre))
+		return go_tre;
+
+	go_tre->dword[0] = MSM_GPI_SPI_GO_TRE_DWORD0(flags, cs, cmd);
+	go_tre->dword[1] = MSM_GPI_SPI_GO_TRE_DWORD1;
+	go_tre->dword[2] = MSM_GPI_SPI_GO_TRE_DWORD2(rx_len);
+	if (cmd == SPI_RX_ONLY) {
+		eot = 0;
+		chain = 0;
+		eob = 1;
+	} else {
+		eot = 0;
+		chain = 1;
+		eob = 0;
+	}
+	go_tre->dword[3] = MSM_GPI_SPI_GO_TRE_DWORD3(0, eot, eob, chain);
+	GENI_SE_DBG(mas->ipc, false, mas->dev,
+		"%s: rx len %d flags 0x%x cs %d cmd %d eot %d eob %d chain %d\n",
+		__func__, rx_len, flags, cs, cmd, eot, eob, chain);
+	return go_tre;
+}
+
+static struct msm_gpi_tre *setup_dma_tre(struct msm_gpi_tre *tre,
+					dma_addr_t buf, u32 len,
+					struct spi_geni_master *mas,
+					bool is_tx)
+{
+	if (IS_ERR_OR_NULL(tre))
+		return tre;
+
+	tre->dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(buf);
+	tre->dword[1] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(buf);
+	tre->dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(len);
+	tre->dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, is_tx, 0, 0);
+	return tre;
+}
+
+static void spi_gsi_ch_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb,
+				void *ptr)
+{
+	struct spi_master *spi = ptr;
+	struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+	switch (cb->cb_event) {
+	case MSM_GPI_QUP_NOTIFY:
+	case MSM_GPI_QUP_MAX_EVENT:
+		GENI_SE_DBG(mas->ipc, false, mas->dev,
+				"%s:cb_ev%d status%llu ts%llu count%llu\n",
+				__func__, cb->cb_event, cb->status,
+				cb->timestamp, cb->count);
+		break;
+	case MSM_GPI_QUP_ERROR:
+	case MSM_GPI_QUP_CH_ERROR:
+	case MSM_GPI_QUP_FW_ERROR:
+	case MSM_GPI_QUP_PENDING_EVENT:
+	case MSM_GPI_QUP_EOT_DESC_MISMATCH:
+	case MSM_GPI_QUP_SW_ERROR:
+		GENI_SE_ERR(mas->ipc, true, mas->dev,
+				"%s: cb_ev %d status %llu ts %llu count %llu\n",
+				__func__, cb->cb_event, cb->status,
+				cb->timestamp, cb->count);
+		GENI_SE_ERR(mas->ipc, true, mas->dev,
+				"err.routine %u, err.type %u, err.code %u\n",
+				cb->error_log.routine,
+				cb->error_log.type,
+				cb->error_log.error_code);
+		mas->qn_err = true;
+		complete_all(&mas->tx_cb);
+		complete_all(&mas->rx_cb);
+
+		break;
+	};
+}
+
+static void spi_gsi_rx_callback(void *cb)
+{
+	struct msm_gpi_dma_async_tx_cb_param *cb_param =
+			(struct msm_gpi_dma_async_tx_cb_param *)cb;
+	struct gsi_desc_cb *desc_cb = (struct gsi_desc_cb *)cb_param->userdata;
+	struct spi_master *spi = desc_cb->spi;
+	struct spi_transfer *xfer = desc_cb->xfer;
+	struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+	if (xfer->rx_buf) {
+		if (cb_param->status == MSM_GPI_TCE_UNEXP_ERR) {
+			GENI_SE_ERR(mas->ipc, true, mas->dev,
+			"%s: Unexpected GSI CB error\n", __func__);
+			return;
+		}
+		if (cb_param->length == xfer->len) {
+			GENI_SE_DBG(mas->ipc, false, mas->dev,
+			"%s\n", __func__);
+			complete(&mas->rx_cb);
+		} else {
+			GENI_SE_ERR(mas->ipc, true, mas->dev,
+			"%s: Length mismatch. Expected %d Callback %d\n",
+			__func__, xfer->len, cb_param->length);
+		}
+	}
+}
+
+static void spi_gsi_tx_callback(void *cb)
+{
+	struct msm_gpi_dma_async_tx_cb_param *cb_param = cb;
+	struct gsi_desc_cb *desc_cb = (struct gsi_desc_cb *)cb_param->userdata;
+	struct spi_master *spi = desc_cb->spi;
+	struct spi_transfer *xfer = desc_cb->xfer;
+	struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+	if (xfer->tx_buf) {
+		if (cb_param->status == MSM_GPI_TCE_UNEXP_ERR) {
+			GENI_SE_ERR(mas->ipc, true, mas->dev,
+			"%s: Unexpected GSI CB error\n", __func__);
+			return;
+		}
+		if (cb_param->length == xfer->len) {
+			GENI_SE_DBG(mas->ipc, false, mas->dev,
+			"%s\n", __func__);
+			complete(&mas->tx_cb);
+		} else {
+			GENI_SE_ERR(mas->ipc, true, mas->dev,
+			"%s: Length mismatch. Expected %d Callback %d\n",
+			__func__, xfer->len, cb_param->length);
+		}
+	}
+}
+
+static int setup_gsi_xfer(struct spi_transfer *xfer,
+				struct spi_geni_master *mas,
+				struct spi_device *spi_slv,
+				struct spi_master *spi)
+{
+	int ret = 0;
+	struct msm_gpi_tre *c0_tre = NULL;
+	struct msm_gpi_tre *go_tre = NULL;
+	struct msm_gpi_tre *tx_tre = NULL;
+	struct msm_gpi_tre *rx_tre = NULL;
+	struct scatterlist *xfer_tx_sg = mas->gsi[mas->num_xfers].tx_sg;
+	struct scatterlist *xfer_rx_sg = &mas->gsi[mas->num_xfers].rx_sg;
+	int rx_nent = 0;
+	int tx_nent = 0;
+	u8 cmd = 0;
+	u8 cs = 0;
+	u32 rx_len = 0;
+	int go_flags = 0;
+	unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+
+	if ((xfer->bits_per_word != mas->cur_word_len) ||
+		(xfer->speed_hz != mas->cur_speed_hz)) {
+		mas->cur_word_len = xfer->bits_per_word;
+		mas->cur_speed_hz = xfer->speed_hz;
+		tx_nent++;
+		c0_tre = setup_config0_tre(xfer, mas, spi_slv->mode);
+		if (IS_ERR_OR_NULL(c0_tre)) {
+			dev_err(mas->dev, "%s:Err setting c0tre:%d\n",
+							__func__, ret);
+			return PTR_ERR(c0_tre);
+		}
+	}
+
+	if (xfer->tx_buf && xfer->rx_buf) {
+		cmd = SPI_FULL_DUPLEX;
+		tx_nent += 2;
+		rx_nent++;
+		rx_len = ((xfer->len << 3) / mas->cur_word_len);
+	} else if (xfer->tx_buf) {
+		cmd = SPI_TX_ONLY;
+		tx_nent += 2;
+	} else if (xfer->rx_buf) {
+		cmd = SPI_RX_ONLY;
+		tx_nent++;
+		rx_nent++;
+		rx_len = ((xfer->len << 3) / mas->cur_word_len);
+	}
+
+	cs |= spi_slv->chip_select;
+	if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
+		go_flags |= FRAGMENTATION;
+	go_tre = setup_go_tre(cmd, cs, rx_len, go_flags, mas);
+
+	sg_init_table(xfer_tx_sg, tx_nent);
+	if (rx_nent)
+		sg_init_table(xfer_rx_sg, rx_nent);
+
+	if (c0_tre)
+		sg_set_buf(xfer_tx_sg++, c0_tre, sizeof(*c0_tre));
+
+	sg_set_buf(xfer_tx_sg++, go_tre, sizeof(*go_tre));
+	mas->gsi[mas->num_xfers].desc_cb.spi = spi;
+	mas->gsi[mas->num_xfers].desc_cb.xfer = xfer;
+	if (cmd & SPI_RX_ONLY) {
+		rx_tre = &mas->gsi[mas->num_xfers].rx_dma_tre;
+		rx_tre = setup_dma_tre(rx_tre, xfer->rx_dma, xfer->len, mas, 0);
+		if (IS_ERR_OR_NULL(rx_tre)) {
+			dev_err(mas->dev, "Err setting up rx tre\n");
+			return PTR_ERR(rx_tre);
+		}
+		sg_set_buf(xfer_rx_sg, rx_tre, sizeof(*rx_tre));
+		mas->gsi[mas->num_xfers].rx_desc =
+			dmaengine_prep_slave_sg(mas->rx,
+				&mas->gsi[mas->num_xfers].rx_sg, rx_nent,
+						DMA_DEV_TO_MEM, flags);
+		if (IS_ERR_OR_NULL(mas->gsi[mas->num_xfers].rx_desc)) {
+			dev_err(mas->dev, "Err setting up rx desc\n");
+			return -EIO;
+		}
+		mas->gsi[mas->num_xfers].rx_desc->callback =
+					spi_gsi_rx_callback;
+		mas->gsi[mas->num_xfers].rx_desc->callback_param =
+					&mas->gsi[mas->num_xfers].rx_cb_param;
+		mas->gsi[mas->num_xfers].rx_cb_param.userdata =
+					&mas->gsi[mas->num_xfers].desc_cb;
+		mas->num_rx_eot++;
+	}
+
+	if (cmd & SPI_TX_ONLY) {
+		tx_tre = &mas->gsi[mas->num_xfers].tx_dma_tre;
+		tx_tre = setup_dma_tre(tx_tre, xfer->tx_dma, xfer->len, mas, 1);
+		if (IS_ERR_OR_NULL(tx_tre)) {
+			dev_err(mas->dev, "Err setting up tx tre\n");
+			return PTR_ERR(tx_tre);
+		}
+		sg_set_buf(xfer_tx_sg++, tx_tre, sizeof(*tx_tre));
+		mas->num_tx_eot++;
+	}
+	mas->gsi[mas->num_xfers].tx_desc = dmaengine_prep_slave_sg(mas->tx,
+					mas->gsi[mas->num_xfers].tx_sg, tx_nent,
+					DMA_MEM_TO_DEV, flags);
+	if (IS_ERR_OR_NULL(mas->gsi[mas->num_xfers].tx_desc)) {
+		dev_err(mas->dev, "Err setting up tx desc\n");
+		return -EIO;
+	}
+	mas->gsi[mas->num_xfers].tx_desc->callback = spi_gsi_tx_callback;
+	mas->gsi[mas->num_xfers].tx_desc->callback_param =
+					&mas->gsi[mas->num_xfers].tx_cb_param;
+	mas->gsi[mas->num_xfers].tx_cb_param.userdata =
+					&mas->gsi[mas->num_xfers].desc_cb;
+	mas->gsi[mas->num_xfers].tx_cookie =
+			dmaengine_submit(mas->gsi[mas->num_xfers].tx_desc);
+	if (mas->num_rx_eot)
+		mas->gsi[mas->num_xfers].rx_cookie =
+			dmaengine_submit(mas->gsi[mas->num_xfers].rx_desc);
+	dma_async_issue_pending(mas->tx);
+	if (mas->num_rx_eot)
+		dma_async_issue_pending(mas->rx);
+	mas->num_xfers++;
+	return ret;
+}
+
+static int spi_geni_map_buf(struct spi_geni_master *mas,
+				struct spi_message *msg)
+{
+	struct spi_transfer *xfer;
+	struct device *gsi_dev = mas->dev;
+
+	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		if (xfer->rx_buf) {
+			xfer->rx_dma = dma_map_single(gsi_dev, xfer->rx_buf,
+						xfer->len, DMA_FROM_DEVICE);
+			if (dma_mapping_error(mas->dev, xfer->rx_dma)) {
+				dev_err(mas->dev, "Err mapping buf\n");
+				return -ENOMEM;
+			}
+		}
+
+		if (xfer->tx_buf) {
+			xfer->tx_dma = dma_map_single(gsi_dev,
+				(void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE);
+			if (dma_mapping_error(gsi_dev, xfer->tx_dma)) {
+				dev_err(mas->dev, "Err mapping buf\n");
+				dma_unmap_single(gsi_dev, xfer->rx_dma,
+						xfer->len, DMA_FROM_DEVICE);
+				return -ENOMEM;
+			}
+		}
+	};
+
+	return 0;
+}
+
+static void spi_geni_unmap_buf(struct spi_geni_master *mas,
+				struct spi_message *msg)
+{
+	struct spi_transfer *xfer;
+	struct device *gsi_dev = mas->dev;
+
+	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		if (xfer->rx_buf)
+			dma_unmap_single(gsi_dev, xfer->rx_dma,
+						xfer->len, DMA_FROM_DEVICE);
+		if (xfer->tx_buf)
+			dma_unmap_single(gsi_dev, xfer->tx_dma,
+						xfer->len, DMA_TO_DEVICE);
+	};
+}
+
+static int spi_geni_prepare_message(struct spi_master *spi,
+					struct spi_message *spi_msg)
+{
+	int ret = 0;
+	struct spi_geni_master *mas = spi_master_get_devdata(spi);
+
+	mas->cur_xfer_mode = select_xfer_mode(spi, spi_msg);
+
+	if (mas->cur_xfer_mode == FIFO_MODE) {
+		geni_se_select_mode(mas->base, FIFO_MODE);
+		reinit_completion(&mas->xfer_done);
+		setup_fifo_params(spi_msg->spi, spi);
+	} else if (mas->cur_xfer_mode == GSI_DMA) {
+		mas->num_tx_eot = 0;
+		mas->num_rx_eot = 0;
+		mas->num_xfers = 0;
+		reinit_completion(&mas->tx_cb);
+		reinit_completion(&mas->rx_cb);
+		memset(mas->gsi, 0,
+				(sizeof(struct spi_geni_gsi) * NUM_SPI_XFER));
+		geni_se_select_mode(mas->base, GSI_DMA);
+		dmaengine_resume(mas->tx);
+		ret = spi_geni_map_buf(mas, spi_msg);
+	} else {
+		dev_err(mas->dev, "%s: Couldn't select mode %d", __func__,
+							mas->cur_xfer_mode);
+		ret = -EINVAL;
+	}
 	return ret;
 }
 
@@ -226,6 +678,10 @@
 
 	mas->cur_speed_hz = 0;
 	mas->cur_word_len = 0;
+	if (mas->cur_xfer_mode == GSI_DMA) {
+		dmaengine_pause(mas->tx);
+		spi_geni_unmap_buf(mas, spi_msg);
+	}
 	return 0;
 }
 
@@ -255,14 +711,64 @@
 			return -ENXIO;
 		}
 		geni_se_init(mas->base, 0x0, (mas->tx_fifo_depth - 2));
-		geni_se_select_mode(mas->base, FIFO_MODE);
 		mas->tx_fifo_depth = get_tx_fifo_depth(mas->base);
 		mas->rx_fifo_depth = get_rx_fifo_depth(mas->base);
 		mas->tx_fifo_width = get_tx_fifo_width(mas->base);
 		mas->oversampling = 1;
 		/* Transmit an entire FIFO worth of data per IRQ */
 		mas->tx_wm = 1;
-		dev_dbg(mas->dev, "tx_fifo %d rx_fifo %d tx_width %d\n",
+
+		mas->tx = dma_request_slave_channel(mas->dev, "tx");
+		if (IS_ERR_OR_NULL(mas->tx)) {
+			dev_info(mas->dev, "Failed to get tx DMA ch %ld",
+							PTR_ERR(mas->tx));
+		} else {
+			mas->rx = dma_request_slave_channel(mas->dev, "rx");
+			if (IS_ERR_OR_NULL(mas->rx)) {
+				dev_info(mas->dev, "Failed to get rx DMA ch %ld",
+							PTR_ERR(mas->rx));
+				dma_release_channel(mas->tx);
+			}
+			mas->gsi = devm_kzalloc(mas->dev,
+				(sizeof(struct spi_geni_gsi) * NUM_SPI_XFER),
+				GFP_KERNEL);
+			if (IS_ERR_OR_NULL(mas->gsi)) {
+				dev_err(mas->dev, "Failed to get GSI mem\n");
+				dma_release_channel(mas->tx);
+				dma_release_channel(mas->rx);
+				mas->tx = NULL;
+				mas->rx = NULL;
+				goto setup_ipc;
+			}
+			mas->tx_event.init.callback = spi_gsi_ch_cb;
+			mas->tx_event.init.cb_param = spi;
+			mas->tx_event.cmd = MSM_GPI_INIT;
+			mas->tx->private = &mas->tx_event;
+			mas->rx_event.init.callback = spi_gsi_ch_cb;
+			mas->rx_event.init.cb_param = spi;
+			mas->rx_event.cmd = MSM_GPI_INIT;
+			mas->rx->private = &mas->rx_event;
+			if (dmaengine_slave_config(mas->tx, NULL)) {
+				dev_err(mas->dev, "Failed to Config Tx\n");
+				dma_release_channel(mas->tx);
+				dma_release_channel(mas->rx);
+				mas->tx = NULL;
+				mas->rx = NULL;
+				goto setup_ipc;
+			}
+			if (dmaengine_slave_config(mas->rx, NULL)) {
+				dev_err(mas->dev, "Failed to Config Rx\n");
+				dma_release_channel(mas->tx);
+				dma_release_channel(mas->rx);
+				mas->tx = NULL;
+				mas->rx = NULL;
+				goto setup_ipc;
+			}
+
+		}
+setup_ipc:
+		mas->ipc = ipc_log_context_create(4, dev_name(mas->dev), 0);
+		dev_info(mas->dev, "tx_fifo %d rx_fifo %d tx_width %d\n",
 			mas->tx_fifo_depth, mas->rx_fifo_depth,
 			mas->tx_fifo_width);
 		mas->setup = true;
@@ -272,10 +778,11 @@
 			dev_err(mas->dev, "%s:Err getting HW version %d\n",
 							__func__, hw_ver);
 		else {
-			dev_dbg(mas->dev, "%s:Major:%d Minor:%d step:%d\n",
-				__func__, major, minor, step);
 			if ((major == 1) && (minor == 0))
 				mas->oversampling = 2;
+			GENI_SE_DBG(mas->ipc, false, mas->dev,
+				"%s:Major:%d Minor:%d step:%dos%d\n",
+			__func__, major, minor, step, mas->oversampling);
 		}
 	}
 exit_prepare_transfer_hardware:
@@ -304,6 +811,29 @@
 		mas->cur_word_len = xfer->bits_per_word;
 	}
 
+	/* Speed and bits per word can be overridden per transfer */
+	if (xfer->speed_hz != mas->cur_speed_hz) {
+		int ret = 0;
+		u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
+		u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
+		int idx = 0;
+		int div = 0;
+
+		ret = get_spi_clk_cfg(xfer->speed_hz, mas, &idx, &div);
+		if (ret) {
+			dev_err(mas->dev, "%s:Err setting clks:%d\n",
+								__func__, ret);
+			return;
+		}
+		mas->cur_speed_hz = xfer->speed_hz;
+		clk_sel |= (idx & CLK_SEL_MSK);
+		m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
+		geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
+		geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
+	}
+
+	mas->tx_rem_bytes = 0;
+	mas->rx_rem_bytes = 0;
 	if (xfer->tx_buf && xfer->rx_buf)
 		m_cmd = SPI_FULL_DUPLEX;
 	else if (xfer->tx_buf)
@@ -314,7 +844,7 @@
 	spi_tx_cfg &= ~CS_TOGGLE;
 	if (xfer->cs_change)
 		spi_tx_cfg |= CS_TOGGLE;
-	trans_len = ((xfer->len / (mas->cur_word_len >> 3)) & TRANS_LEN_MSK);
+	trans_len = ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
 	if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
 		m_param |= FRAGMENTATION;
 
@@ -330,7 +860,8 @@
 	}
 	geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
 	geni_setup_m_cmd(mas->base, m_cmd, m_param);
-	geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
+	if (m_cmd & SPI_TX_ONLY)
+		geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
 	/* Ensure all writes are done before the WM interrupt */
 	mb();
 }
@@ -338,17 +869,7 @@
 static void handle_fifo_timeout(struct spi_geni_master *mas)
 {
 	unsigned long timeout;
-	u32 tx_trans_len = geni_read_reg(mas->base, SE_SPI_TX_TRANS_LEN);
-	u32 rx_trans_len = geni_read_reg(mas->base, SE_SPI_RX_TRANS_LEN);
-	u32 spi_tx_cfg = geni_read_reg(mas->base, SE_SPI_TRANS_CFG);
-	u32 m_cmd = geni_read_reg(mas->base, SE_GENI_M_CMD0);
 
-	/* Timed-out on a FIFO xfer, print relevant reg info. */
-	dev_err(mas->dev, "tx_rem_bytes %d rx_rem_bytes %d\n",
-			mas->tx_rem_bytes, mas->rx_rem_bytes);
-	dev_err(mas->dev, "tx_trans_len %d rx_trans_len %d\n", tx_trans_len,
-								rx_trans_len);
-	dev_err(mas->dev, "spi_tx_cfg 0x%x m_cmd 0x%x\n", spi_tx_cfg, m_cmd);
 	reinit_completion(&mas->xfer_done);
 	geni_cancel_m_cmd(mas->base);
 	/* Ensure cmd cancel is written */
@@ -380,30 +901,64 @@
 		return -EINVAL;
 	}
 
-	reinit_completion(&mas->xfer_done);
-	/* Speed and bits per word can be overridden per transfer */
-	if (xfer->speed_hz != mas->cur_speed_hz) {
-		mas->cur_speed_hz = xfer->speed_hz;
-		ret = do_spi_clk_cfg(mas->cur_speed_hz, mas);
-		if (ret) {
-			dev_err(mas->dev, "%s:Err setting clks:%d\n",
-								__func__, ret);
-			goto geni_transfer_one_exit;
-		}
-	}
-
-	setup_fifo_xfer(xfer, mas, slv->mode, spi);
-	timeout = wait_for_completion_timeout(&mas->xfer_done,
+	if (mas->cur_xfer_mode == FIFO_MODE) {
+		setup_fifo_xfer(xfer, mas, slv->mode, spi);
+		timeout = wait_for_completion_timeout(&mas->xfer_done,
 					msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
-	if (!timeout) {
-		dev_err(mas->dev, "Xfer[len %d tx %p rx %p n %d] timed out.\n",
+		if (!timeout) {
+			GENI_SE_ERR(mas->ipc, true, mas->dev,
+				"Xfer[len %d tx %pK rx %pK n %d] timed out.\n",
 						xfer->len, xfer->tx_buf,
 						xfer->rx_buf,
 						xfer->bits_per_word);
-		ret = -ETIMEDOUT;
-		handle_fifo_timeout(mas);
+			mas->cur_xfer = NULL;
+			ret = -ETIMEDOUT;
+			goto err_fifo_geni_transfer_one;
+		}
+	} else {
+		setup_gsi_xfer(xfer, mas, slv, spi);
+		if ((mas->num_xfers >= NUM_SPI_XFER) ||
+			(list_is_last(&xfer->transfer_list,
+					&spi->cur_msg->transfers))) {
+			int i;
+
+			for (i = 0 ; i < mas->num_tx_eot; i++) {
+				timeout =
+				wait_for_completion_interruptible_timeout(
+					&mas->tx_cb,
+					msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
+				if (timeout <= 0) {
+					GENI_SE_ERR(mas->ipc, true, mas->dev,
+					"Tx[%d] timeout%lu\n", i, timeout);
+					ret = -ETIMEDOUT;
+					goto err_gsi_geni_transfer_one;
+				}
+			}
+			for (i = 0 ; i < mas->num_rx_eot; i++) {
+				timeout =
+				wait_for_completion_interruptible_timeout(
+					&mas->rx_cb,
+					msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
+				if (timeout <= 0) {
+					GENI_SE_ERR(mas->ipc, true, mas->dev,
+					 "Rx[%d] timeout%lu\n", i, timeout);
+					ret = -ETIMEDOUT;
+					goto err_gsi_geni_transfer_one;
+				}
+			}
+			if (mas->qn_err) {
+				ret = -EIO;
+				mas->qn_err = false;
+				goto err_gsi_geni_transfer_one;
+			}
+		}
 	}
-geni_transfer_one_exit:
+	return ret;
+err_gsi_geni_transfer_one:
+	dmaengine_terminate_all(mas->tx);
+	return ret;
+err_fifo_geni_transfer_one:
+	handle_fifo_timeout(mas);
 	return ret;
 }
 
@@ -412,8 +967,12 @@
 	int i = 0;
 	int tx_fifo_width = (mas->tx_fifo_width >> 3);
 	int max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
-	const u8 *tx_buf = mas->cur_xfer->tx_buf;
+	const u8 *tx_buf = NULL;
 
+	if (!mas->cur_xfer)
+		return;
+
+	tx_buf = mas->cur_xfer->tx_buf;
 	tx_buf += (mas->cur_xfer->len - mas->tx_rem_bytes);
 	max_bytes = min_t(int, mas->tx_rem_bytes, max_bytes);
 	while (i < max_bytes) {
@@ -444,8 +1003,12 @@
 	u32 rx_fifo_status = geni_read_reg(mas->base, SE_GENI_RX_FIFO_STATUS);
 	int rx_bytes = 0;
 	int rx_wc = 0;
-	u8 *rx_buf = mas->cur_xfer->rx_buf;
+	u8 *rx_buf = NULL;
 
+	if (!mas->cur_xfer)
+		return;
+
+	rx_buf = mas->cur_xfer->rx_buf;
 	rx_wc = (rx_fifo_status & RX_FIFO_WC_MSK);
 	if (rx_fifo_status & RX_LAST) {
 		int rx_last_byte_valid =
@@ -631,6 +1194,8 @@
 	spi->auto_runtime_pm = false;
 
 	init_completion(&geni_mas->xfer_done);
+	init_completion(&geni_mas->tx_cb);
+	init_completion(&geni_mas->rx_cb);
 	pm_runtime_enable(&pdev->dev);
 	ret = spi_register_master(spi);
 	if (ret) {
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 168383ec..9f47fb3 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -115,6 +115,7 @@
  */
 struct ion_handle {
 	struct kref ref;
+	unsigned int user_ref_count;
 	struct ion_client *client;
 	struct ion_buffer *buffer;
 	struct rb_node node;
@@ -433,6 +434,50 @@
 	return ret;
 }
 
+/* Must hold the client lock */
+static void user_ion_handle_get(struct ion_handle *handle)
+{
+	if (handle->user_ref_count++ == 0)
+		kref_get(&handle->ref);
+}
+
+/* Must hold the client lock */
+static struct ion_handle *user_ion_handle_get_check_overflow(
+	struct ion_handle *handle)
+{
+	if (handle->user_ref_count + 1 == 0)
+		return ERR_PTR(-EOVERFLOW);
+	user_ion_handle_get(handle);
+	return handle;
+}
+
+/* passes a kref to the user ref count.
+ * We know we're holding a kref to the object before and
+ * after this call, so no need to reverify handle.
+ */
+static struct ion_handle *pass_to_user(struct ion_handle *handle)
+{
+	struct ion_client *client = handle->client;
+	struct ion_handle *ret;
+
+	mutex_lock(&client->lock);
+	ret = user_ion_handle_get_check_overflow(handle);
+	ion_handle_put_nolock(handle);
+	mutex_unlock(&client->lock);
+	return ret;
+}
+
+/* Must hold the client lock */
+static int user_ion_handle_put_nolock(struct ion_handle *handle)
+{
+	int ret = 0;
+
+	if (--handle->user_ref_count == 0)
+		ret = ion_handle_put_nolock(handle);
+
+	return ret;
+}
+
 static struct ion_handle *ion_handle_lookup(struct ion_client *client,
 					    struct ion_buffer *buffer)
 {
@@ -650,6 +695,25 @@
 	ion_handle_put_nolock(handle);
 }
 
+static void user_ion_free_nolock(struct ion_client *client,
+				 struct ion_handle *handle)
+{
+	bool valid_handle;
+
+	WARN_ON(client != handle->client);
+
+	valid_handle = ion_handle_validate(client, handle);
+	if (!valid_handle) {
+		WARN(1, "%s: invalid handle passed to free.\n", __func__);
+		return;
+	}
+	if (!handle->user_ref_count > 0) {
+		WARN(1, "%s: User does not have access!\n", __func__);
+		return;
+	}
+	user_ion_handle_put_nolock(handle);
+}
+
 void ion_free(struct ion_client *client, struct ion_handle *handle)
 {
 	BUG_ON(client != handle->client);
@@ -1514,7 +1578,7 @@
 				     data.allocation.flags, true);
 		if (IS_ERR(handle))
 			return PTR_ERR(handle);
-
+		pass_to_user(handle);
 		data.allocation.handle = handle->id;
 
 		cleanup_handle = handle;
@@ -1531,7 +1595,7 @@
 			mutex_unlock(&client->lock);
 			return PTR_ERR(handle);
 		}
-		ion_free_nolock(client, handle);
+		user_ion_free_nolock(client, handle);
 		ion_handle_put_nolock(handle);
 		mutex_unlock(&client->lock);
 		break;
@@ -1555,10 +1619,15 @@
 		struct ion_handle *handle;
 
 		handle = ion_import_dma_buf_fd(client, data.fd.fd);
-		if (IS_ERR(handle))
+		if (IS_ERR(handle)) {
 			ret = PTR_ERR(handle);
-		else
-			data.handle.handle = handle->id;
+		} else {
+			handle = pass_to_user(handle);
+			if (IS_ERR(handle))
+				ret = PTR_ERR(handle);
+			else
+				data.handle.handle = handle->id;
+		}
 		break;
 	}
 	case ION_IOC_SYNC:
@@ -1590,8 +1659,10 @@
 	if (dir & _IOC_READ) {
 		if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) {
 			if (cleanup_handle) {
-				ion_free(client, cleanup_handle);
-				ion_handle_put(cleanup_handle);
+				mutex_lock(&client->lock);
+				user_ion_free_nolock(client, cleanup_handle);
+				ion_handle_put_nolock(cleanup_handle);
+				mutex_unlock(&client->lock);
 			}
 			return -EFAULT;
 		}
diff --git a/drivers/thermal/qcom/Kconfig b/drivers/thermal/qcom/Kconfig
index be33725..e7d6241 100644
--- a/drivers/thermal/qcom/Kconfig
+++ b/drivers/thermal/qcom/Kconfig
@@ -41,14 +41,14 @@
 	  sensors to query for temperature and the aggregation logic to
 	  determine the virtual sensor temperature.
 
-config QTI_REG_COOLING_DEVICE
-	bool "QTI Regulator cooling device"
+config QTI_AOP_REG_COOLING_DEVICE
+	bool "QTI AOP Regulator cooling device"
 	depends on THERMAL_OF && MSM_QMP
 	help
-	  This enables the Regulator cooling device. This cooling device
-	  will be used by QTI chipset to place a floor voltage restriction at
-	  low temperatures. The regulator cooling device will message the AOP
-	  using mail box to establish the floor voltage.
+	  This enables the AOP based Regulator cooling device. This cooling
+	  device will be used by QTI chipset to place a floor voltage
+	  restriction at low temperatures. The cooling device will message
+	  the AOP using mail box to establish the floor voltage.
 
 config QTI_QMI_COOLING_DEVICE
 	bool "QTI QMI cooling devices"
@@ -60,3 +60,14 @@
 	   remote subsystem voltage restriction at low temperatures etc.
 	   The QMI cooling device will interface with remote subsystem
 	   using QTI QMI interface.
+
+config REGULATOR_COOLING_DEVICE
+	bool "Regulator voltage floor cooling device"
+	depends on REGULATOR && THERMAL_OF
+	help
+	  This implements a mitigation device to place a minimum voltage floor
+	  on a particular regulator. This mitigation device will be used by low
+	  temperature reliability rules to mitigate a regulator at nominal
+	  voltage.
+
+	  If you want this support, you should say Y here.
diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile
index 000c6e7..257b714 100644
--- a/drivers/thermal/qcom/Makefile
+++ b/drivers/thermal/qcom/Makefile
@@ -3,5 +3,6 @@
 obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o
 obj-$(CONFIG_QTI_THERMAL_LIMITS_DCVS) += msm_lmh_dcvs.o lmh_dbg.o
 obj-$(CONFIG_QTI_VIRTUAL_SENSOR) += qti_virtual_sensor.o
-obj-$(CONFIG_QTI_REG_COOLING_DEVICE) += regulator_cooling.o
+obj-$(CONFIG_QTI_AOP_REG_COOLING_DEVICE) += regulator_aop_cdev.o
+obj-$(CONFIG_REGULATOR_COOLING_DEVICE) += regulator_cdev.o
 obj-$(CONFIG_QTI_QMI_COOLING_DEVICE) += thermal_mitigation_device_service_v01.o qmi_cooling.o
diff --git a/drivers/thermal/qcom/regulator_cooling.c b/drivers/thermal/qcom/regulator_aop_cdev.c
similarity index 98%
rename from drivers/thermal/qcom/regulator_cooling.c
rename to drivers/thermal/qcom/regulator_aop_cdev.c
index 3cbf198..965be2f 100644
--- a/drivers/thermal/qcom/regulator_cooling.c
+++ b/drivers/thermal/qcom/regulator_aop_cdev.c
@@ -17,7 +17,7 @@
 #include <linux/slab.h>
 #include <linux/mailbox_client.h>
 
-#define REG_CDEV_DRIVER "reg-cooling-device"
+#define REG_CDEV_DRIVER "reg-aop-cooling-device"
 #define REG_MSG_FORMAT "{class:volt_flr, event:zero_temp, res:%s, value:%s}"
 #define REG_CDEV_MAX_STATE 1
 #define MBOX_TOUT_MS 1000
diff --git a/drivers/thermal/qcom/regulator_cdev.c b/drivers/thermal/qcom/regulator_cdev.c
new file mode 100644
index 0000000..a770dcb
--- /dev/null
+++ b/drivers/thermal/qcom/regulator_cdev.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+
+#define REG_CDEV_DRIVER "reg-cooling-device"
+
+struct reg_cooling_device {
+	struct regulator		*reg;
+	struct thermal_cooling_device	*cool_dev;
+	unsigned int			min_reg_state;
+	unsigned int			*lvl;
+	unsigned int			lvl_ct;
+	char				reg_name[THERMAL_NAME_LENGTH];
+	bool				reg_enable;
+};
+
+static int reg_get_max_state(struct thermal_cooling_device *cdev,
+				 unsigned long *state)
+{
+	struct reg_cooling_device *reg_dev = cdev->devdata;
+
+	*state = reg_dev->lvl_ct;
+	return 0;
+}
+
+static int reg_get_min_state(struct thermal_cooling_device *cdev,
+				 unsigned long *state)
+{
+	struct reg_cooling_device *reg_dev = cdev->devdata;
+
+	*state = reg_dev->min_reg_state;
+	return 0;
+}
+
+static int reg_set_min_state(struct thermal_cooling_device *cdev,
+				 unsigned long state)
+{
+	struct reg_cooling_device *reg_dev = cdev->devdata;
+	int ret = 0;
+
+	if (state > reg_dev->lvl_ct)
+		state = reg_dev->lvl_ct;
+
+	if (reg_dev->min_reg_state == state)
+		return ret;
+
+	ret = regulator_set_voltage(reg_dev->reg,
+			reg_dev->lvl[state], INT_MAX);
+	if (ret) {
+		dev_err(&cdev->device,
+			"switching to floor %lu err:%d\n",
+			state, ret);
+		return ret;
+	}
+	if (reg_dev->reg_enable && state == reg_dev->lvl_ct) {
+		ret = regulator_disable(reg_dev->reg);
+		if (ret) {
+			dev_err(&cdev->device,
+				"regulator disable err:%d\n", ret);
+			return ret;
+		}
+		reg_dev->reg_enable = false;
+	} else if (!reg_dev->reg_enable && state != reg_dev->lvl_ct) {
+		ret = regulator_enable(reg_dev->reg);
+		if (ret) {
+			dev_err(&cdev->device,
+				"regulator enable err:%d\n", ret);
+			return ret;
+		}
+		reg_dev->reg_enable = true;
+	}
+	reg_dev->min_reg_state = state;
+
+	return ret;
+}
+
+static int reg_get_cur_state(struct thermal_cooling_device *cdev,
+				 unsigned long *state)
+{
+	*state = 0;
+	return 0;
+}
+
+static int reg_set_cur_state(struct thermal_cooling_device *cdev,
+				 unsigned long state)
+{
+	/* regulator cooling device doesn't support voltage ceil */
+	return 0;
+}
+
+static struct thermal_cooling_device_ops reg_device_ops = {
+	.get_max_state = reg_get_max_state,
+	.get_cur_state = reg_get_cur_state,
+	.set_cur_state = reg_set_cur_state,
+	.set_min_state = reg_set_min_state,
+	.get_min_state = reg_get_min_state,
+};
+
+static int reg_cdev_probe(struct platform_device *pdev)
+{
+	struct reg_cooling_device *reg_dev;
+	int ret = 0;
+	struct device_node *np;
+
+	np = dev_of_node(&pdev->dev);
+	if (!np) {
+		dev_err(&pdev->dev,
+			"of node not available for cooling device\n");
+		return -EINVAL;
+	}
+
+	reg_dev = devm_kzalloc(&pdev->dev, sizeof(*reg_dev), GFP_KERNEL);
+	if (!reg_dev)
+		return -ENOMEM;
+
+	reg_dev->reg = devm_regulator_get(&pdev->dev, "regulator-cdev");
+	if (IS_ERR_OR_NULL(reg_dev->reg)) {
+		ret = PTR_ERR(reg_dev->reg);
+		dev_err(&pdev->dev, "regulator register err:%d\n", ret);
+		return ret;
+	}
+	ret = of_property_count_u32_elems(np, "regulator-levels");
+	if (ret <= 0) {
+		dev_err(&pdev->dev, "Invalid levels err:%d\n", ret);
+		return ret;
+	}
+	reg_dev->lvl_ct = ret;
+	reg_dev->lvl = devm_kcalloc(&pdev->dev, reg_dev->lvl_ct,
+			sizeof(*reg_dev->lvl), GFP_KERNEL);
+	if (!reg_dev->lvl)
+		return -ENOMEM;
+	ret = of_property_read_u32_array(np, "regulator-levels",
+				reg_dev->lvl, reg_dev->lvl_ct);
+	if (ret) {
+		dev_err(&pdev->dev, "cdev level fetch err:%d\n", ret);
+		return ret;
+	}
+	/* level count is an index and it depicts the max possible index */
+	reg_dev->lvl_ct--;
+	reg_dev->min_reg_state = reg_dev->lvl_ct;
+	reg_dev->reg_enable = false;
+	strlcpy(reg_dev->reg_name, np->name, THERMAL_NAME_LENGTH);
+
+	reg_dev->cool_dev = thermal_of_cooling_device_register(
+					np, reg_dev->reg_name, reg_dev,
+					&reg_device_ops);
+	if (IS_ERR(reg_dev->cool_dev)) {
+		ret = PTR_ERR(reg_dev->cool_dev);
+		dev_err(&pdev->dev, "regulator cdev register err:%d\n",
+				ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id reg_cdev_of_match[] = {
+	{.compatible = "qcom,regulator-cooling-device", },
+	{}
+};
+
+static struct platform_driver reg_cdev_driver = {
+	.driver = {
+		.name = REG_CDEV_DRIVER,
+		.of_match_table = reg_cdev_of_match,
+	},
+	.probe = reg_cdev_probe,
+};
+builtin_platform_driver(reg_cdev_driver);
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 8039346..11b4958 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -1119,10 +1119,21 @@
 	unsigned int rx_bytes = 0;
 	struct tty_port *tport;
 	int ret;
+	unsigned int geni_status;
+
+	geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
+	/* Possible stop rx is called */
+	if (!(geni_status & S_GENI_CMD_ACTIVE))
+		return 0;
 
 	geni_se_rx_dma_unprep(msm_port->wrapper_dev, msm_port->rx_dma,
 			      DMA_RX_BUF_SIZE);
 	rx_bytes = geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN);
+	if (unlikely(!msm_port->rx_buf || !rx_bytes)) {
+		IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: Rx_buf %pK Size %d\n",
+					__func__, msm_port->rx_buf, rx_bytes);
+		return 0;
+	}
 
 	tport = &uport->state->port;
 	ret = tty_insert_flip_string(tport, (unsigned char *)(msm_port->rx_buf),
@@ -1313,13 +1324,13 @@
 		wait_for_transfers_inflight(uport);
 	}
 
+	disable_irq(uport->irq);
+	free_irq(uport->irq, msm_port);
 	spin_lock_irqsave(&uport->lock, flags);
 	msm_geni_serial_stop_tx(uport);
 	msm_geni_serial_stop_rx(uport);
 	spin_unlock_irqrestore(&uport->lock, flags);
 
-	disable_irq(uport->irq);
-	free_irq(uport->irq, msm_port);
 	if (uart_console(uport)) {
 		se_geni_resources_off(&msm_port->serial_rsc);
 	} else {
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 69d617f..aca5d97 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -252,6 +252,7 @@
 	struct notifier_block	vbus_nb;
 	struct notifier_block	id_nb;
 	struct notifier_block	eud_event_nb;
+	struct notifier_block	host_restart_nb;
 
 	struct notifier_block	host_nb;
 
@@ -285,6 +286,8 @@
 static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc);
 static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA);
 static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event);
+static int dwc3_restart_usb_host_mode(struct notifier_block *nb,
+					unsigned long event, void *ptr);
 
 static inline bool is_valid_usb_speed(struct dwc3 *dwc, int speed)
 {
@@ -2141,7 +2144,6 @@
 static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 {
 	int ret;
-	bool can_suspend_ssphy;
 	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 	struct dwc3_event_buffer *evt;
 	struct usb_irq *uirq;
@@ -2198,10 +2200,6 @@
 	if (ret)
 		return ret;
 
-	/* Initialize variables here */
-	can_suspend_ssphy = !(mdwc->in_host_mode &&
-				dwc3_msm_is_host_superspeed(mdwc));
-
 	/* Disable core irq */
 	if (dwc->irq)
 		disable_irq(dwc->irq);
@@ -2217,7 +2215,7 @@
 	usb_phy_set_suspend(mdwc->hs_phy, 1);
 
 	/* Suspend SS PHY */
-	if (dwc->maximum_speed == USB_SPEED_SUPER && can_suspend_ssphy) {
+	if (dwc->maximum_speed == USB_SPEED_SUPER) {
 		/* indicate phy about SS mode */
 		if (dwc3_msm_is_superspeed(mdwc))
 			mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE;
@@ -2926,12 +2924,21 @@
 	if (!IS_ERR(edev)) {
 		mdwc->extcon_id = edev;
 		mdwc->id_nb.notifier_call = dwc3_msm_id_notifier;
+		mdwc->host_restart_nb.notifier_call =
+					dwc3_restart_usb_host_mode;
 		ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
 				&mdwc->id_nb);
 		if (ret < 0) {
 			dev_err(mdwc->dev, "failed to register notifier for USB-HOST\n");
 			goto err;
 		}
+
+		ret = extcon_register_blocking_notifier(edev, EXTCON_USB_HOST,
+							&mdwc->host_restart_nb);
+		if (ret < 0) {
+			dev_err(mdwc->dev, "failed to register blocking notifier\n");
+			goto err1;
+		}
 	}
 
 	edev = NULL;
@@ -2940,7 +2947,7 @@
 		edev = extcon_get_edev_by_phandle(mdwc->dev, 2);
 		if (IS_ERR(edev) && PTR_ERR(edev) != -ENODEV) {
 			ret = PTR_ERR(edev);
-			goto err;
+			goto err1;
 		}
 	}
 
@@ -2951,11 +2958,15 @@
 				&mdwc->eud_event_nb);
 		if (ret < 0) {
 			dev_err(mdwc->dev, "failed to register notifier for EUD-USB\n");
-			goto err1;
+			goto err2;
 		}
 	}
 
 	return 0;
+err2:
+	if (mdwc->extcon_id)
+		extcon_unregister_blocking_notifier(mdwc->extcon_id,
+				EXTCON_USB_HOST, &mdwc->host_restart_nb);
 err1:
 	if (mdwc->extcon_id)
 		extcon_unregister_notifier(mdwc->extcon_id, EXTCON_USB_HOST,
@@ -3882,6 +3893,43 @@
 	return 0;
 }
 
+/* speed: 0 - USB_SPEED_HIGH, 1 - USB_SPEED_SUPER */
+static int dwc3_restart_usb_host_mode(struct notifier_block *nb,
+				unsigned long event, void *ptr)
+{
+	struct dwc3_msm *mdwc;
+	struct dwc3 *dwc;
+	int ret = -EINVAL, usb_speed;
+
+	mdwc = container_of(nb, struct dwc3_msm, host_restart_nb);
+	dwc = platform_get_drvdata(mdwc->dwc3);
+
+	usb_speed = (event == 0 ? USB_SPEED_HIGH : USB_SPEED_SUPER);
+	if (dwc->maximum_speed == usb_speed)
+		goto err;
+
+	dbg_event(0xFF, "stop_host_mode", dwc->maximum_speed);
+	ret = dwc3_otg_start_host(mdwc, 0);
+	if (ret)
+		goto err;
+
+	/*
+	 * stop host mode functionality performs autosuspend with mdwc
+	 * device, and it may take sometime to call PM runtime suspend.
+	 * Hence call pm_runtime_suspend() API to invoke PM runtime
+	 * suspend immediately to put USB controller and PHYs into suspend.
+	 */
+	ret = pm_runtime_suspend(mdwc->dev);
+	dbg_event(0xFF, "pm_runtime_sus", ret);
+
+	dwc->maximum_speed = usb_speed;
+	mdwc->otg_state = OTG_STATE_B_IDLE;
+	schedule_delayed_work(&mdwc->sm_work, 0);
+	dbg_event(0xFF, "complete_host_change", dwc->maximum_speed);
+err:
+	return ret;
+}
+
 static int get_psy_type(struct dwc3_msm *mdwc)
 {
 	union power_supply_propval pval = {0};
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index dca4811..574ff79 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -38,6 +38,10 @@
 module_param(disable_usb_pd, bool, 0644);
 MODULE_PARM_DESC(disable_usb_pd, "Disable USB PD for USB3.1 compliance testing");
 
+static bool rev3_sink_only;
+module_param(rev3_sink_only, bool, 0644);
+MODULE_PARM_DESC(rev3_sink_only, "Enable power delivery rev3.0 sink only mode");
+
 enum usbpd_state {
 	PE_UNKNOWN,
 	PE_ERROR_RECOVERY,
@@ -533,21 +537,18 @@
 	pd->send_dr_swap = false;
 }
 
-static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
-		size_t num_data, enum pd_msg_type type)
+static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data,
+		size_t num_data, enum pd_sop_type sop)
 {
 	int ret;
 	u16 hdr;
 
-	hdr = PD_MSG_HDR(hdr_type, pd->current_dr, pd->current_pr,
+	hdr = PD_MSG_HDR(msg_type, pd->current_dr, pd->current_pr,
 			pd->tx_msgid, num_data, pd->spec_rev);
-	ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), type, 15);
-	/* TODO figure out timeout. based on tReceive=1.1ms x nRetryCount? */
 
-	if (ret < 0)
+	ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop);
+	if (ret)
 		return ret;
-	else if (ret != num_data * sizeof(u32))
-		return -EIO;
 
 	pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
 	return 0;
@@ -609,7 +610,7 @@
 
 static int pd_eval_src_caps(struct usbpd *pd)
 {
-	int obj_cnt;
+	int i;
 	union power_supply_propval val;
 	u32 first_pdo = pd->received_pdos[0];
 
@@ -626,11 +627,20 @@
 	power_supply_set_property(pd->usb_psy,
 			POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val);
 
-	for (obj_cnt = 1; obj_cnt < PD_MAX_DATA_OBJ; obj_cnt++) {
-		if ((PD_SRC_PDO_TYPE(pd->received_pdos[obj_cnt]) ==
+	if (pd->spec_rev == USBPD_REV_30 && !rev3_sink_only) {
+		bool pps_found = false;
+
+		/* downgrade to 2.0 if no PPS */
+		for (i = 1; i < PD_MAX_DATA_OBJ; i++) {
+			if ((PD_SRC_PDO_TYPE(pd->received_pdos[i]) ==
 					PD_SRC_PDO_TYPE_AUGMENTED) &&
-				!PD_APDO_PPS(pd->received_pdos[obj_cnt]))
-			pd->spec_rev = USBPD_REV_30;
+				!PD_APDO_PPS(pd->received_pdos[i])) {
+				pps_found = true;
+				break;
+			}
+		}
+		if (!pps_found)
+			pd->spec_rev = USBPD_REV_20;
 	}
 
 	/* Select the first PDO (vSafe5V) immediately. */
@@ -648,7 +658,7 @@
 	/* Force CC logic to source/sink to keep Rp/Rd unchanged */
 	set_power_role(pd, pd->current_pr);
 	pd->hard_reset_count++;
-	pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
+	pd_phy_signal(HARD_RESET_SIG);
 	pd->in_pr_swap = false;
 	power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val);
 }
@@ -664,12 +674,12 @@
 		queue_work(pd->wq, &pd->sm_work);
 }
 
-static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
+static void phy_sig_received(struct usbpd *pd, enum pd_sig_type sig)
 {
 	union power_supply_propval val = {1};
 
-	if (type != HARD_RESET_SIG) {
-		usbpd_err(&pd->dev, "invalid signal (%d) received\n", type);
+	if (sig != HARD_RESET_SIG) {
+		usbpd_err(&pd->dev, "invalid signal (%d) received\n", sig);
 		return;
 	}
 
@@ -684,16 +694,16 @@
 	kick_sm(pd, 0);
 }
 
-static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
+static void phy_msg_received(struct usbpd *pd, enum pd_sop_type sop,
 		u8 *buf, size_t len)
 {
 	struct rx_msg *rx_msg;
 	unsigned long flags;
 	u16 header;
 
-	if (type != SOP_MSG) {
+	if (sop != SOP_MSG) {
 		usbpd_err(&pd->dev, "invalid msg type (%d) received; only SOP supported\n",
-				type);
+				sop);
 		return;
 	}
 
@@ -731,6 +741,10 @@
 		return;
 	}
 
+	/* if spec rev differs (i.e. is older), update PHY */
+	if (PD_MSG_HDR_REV(header) < pd->spec_rev)
+		pd->spec_rev = PD_MSG_HDR_REV(header);
+
 	rx_msg = kzalloc(sizeof(*rx_msg), GFP_KERNEL);
 	if (!rx_msg)
 		return;
@@ -817,6 +831,8 @@
 		power_supply_set_property(pd->usb_psy,
 				POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
 
+		/* support only PD 2.0 as a source */
+		pd->spec_rev = USBPD_REV_20;
 		pd_reset_protocol(pd);
 
 		if (!pd->in_pr_swap) {
@@ -988,6 +1004,11 @@
 		if (!val.intval || disable_usb_pd)
 			break;
 
+		/*
+		 * support up to PD 3.0 as a sink; if source is 2.0
+		 * phy_msg_received() will handle the downgrade.
+		 */
+		pd->spec_rev = USBPD_REV_30;
 		pd_reset_protocol(pd);
 
 		if (!pd->in_pr_swap) {
@@ -1675,6 +1696,8 @@
 		/* set due to dual_role class "mode" change */
 		if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
 			val.intval = pd->forced_pr;
+		else if (rev3_sink_only)
+			val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
 		else
 			/* Set CC back to DRP toggle */
 			val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
@@ -3401,8 +3424,6 @@
 		pd->dual_role->drv_data = pd;
 	}
 
-	/* default support as PD 2.0 source or sink */
-	pd->spec_rev = USBPD_REV_20;
 	pd->current_pr = PR_NONE;
 	pd->current_dr = DR_NONE;
 	list_add_tail(&pd->instance, &_usbpd);
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 1f5306f..735774a 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -80,6 +80,10 @@
 #define VDD_PDPHY_VOL_MAX		3088000 /* uV */
 #define VDD_PDPHY_HPM_LOAD		3000 /* uA */
 
+/* timers */
+#define RECEIVER_RESPONSE_TIME		15	/* tReceiverResponse */
+#define HARD_RESET_COMPLETE_TIME	5	/* tHardResetComplete */
+
 struct usb_pdphy {
 	struct device *dev;
 	struct regmap *regmap;
@@ -96,8 +100,8 @@
 	int msg_tx_discarded_irq;
 	int msg_rx_discarded_irq;
 
-	void (*signal_cb)(struct usbpd *pd, enum pd_sig_type type);
-	void (*msg_rx_cb)(struct usbpd *pd, enum pd_msg_type type,
+	void (*signal_cb)(struct usbpd *pd, enum pd_sig_type sig);
+	void (*msg_rx_cb)(struct usbpd *pd, enum pd_sop_type sop,
 			  u8 *buf, size_t len);
 	void (*shutdown_cb)(struct usbpd *pd);
 
@@ -401,14 +405,13 @@
 }
 EXPORT_SYMBOL(pd_phy_open);
 
-int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
+int pd_phy_signal(enum pd_sig_type sig)
 {
 	u8 val;
 	int ret;
 	struct usb_pdphy *pdphy = __pdphy;
 
-	dev_dbg(pdphy->dev, "%s: type %d timeout %u\n", __func__, type,
-			timeout_ms);
+	dev_dbg(pdphy->dev, "%s: type %d\n", __func__, sig);
 
 	if (!pdphy) {
 		pr_err("%s: pdphy not found\n", __func__);
@@ -428,7 +431,7 @@
 
 	usleep_range(2, 3);
 
-	val = (type == CABLE_RESET_SIG ? TX_CONTROL_FRAME_TYPE_CABLE_RESET : 0)
+	val = (sig == CABLE_RESET_SIG ? TX_CONTROL_FRAME_TYPE_CABLE_RESET : 0)
 		| TX_CONTROL_SEND_SIGNAL;
 
 	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
@@ -436,7 +439,8 @@
 		return ret;
 
 	ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
-		pdphy->tx_status != -EINPROGRESS, msecs_to_jiffies(timeout_ms));
+		pdphy->tx_status != -EINPROGRESS,
+		msecs_to_jiffies(HARD_RESET_COMPLETE_TIME));
 	if (ret <= 0) {
 		dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
 		return ret ? ret : -ETIMEDOUT;
@@ -447,7 +451,7 @@
 	if (pdphy->tx_status)
 		return pdphy->tx_status;
 
-	if (type == HARD_RESET_SIG)
+	if (sig == HARD_RESET_SIG)
 		/* Frame filter is reconfigured in pd_phy_open() */
 		return pdphy_reg_write(pdphy, USB_PDPHY_FRAME_FILTER, 0);
 
@@ -455,16 +459,15 @@
 }
 EXPORT_SYMBOL(pd_phy_signal);
 
-int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
-	enum pd_msg_type type, unsigned int timeout_ms)
+int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop)
 {
 	u8 val;
 	int ret;
 	size_t total_len = data_len + USB_PDPHY_MSG_HDR_LEN;
 	struct usb_pdphy *pdphy = __pdphy;
 
-	dev_dbg(pdphy->dev, "%s: hdr %x frame type %d timeout %u\n",
-			__func__, hdr, type, timeout_ms);
+	dev_dbg(pdphy->dev, "%s: hdr %x frame sop_type %d\n",
+			__func__, hdr, sop);
 
 	if (data && data_len)
 		print_hex_dump_debug("tx data obj:", DUMP_PREFIX_NONE, 32, 4,
@@ -518,14 +521,15 @@
 
 	usleep_range(2, 3);
 
-	val = TX_CONTROL_RETRY_COUNT | (type << 2) | TX_CONTROL_SEND_MSG;
+	val = TX_CONTROL_RETRY_COUNT | (sop << 2) | TX_CONTROL_SEND_MSG;
 
 	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
 	if (ret)
 		return ret;
 
 	ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
-		pdphy->tx_status != -EINPROGRESS, msecs_to_jiffies(timeout_ms));
+		pdphy->tx_status != -EINPROGRESS,
+		msecs_to_jiffies(RECEIVER_RESPONSE_TIME));
 	if (ret <= 0) {
 		dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
 		return ret ? ret : -ETIMEDOUT;
@@ -534,7 +538,7 @@
 	if (hdr && !pdphy->tx_status)
 		pdphy->tx_bytes += data_len + USB_PDPHY_MSG_HDR_LEN;
 
-	return pdphy->tx_status ? pdphy->tx_status : data_len;
+	return pdphy->tx_status ? pdphy->tx_status : 0;
 }
 EXPORT_SYMBOL(pd_phy_write);
 
diff --git a/drivers/usb/pd/usbpd.h b/drivers/usb/pd/usbpd.h
index 1087017..9b6053e 100644
--- a/drivers/usb/pd/usbpd.h
+++ b/drivers/usb/pd/usbpd.h
@@ -45,7 +45,7 @@
 	CABLE_RESET_SIG,
 };
 
-enum pd_msg_type {
+enum pd_sop_type {
 	SOP_MSG = 0,
 	SOPI_MSG,
 	SOPII_MSG,
@@ -61,8 +61,8 @@
 #define FRAME_FILTER_EN_HARD_RESET	BIT(5)
 
 struct pd_phy_params {
-	void		(*signal_cb)(struct usbpd *pd, enum pd_sig_type type);
-	void		(*msg_rx_cb)(struct usbpd *pd, enum pd_msg_type type,
+	void		(*signal_cb)(struct usbpd *pd, enum pd_sig_type sig);
+	void		(*msg_rx_cb)(struct usbpd *pd, enum pd_sop_type sop,
 					u8 *buf, size_t len);
 	void		(*shutdown_cb)(struct usbpd *pd);
 	enum data_role	data_role;
@@ -72,9 +72,9 @@
 
 #if IS_ENABLED(CONFIG_QPNP_USB_PDPHY)
 int pd_phy_open(struct pd_phy_params *params);
-int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms);
+int pd_phy_signal(enum pd_sig_type sig);
 int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
-	enum pd_msg_type type, unsigned int timeout_ms);
+		enum pd_sop_type sop);
 int pd_phy_update_roles(enum data_role dr, enum power_role pr);
 void pd_phy_close(void);
 #else
@@ -83,13 +83,13 @@
 	return -ENODEV;
 }
 
-static inline int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
+static inline int pd_phy_signal(enum pd_sig_type type)
 {
 	return -ENODEV;
 }
 
 static inline int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
-	enum pd_msg_type type, unsigned int timeout_ms)
+		enum pd_sop_type sop)
 {
 	return -ENODEV;
 }
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 2524807..6fa5a66 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -91,8 +91,11 @@
 
 	if (type == ACL_TYPE_ACCESS) {
 		umode_t mode = inode->i_mode;
-
+		struct posix_acl *old_acl = acl;
 		error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+
+		if (!acl)
+			posix_acl_release(old_acl);
 		if (error)
 			return error;
 		if (mode != inode->i_mode)
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 7034e17..b2d55a3 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -258,8 +258,10 @@
 
 	if (type == ACL_TYPE_ACCESS) {
 		umode_t mode;
-
+		struct posix_acl *old_acl = acl;
 		error = posix_acl_update_mode(inode, &mode, &acl);
+		if (!acl)
+			posix_acl_release(old_acl);
 		if (error)
 			return error;
 		error = xfs_set_mode(inode, mode);
diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
index 323beaf..74a742a 100644
--- a/include/dt-bindings/clock/qcom,gpucc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
@@ -44,6 +44,7 @@
 #define GPU_CC_GMU_CLK_SRC					26
 #define GPU_CC_CX_GFX3D_CLK					27
 #define GPU_CC_CX_GFX3D_SLV_CLK					28
+#define GPU_CC_PLL0						29
 
 /* GPUCC reset clock registers */
 #define GPUCC_GPU_CC_ACD_BCR					0
@@ -55,7 +56,6 @@
 #define GPUCC_GPU_CC_XO_BCR					6
 
 /* GFX3D clock registers */
-#define GPU_CC_PLL0						0
 #define GPU_CC_PLL0_OUT_EVEN					1
 #define GPU_CC_GX_GFX3D_CLK_SRC					2
 #define GPU_CC_GX_GFX3D_CLK					3
diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h
new file mode 100644
index 0000000..08e0def
--- /dev/null
+++ b/include/linux/msm_ext_display.h
@@ -0,0 +1,182 @@
+/*  Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 and
+ *  only version 2 as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef _MSM_EXT_DISPLAY_H_
+#define _MSM_EXT_DISPLAY_H_
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/extcon.h>
+
+#define AUDIO_ACK_SET_ENABLE BIT(5)
+#define AUDIO_ACK_ENABLE BIT(4)
+#define AUDIO_ACK_CONNECT BIT(0)
+
+/*
+ *   Flags to be used with the HPD operation of the external display
+ *   interface:
+ *   MSM_EXT_DISP_HPD_AUDIO: audio will be routed to external display
+ *   MSM_EXT_DISP_HPD_VIDEO: video will be routed to external display
+ */
+#define MSM_EXT_DISP_HPD_AUDIO BIT(0)
+#define MSM_EXT_DISP_HPD_VIDEO BIT(1)
+
+/**
+ *  struct ext_disp_cable_notify - cable notify handler structure
+ *  @link: a link for the linked list
+ *  @status: current status of HDMI/DP cable connection
+ *  @hpd_notify: callback function to provide cable status
+ */
+struct ext_disp_cable_notify {
+	struct list_head link;
+	int status;
+	void (*hpd_notify)(struct ext_disp_cable_notify *h);
+};
+
+struct msm_ext_disp_audio_edid_blk {
+	u8 *audio_data_blk;
+	unsigned int audio_data_blk_size; /* in bytes */
+	u8 *spk_alloc_data_blk;
+	unsigned int spk_alloc_data_blk_size; /* in bytes */
+};
+
+struct msm_ext_disp_audio_setup_params {
+	u32 sample_rate_hz;
+	u32 num_of_channels;
+	u32 channel_allocation;
+	u32 level_shift;
+	bool down_mix;
+	u32 sample_present;
+};
+
+/*
+ *  External Display identifier for use to determine which interface
+ *  the audio driver is interacting with.
+ */
+enum msm_ext_disp_type {
+	EXT_DISPLAY_TYPE_HDMI = EXTCON_DISP_HDMI,
+	EXT_DISPLAY_TYPE_DP = EXTCON_DISP_DP,
+	EXT_DISPLAY_TYPE_MAX = 0xFFFFFFFF
+};
+
+/*
+ *  External Display cable state used by display interface to indicate
+ *  connect/disconnect of interface.
+ */
+enum msm_ext_disp_cable_state {
+	EXT_DISPLAY_CABLE_DISCONNECT,
+	EXT_DISPLAY_CABLE_CONNECT,
+	EXT_DISPLAY_CABLE_STATE_MAX
+};
+
+/**
+ *  External Display power state used by display interface to indicate
+ *  power on/off of the interface.
+ */
+enum msm_ext_disp_power_state {
+	EXT_DISPLAY_POWER_OFF,
+	EXT_DISPLAY_POWER_ON,
+	EXT_DISPLAY_POWER_MAX
+};
+
+/**
+ *  struct msm_ext_disp_intf_ops - operations exposed to display interface
+ *  @audio_config: configures the audio operations exposed to codec driver
+ *  @audio_notify: notifies the audio connection state to user modules.
+ *  @video_notify: notifies the video connection state to user modules.
+ */
+struct msm_ext_disp_intf_ops {
+	int (*audio_config)(struct platform_device *pdev,
+			enum msm_ext_disp_type type,
+			enum msm_ext_disp_cable_state state);
+
+	int (*audio_notify)(struct platform_device *pdev,
+			enum msm_ext_disp_type type,
+			enum msm_ext_disp_cable_state state);
+
+
+	int (*video_notify)(struct platform_device *pdev,
+			enum msm_ext_disp_type type,
+			enum msm_ext_disp_cable_state state);
+};
+
+/**
+ *  struct msm_ext_disp_audio_codec_ops - operations exposed to audio codec
+ *  @audio_info_setup: configure audio on interface
+ *  @get_audio_edid_blk: retrieve audio edid block
+ *  @cable_status: cable connected/disconnected
+ *  @get_intf_id: id of connected interface
+ *  @teardown_done: audio session teardown done by qdsp
+ *  @acknowledge: acknowledge audio status received by user modules
+ */
+struct msm_ext_disp_audio_codec_ops {
+	int (*audio_info_setup)(struct platform_device *pdev,
+			struct msm_ext_disp_audio_setup_params *params);
+	int (*get_audio_edid_blk)(struct platform_device *pdev,
+			struct msm_ext_disp_audio_edid_blk *blk);
+	int (*cable_status)(struct platform_device *pdev, u32 vote);
+	int (*get_intf_id)(struct platform_device *pdev);
+	void (*teardown_done)(struct platform_device *pdev);
+	int (*acknowledge)(struct platform_device *pdev, u32 ack);
+};
+
+/**
+ *  struct msm_ext_disp_init_data - data needed to register a display interface
+ *  @type: external display type
+ *  @intf_ops: external display interface operations
+ *  @codec_ops: audio codec operations
+ *  @pdev: platform device instance of the interface driver
+ *  @intf_data: interface specific data
+ */
+struct msm_ext_disp_init_data {
+	enum msm_ext_disp_type type;
+	struct msm_ext_disp_intf_ops intf_ops;
+	struct msm_ext_disp_audio_codec_ops codec_ops;
+	struct platform_device *pdev;
+	void *intf_data;
+};
+
+/**
+ * struct msm_ext_disp_data - data needed by interface modules
+ * @intf_pdev: platform device instance of the interface
+ * @intf_data: data related to interface module
+ */
+struct msm_ext_disp_data {
+	struct platform_device *intf_pdev;
+	void *intf_data;
+};
+
+/**
+ *  msm_ext_disp_register_audio_codec() - audio codec registration
+ *  @pdev: platform device pointer
+ *  @codec_ops: audio codec operations
+ */
+int msm_ext_disp_register_audio_codec(struct platform_device *pdev,
+		struct msm_ext_disp_audio_codec_ops *ops);
+
+/**
+ *  msm_hdmi_register_audio_codec() - wrapper for hdmi audio codec
+ * registration
+ *  @pdev: platform device pointer
+ *  @codec_ops: audio codec operations
+ */
+int msm_hdmi_register_audio_codec(struct platform_device *pdev,
+		struct msm_ext_disp_audio_codec_ops *ops);
+
+/**
+ *  msm_ext_disp_register_intf() - display interface registration
+ *  @init_data: data needed to register the display interface
+ */
+int msm_ext_disp_register_intf(struct platform_device *pdev,
+		struct msm_ext_disp_init_data *init_data);
+
+#endif /*_MSM_EXT_DISPLAY_H_*/
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index 2938206..aa4c1ed 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -82,7 +82,7 @@
 #define GENI_SER_M_CLK_CFG		(0x48)
 #define GENI_SER_S_CLK_CFG		(0x4C)
 #define GENI_CLK_CTRL_RO		(0x60)
-#define GENI_IF_DISABLE_RO		(0x64)
+#define GENI_IF_FIFO_DISABLE_RO		(0x64)
 #define GENI_FW_REVISION_RO		(0x68)
 #define GENI_FW_S_REVISION_RO		(0x6C)
 #define SE_GENI_CLK_SEL			(0x7C)
@@ -147,7 +147,8 @@
 
 /* CLK_CTRL_RO fields */
 
-/* IF_DISABLE_RO fields */
+/* FIFO_IF_DISABLE_RO fields */
+#define FIFO_IF_DISABLE			(BIT(0))
 
 /* FW_REVISION_RO fields */
 #define FW_REV_PROTOCOL_MSK	(GENMASK(15, 8))
@@ -330,6 +331,12 @@
 #define DEFAULT_BUS_WIDTH	(4)
 #define DEFAULT_SE_CLK		(19200000)
 
+/* GSI TRE fields */
+/* Packing fields */
+#define GSI_TX_PACK_EN          (BIT(0))
+#define GSI_RX_PACK_EN          (BIT(1))
+#define GSI_PRESERVE_PACK       (BIT(2))
+
 #define GENI_SE_ERR(log_ctx, print, dev, x...) do { \
 if (log_ctx) \
 	ipc_log_string(log_ctx, x); \
diff --git a/include/linux/qcom_tspp.h b/include/linux/qcom_tspp.h
index 1b34c38..7a9e569 100644
--- a/include/linux/qcom_tspp.h
+++ b/include/linux/qcom_tspp.h
@@ -16,6 +16,7 @@
 struct tspp_data_descriptor {
 	void *virt_base;   /* logical address of the actual data */
 	phys_addr_t phys_base; /* physical address of the actual data */
+	dma_addr_t dma_base; /* DMA address of the actual data */
 	u32 size;          /* size of buffer in bytes */
 	int id;            /* unique identifier */
 	void *user;        /* user-defined data */
@@ -75,9 +76,17 @@
 	TSIF_TTS_LPASS_TIMER	/* Time stamps from AV/Qtimer Timer  */
 };
 
+struct tspp_ion_dma_buf_info {
+	struct dma_buf *dbuf;
+	struct dma_buf_attachment *attach;
+	struct sg_table *table;
+	bool smmu_map;
+	dma_addr_t dma_map_base;
+};
+
 typedef void (tspp_notifier)(int channel_id, void *user);
 typedef void* (tspp_allocator)(int channel_id, u32 size,
-	phys_addr_t *phys_base, void *user);
+	      phys_addr_t *phys_base, dma_addr_t *dma_base, void *user);
 typedef void (tspp_memfree)(int channel_id, u32 size,
 	void *virt_base, phys_addr_t phys_base, void *user);
 
@@ -105,4 +114,9 @@
 int tspp_get_lpass_time_counter(u32 dev, enum tspp_source source,
 			u64 *lpass_time_counter);
 
+int tspp_attach_ion_dma_buff(u32 dev,
+	struct tspp_ion_dma_buf_info *ion_dma_buf);
+
+int tspp_detach_ion_dma_buff(u32 dev,
+	struct tspp_ion_dma_buf_info *ion_dma_buf);
 #endif /* _MSM_TSPP_H_ */
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
index 0320210..19e76db 100644
--- a/include/linux/sde_rsc.h
+++ b/include/linux/sde_rsc.h
@@ -21,6 +21,9 @@
 
 #define MAX_RSC_CLIENT_NAME_LEN 128
 
+/* DRM Object IDs are numbered excluding 0, use 0 to indicate invalid CRTC */
+#define SDE_RSC_INVALID_CRTC_ID 0
+
 /**
  * event will be triggered before sde core power collapse,
  * mdss gdsc is still on
@@ -169,12 +172,29 @@
  * @config:	 fps, vtotal, porches, etc configuration for command mode
  *               panel
  * @crtc_id:	 current client's crtc id
+ * @wait_vblank_crtc_id:	Output parameter. If set to non-zero, rsc hw
+ *				state update requires a wait for one vblank on
+ *				the primary crtc. In that case, this output
+ *				param will be set to the crtc on which to wait.
+ *				If SDE_RSC_INVALID_CRTC_ID, no wait necessary
  *
  * Return: error code.
  */
 int sde_rsc_client_state_update(struct sde_rsc_client *client,
 	enum sde_rsc_state state,
-	struct sde_rsc_cmd_config *config, int crtc_id);
+	struct sde_rsc_cmd_config *config, int crtc_id,
+	int *wait_vblank_crtc_id);
+
+/**
+ * sde_rsc_client_is_state_update_complete() - check if state update is complete
+ * RSC state transition is not complete until HW receives VBLANK signal. This
+ * function checks RSC HW to determine whether that signal has been received.
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: true if the state update has completed.
+ */
+bool sde_rsc_client_is_state_update_complete(
+		struct sde_rsc_client *caller_client);
 
 /**
  * sde_rsc_client_vote() - ab/ib vote from rsc client
@@ -244,6 +264,12 @@
 	return 0;
 }
 
+static inline bool sde_rsc_client_is_state_update_complete(
+		struct sde_rsc_client *caller_client)
+{
+	return false;
+}
+
 static inline int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
 	u32 bus_id, u64 ab_vote, u64 ib_vote)
 {
diff --git a/include/trace/events/msm_vidc.h b/include/trace/events/msm_vidc.h
index ea698bf..c6c446a 100644
--- a/include/trace/events/msm_vidc.h
+++ b/include/trace/events/msm_vidc.h
@@ -310,6 +310,39 @@
 	TP_ARGS(buffer_op, domain_num, partition_num, align, iova, buffer_size)
 );
 
+DECLARE_EVENT_CLASS(msm_vidc_perf,
+
+	TP_PROTO(const char *name, unsigned long value),
+
+	TP_ARGS(name, value),
+
+	TP_STRUCT__entry(
+		__field(const char *, name)
+		__field(unsigned long, value)
+	),
+
+	TP_fast_assign(
+		__entry->name = name;
+		__entry->value = value;
+	),
+
+	TP_printk("%s %lu", __entry->name, __entry->value)
+);
+
+DEFINE_EVENT(msm_vidc_perf, msm_vidc_perf_clock_scale,
+
+	TP_PROTO(const char *clock_name, unsigned long frequency),
+
+	TP_ARGS(clock_name, frequency)
+);
+
+DEFINE_EVENT(msm_vidc_perf, msm_vidc_perf_bus_vote,
+
+	TP_PROTO(const char *governor_mode, unsigned long ab),
+
+	TP_ARGS(governor_mode, ab)
+);
+
 #endif
 
 #include <trace/define_trace.h>
diff --git a/include/uapi/drm/msm_drm_pp.h b/include/uapi/drm/msm_drm_pp.h
index c7f2308..5f70a57 100644
--- a/include/uapi/drm/msm_drm_pp.h
+++ b/include/uapi/drm/msm_drm_pp.h
@@ -104,6 +104,7 @@
 #define GAMUT_3D_MODE5_TBL_SZ 32
 #define GAMUT_3D_MODE13_TBL_SZ 550
 #define GAMUT_3D_SCALE_OFF_SZ 16
+#define GAMUT_3D_SCALEB_OFF_SZ 12
 #define GAMUT_3D_TBL_NUM 4
 #define GAMUT_3D_SCALE_OFF_TBL_NUM 3
 #define GAMUT_3D_MAP_EN (1 << 0)
diff --git a/include/uapi/linux/hbtp_input.h b/include/uapi/linux/hbtp_input.h
index 9173c2a..3b124ff 100644
--- a/include/uapi/linux/hbtp_input.h
+++ b/include/uapi/linux/hbtp_input.h
@@ -6,6 +6,8 @@
 #define HBTP_MAX_FINGER		20
 #define HBTP_ABS_MT_FIRST	ABS_MT_TOUCH_MAJOR
 #define HBTP_ABS_MT_LAST	ABS_MT_TOOL_Y
+#define MAX_ROI_SIZE		144
+#define MAX_ACCEL_SIZE		128
 
 #define HBTP_EVENT_TYPE_DISPLAY	"EVENT_TYPE=HBTP_DISPLAY"
 
@@ -20,6 +22,11 @@
 	__s32 orientation;
 };
 
+struct hbtp_sensor_data {
+	__s16 accelBuffer[MAX_ACCEL_SIZE];
+	__s16 ROI[MAX_ROI_SIZE];
+};
+
 struct hbtp_input_mt {
 	__s32 num_touches;
 	struct hbtp_input_touch touches[HBTP_MAX_FINGER];
@@ -68,6 +75,8 @@
 					enum hbtp_afe_signal)
 #define HBTP_SET_POWER_CTRL	_IOW(HBTP_INPUT_IOCTL_BASE, 206, \
 					enum hbtp_afe_power_ctrl)
+#define HBTP_SET_SENSORDATA	_IOW(HBTP_INPUT_IOCTL_BASE, 207, \
+					struct hbtp_sensor_data)
 
 #endif	/* _UAPI_HBTP_INPUT_H */
 
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 939ad08..5fdbdd8 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -892,22 +892,37 @@
  * @hdr_len_remove: Specifies how much of the header needs to
 		be removed in bytes
  * @eth_hdr_retained: Specifies if Ethernet header is retained or not
+ * @hdr_ofst_pkt_size_valid: Specifies if the Header offset is valid
+ * @hdr_ofst_pkt_size: If hdr_ofst_pkt_size_valid =1, this indicates where the
+		packet size field (2bytes) resides
+ * @hdr_endianness: 0:little endian, 1:big endian
  */
 struct ipa_l2tp_header_remove_procparams {
 	uint32_t hdr_len_remove:8;
 	uint32_t eth_hdr_retained:1;
-	uint32_t reserved:23;
+	/* Following fields are valid if eth_hdr_retained =1 ( bridge mode) */
+	uint32_t hdr_ofst_pkt_size_valid:1;
+	uint32_t hdr_ofst_pkt_size:6;
+	uint32_t hdr_endianness:1;
+	uint32_t reserved:15;
 };
 
 /**
- * union ipa_l2tp_hdr_proc_ctx_params -
+ * struct ipa_l2tp_hdr_proc_ctx_params -
  * @hdr_add_param: parameters for header add
  * @hdr_remove_param: parameters for header remove
+ * @is_dst_pipe_valid: if dst pipe is valid
+ * @dst_pipe: destination pipe
  */
-union ipa_l2tp_hdr_proc_ctx_params {
+struct ipa_l2tp_hdr_proc_ctx_params {
 	struct ipa_l2tp_header_add_procparams hdr_add_param;
 	struct ipa_l2tp_header_remove_procparams hdr_remove_param;
+	uint8_t is_dst_pipe_valid;
+	enum ipa_client_type dst_pipe;
 };
+
+#define L2TP_USER_SPACE_SPECIFY_DST_PIPE
+
 /**
  * struct ipa_hdr_proc_ctx_add - processing context descriptor includes
  * in and out parameters
@@ -924,7 +939,7 @@
 	uint32_t hdr_hdl;
 	uint32_t proc_ctx_hdl;
 	int status;
-	union ipa_l2tp_hdr_proc_ctx_params l2tp_params;
+	struct ipa_l2tp_hdr_proc_ctx_params l2tp_params;
 };
 
 #define IPA_L2TP_HDR_PROC_SUPPORT
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 731b2f0..5183111 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1079,6 +1079,26 @@
 #define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT \
 	(V4L2_CID_MPEG_MSM_VIDC_BASE + 110)
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE  \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 111)
+
+enum v4l2_mpeg_vidc_video_tme_profile {
+	V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0 = 0,
+	V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1 = 1,
+	V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2 = 2,
+	V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3 = 3,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 112)
+
+enum v4l2_mpeg_vidc_video_tme_level {
+	V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER = 0,
+};
+
+#define V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION  \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 113)
+
 /*  Camera class control IDs */
 
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 4f1f9e9..85b7e87 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -613,6 +613,7 @@
 #define V4L2_PIX_FMT_VP8      v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
 #define V4L2_PIX_FMT_VP9      v4l2_fourcc('V', 'P', '9', '0') /* VP9 */
 #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* for HEVC stream */
+#define V4L2_PIX_FMT_TME v4l2_fourcc('T', 'M', 'E', '0') /* for TME stream */
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h
index be87b1e..4f12e5c 100644
--- a/include/uapi/media/msm_media_info.h
+++ b/include/uapi/media/msm_media_info.h
@@ -769,11 +769,49 @@
 	 *           + max(Extradata, Y_Stride * 48), 4096)
 	 */
 	COLOR_FMT_P010_UBWC,
+	/* Venus P010:
+	 * YUV 4:2:0 image with a plane of 10 bit Y samples followed
+	 * by an interleaved U/V plane containing 10 bit 2x2 subsampled
+	 * colour difference samples.
+	 *
+	 * <-------- Y/UV_Stride -------->
+	 * <------- Width ------->
+	 * Y Y Y Y Y Y Y Y Y Y Y Y . . . .  ^           ^
+	 * Y Y Y Y Y Y Y Y Y Y Y Y . . . .  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y . . . .  Height      |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y . . . .  |          Y_Scanlines
+	 * Y Y Y Y Y Y Y Y Y Y Y Y . . . .  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y . . . .  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y . . . .  |           |
+	 * Y Y Y Y Y Y Y Y Y Y Y Y . . . .  V           |
+	 * . . . . . . . . . . . . . . . .              |
+	 * . . . . . . . . . . . . . . . .              |
+	 * . . . . . . . . . . . . . . . .              |
+	 * . . . . . . . . . . . . . . . .              V
+	 * U V U V U V U V U V U V . . . .  ^
+	 * U V U V U V U V U V U V . . . .  |
+	 * U V U V U V U V U V U V . . . .  |
+	 * U V U V U V U V U V U V . . . .  UV_Scanlines
+	 * . . . . . . . . . . . . . . . .  |
+	 * . . . . . . . . . . . . . . . .  V
+	 * . . . . . . . . . . . . . . . .  --> Buffer size alignment
+	 *
+	 * Y_Stride : Width * 2 aligned to 128
+	 * UV_Stride : Width * 2 aligned to 128
+	 * Y_Scanlines: Height aligned to 32
+	 * UV_Scanlines: Height/2 aligned to 16
+	 * Extradata: Arbitrary (software-imposed) padding
+	 * Total size = align((Y_Stride * Y_Scanlines
+	 *          + UV_Stride * UV_Scanlines
+	 *          + max(Extradata, Y_Stride * 8), 4096)
+	 */
+	COLOR_FMT_P010,
 };
 
 #define COLOR_FMT_RGBA1010102_UBWC	COLOR_FMT_RGBA1010102_UBWC
 #define COLOR_FMT_RGB565_UBWC		COLOR_FMT_RGB565_UBWC
 #define COLOR_FMT_P010_UBWC		COLOR_FMT_P010_UBWC
+#define COLOR_FMT_P010		COLOR_FMT_P010
 
 static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height)
 {
@@ -818,6 +856,10 @@
 		alignment = 256;
 		stride = MSM_MEDIA_ALIGN(width * 2, alignment);
 		break;
+	case COLOR_FMT_P010:
+		alignment = 128;
+		stride = MSM_MEDIA_ALIGN(width*2, alignment);
+		break;
 	default:
 		break;
 	}
@@ -856,6 +898,10 @@
 		alignment = 256;
 		stride = MSM_MEDIA_ALIGN(width * 2, alignment);
 		break;
+	case COLOR_FMT_P010:
+		alignment = 128;
+		stride = MSM_MEDIA_ALIGN(width*2, alignment);
+		break;
 	default:
 		break;
 	}
@@ -882,6 +928,7 @@
 	case COLOR_FMT_NV12:
 	case COLOR_FMT_NV12_MVTB:
 	case COLOR_FMT_NV12_UBWC:
+	case COLOR_FMT_P010:
 		alignment = 32;
 		break;
 	case COLOR_FMT_NV12_BPP10_UBWC:
@@ -916,6 +963,7 @@
 	case COLOR_FMT_NV12_MVTB:
 	case COLOR_FMT_NV12_BPP10_UBWC:
 	case COLOR_FMT_P010_UBWC:
+	case COLOR_FMT_P010:
 		alignment = 16;
 		break;
 	case COLOR_FMT_NV12_UBWC:
@@ -1204,6 +1252,7 @@
 	switch (color_fmt) {
 	case COLOR_FMT_NV21:
 	case COLOR_FMT_NV12:
+	case COLOR_FMT_P010:
 		uv_alignment = 4096;
 		y_plane = y_stride * y_sclines;
 		uv_plane = uv_stride * uv_sclines + uv_alignment;
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index dce76d1..1b53241 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -15,7 +15,7 @@
 #include <linux/kthread.h>
 #include <linux/slab.h>
 #include <trace/events/power.h>
-
+#include <linux/sched/sysctl.h>
 #include "sched.h"
 
 #define SUGOV_KTHREAD_PRIORITY	50
@@ -216,6 +216,10 @@
 				u64 upto)
 {
 	u64 delta_ns, cycles;
+
+	if (unlikely(!sysctl_sched_use_walt_cpu_util))
+		return;
+
 	/* Track cycles in current window */
 	delta_ns = upto - sg_policy->last_cyc_update_time;
 	cycles = (prev_freq * delta_ns) / (NSEC_PER_SEC / KHZ);
@@ -229,6 +233,9 @@
 	u64 last_ws = sg_policy->last_ws;
 	unsigned int avg_freq;
 
+	if (unlikely(!sysctl_sched_use_walt_cpu_util))
+		return;
+
 	WARN_ON(curr_ws < last_ws);
 	if (curr_ws <= last_ws)
 		return;
@@ -259,6 +266,9 @@
 	unsigned long cpu_util = sg_cpu->util;
 	bool is_hiload;
 
+	if (unlikely(!sysctl_sched_use_walt_cpu_util))
+		return;
+
 	is_hiload = (cpu_util >= mult_frac(sg_policy->avg_cap,
 					   HISPEED_LOAD,
 					   100));
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index a26036d..49237ae 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -70,6 +70,9 @@
 
 static struct hrtimer sched_clock_timer;
 static int irqtime = -1;
+static u64 suspend_ns;
+static u64 suspend_cycles;
+static u64 resume_cycles;
 
 core_param(irqtime, irqtime, int, 0400);
 
@@ -274,6 +277,11 @@
 	struct clock_read_data *rd = &cd.read_data[0];
 
 	update_sched_clock();
+
+	suspend_ns = rd->epoch_ns;
+	suspend_cycles = rd->epoch_cyc;
+	pr_info("suspend ns:%17llu	suspend cycles:%17llu\n",
+				rd->epoch_ns, rd->epoch_cyc);
 	hrtimer_cancel(&sched_clock_timer);
 	rd->read_sched_clock = suspended_sched_clock_read;
 
@@ -285,6 +293,8 @@
 	struct clock_read_data *rd = &cd.read_data[0];
 
 	rd->epoch_cyc = cd.actual_read_sched_clock();
+	resume_cycles = rd->epoch_cyc;
+	pr_info("resume cycles:%17llu\n", rd->epoch_cyc);
 	hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
 	rd->read_sched_clock = cd.actual_read_sched_clock;
 }
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index ad1d616..e82cff5 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -304,7 +304,7 @@
 	if (!*fmt)
 		return 0;
 
-	seq_printf(m, "0x%lx : \"", *(unsigned long *)fmt);
+	seq_printf(m, "0x%lx : \"", 0L);
 
 	/*
 	 * Tabs and new lines need to be converted.
diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c
index 834594a..bbf0a3a 100644
--- a/net/netfilter/xt_quota2.c
+++ b/net/netfilter/xt_quota2.c
@@ -16,6 +16,7 @@
 #include <linux/proc_fs.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
+#include <linux/workqueue.h>
 #include <asm/atomic.h>
 #include <net/netlink.h>
 
@@ -43,6 +44,8 @@
 	unsigned char payload[0];
 } ulog_packet_msg_t;
 #endif
+#define QUOTA2_SYSFS_WORK_MAX_SIZE 64
+#define QUOTA2_SYSFS_NUM_ENVP 3
 
 /**
  * @lock:	lock to protect quota writers from each other
@@ -54,17 +57,16 @@
 	atomic_t ref;
 	char name[sizeof(((struct xt_quota_mtinfo2 *)NULL)->name)];
 	struct proc_dir_entry *procfs_entry;
+	char last_iface[QUOTA2_SYSFS_WORK_MAX_SIZE];
+	char last_prefix[QUOTA2_SYSFS_WORK_MAX_SIZE];
+	struct work_struct work;
 };
 
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-/* Harald's favorite number +1 :D From ipt_ULOG.C */
-static int qlog_nl_event = 112;
-module_param_named(event_num, qlog_nl_event, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(event_num,
-		 "Event number for NETLINK_NFLOG message. 0 disables log."
-		 "111 is what ipt_ULOG uses.");
-static struct sock *nflognl;
-#endif
+#define to_quota_counter(x) container_of(x, struct xt_quota_counter, work)
+
+static struct class *quota_class;
+static struct device *quota_device;
+static struct kobject *quota_kobj;
 
 static LIST_HEAD(counter_list);
 static DEFINE_SPINLOCK(counter_list_lock);
@@ -75,68 +77,39 @@
 static kgid_t quota_list_gid = KGIDT_INIT(0);
 module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR);
 
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-static void quota2_log(unsigned int hooknum,
-		       const struct sk_buff *skb,
-		       const struct net_device *in,
+static void quota2_work(struct work_struct *work)
+{
+	char alert_msg[QUOTA2_SYSFS_WORK_MAX_SIZE];
+	char iface_name[QUOTA2_SYSFS_WORK_MAX_SIZE];
+	char *envp[QUOTA2_SYSFS_NUM_ENVP] = {alert_msg, iface_name,  NULL};
+	struct xt_quota_counter *counter = to_quota_counter(work);
+
+	snprintf(alert_msg, sizeof(alert_msg), "ALERT_NAME=%s", counter->name);
+	snprintf(iface_name, sizeof(iface_name), "INTERFACE=%s",
+		 counter->last_iface);
+
+	kobject_uevent_env(quota_kobj, KOBJ_CHANGE, envp);
+}
+
+static void quota2_log(const struct net_device *in,
 		       const struct net_device *out,
+		       struct  xt_quota_counter *q,
 		       const char *prefix)
 {
-	ulog_packet_msg_t *pm;
-	struct sk_buff *log_skb;
-	size_t size;
-	struct nlmsghdr *nlh;
-
-	if (!qlog_nl_event)
+	if (!prefix)
 		return;
 
-	size = NLMSG_SPACE(sizeof(*pm));
-	size = max(size, (size_t)NLMSG_GOODSIZE);
-	log_skb = alloc_skb(size, GFP_ATOMIC);
-	if (!log_skb) {
-		pr_err("xt_quota2: cannot alloc skb for logging\n");
-		return;
-	}
+	strlcpy(q->last_prefix, prefix, QUOTA2_SYSFS_WORK_MAX_SIZE);
 
-	nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, qlog_nl_event,
-			sizeof(*pm), 0);
-	if (!nlh) {
-		pr_err("xt_quota2: nlmsg_put failed\n");
-		kfree_skb(log_skb);
-		return;
-	}
-	pm = nlmsg_data(nlh);
-	if (skb->tstamp.tv64 == 0)
-		__net_timestamp((struct sk_buff *)skb);
-	pm->data_len = 0;
-	pm->hook = hooknum;
-	if (prefix != NULL)
-		strlcpy(pm->prefix, prefix, sizeof(pm->prefix));
-	else
-		*(pm->prefix) = '\0';
 	if (in)
-		strlcpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+		strlcpy(q->last_iface, in->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
+	else if (out)
+		strlcpy(q->last_iface, out->name, QUOTA2_SYSFS_WORK_MAX_SIZE);
 	else
-		pm->indev_name[0] = '\0';
+		strlcpy(q->last_iface, "UNKNOWN", QUOTA2_SYSFS_WORK_MAX_SIZE);
 
-	if (out)
-		strlcpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
-	else
-		pm->outdev_name[0] = '\0';
-
-	NETLINK_CB(log_skb).dst_group = 1;
-	pr_debug("throwing 1 packets to netlink group 1\n");
-	netlink_broadcast(nflognl, log_skb, 0, 1, GFP_ATOMIC);
+	schedule_work(&q->work);
 }
-#else
-static void quota2_log(unsigned int hooknum,
-		       const struct sk_buff *skb,
-		       const struct net_device *in,
-		       const struct net_device *out,
-		       const char *prefix)
-{
-}
-#endif  /* if+else CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG */
 
 static ssize_t quota_proc_read(struct file *file, char __user *buf,
 			   size_t size, loff_t *ppos)
@@ -193,6 +166,9 @@
 		INIT_LIST_HEAD(&e->list);
 		atomic_set(&e->ref, 1);
 		strlcpy(e->name, q->name, sizeof(e->name));
+		strlcpy(e->last_prefix, "UNSET", sizeof(e->last_prefix));
+		strlcpy(e->last_iface, "UNSET", sizeof(e->last_iface));
+		INIT_WORK(&e->work, quota2_work);
 	}
 	return e;
 }
@@ -326,11 +302,7 @@
 		} else {
 			/* We are transitioning, log that fact. */
 			if (e->quota) {
-				quota2_log(par->hooknum,
-					   skb,
-					   par->in,
-					   par->out,
-					   q->name);
+				quota2_log(par->in, par->out, e, q->name);
 			}
 			/* we do not allow even small packets from now on */
 			e->quota = 0;
@@ -368,11 +340,25 @@
 	int ret;
 	pr_debug("xt_quota2: init()");
 
-#ifdef CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG
-	nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL);
-	if (!nflognl)
-		return -ENOMEM;
-#endif
+	quota_class = class_create(THIS_MODULE, "xt_quota2");
+	ret = PTR_ERR(quota_class);
+	if (IS_ERR(quota_class)) {
+		pr_err("xt_quota2: couldn't create class");
+		class_destroy(quota_class);
+		return ret;
+	}
+
+	quota_device = device_create(quota_class, NULL, MKDEV(0, 0), NULL,
+				     "counters");
+	ret = PTR_ERR(quota_device);
+	if (IS_ERR(quota_device)) {
+		pr_err("xt_quota2: couldn't create device");
+		device_destroy(quota_class, MKDEV(0, 0));
+		class_destroy(quota_class);
+		return ret;
+	}
+
+	quota_kobj = &quota_device->kobj;
 
 	proc_xt_quota = proc_mkdir("xt_quota", init_net.proc_net);
 	if (proc_xt_quota == NULL)
@@ -389,6 +375,8 @@
 {
 	xt_unregister_matches(quota_mt2_reg, ARRAY_SIZE(quota_mt2_reg));
 	remove_proc_entry("xt_quota", init_net.proc_net);
+	device_destroy(quota_class, MKDEV(0, 0));
+	class_destroy(quota_class);
 }
 
 module_init(quota_mt2_init);
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index abadd08..66ecd6a 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -160,34 +160,6 @@
 	the machine driver and the corresponding
 	DAI-links
 
-config SND_SOC_MSM8996
-	tristate "SoC Machine driver for MSM8996 boards"
-	depends on ARCH_MSM8996
-	select SND_SOC_COMPRESS
-	select SND_SOC_QDSP6V2
-	select SND_SOC_MSM_STUB
-	select SND_SOC_MSM_HOSTLESS_PCM
-	select SND_DYNAMIC_MINORS
-	select MSM_QDSP6_APRV2
-	select MSM_QDSP6V2_CODECS
-	select SND_SOC_WCD9335
-	select SND_SOC_WSA881X
-	select SND_SOC_MSM_HDMI_CODEC_RX
-	select DTS_SRS_TM
-	select QTI_PP
-	select QTI_PP_AUDIOSPHERE
-	select SND_SOC_CPE
-	select MSM_ULTRASOUND
-	select DOLBY_DS2
-	select SND_HWDEP
-        select DTS_EAGLE
-	help
-	 To add support for SoC audio on MSM8996.
-	 This will enable sound soc drivers which
-	 interfaces with DSP, also it will enable
-	 the machine driver and the corresponding
-	 DAI-links
-
 config SND_SOC_MACHINE_MSM8998
 	tristate "SoC Machine driver for MSM8998 boards"
 	select SND_SOC_WSA881X
@@ -230,7 +202,7 @@
 
 config SND_SOC_660
 	tristate "SoC Machine driver for SDM660/670 boards"
-	depends on ARCH_SDM660 || ARCH_SDM670
+	depends on ARCH_QCOM
 	select SND_SOC_INT_CODEC
 	select SND_SOC_EXT_CODEC
 	help
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 312bb45..93fddb5 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -12,10 +12,6 @@
 snd-soc-cpe-objs := msm-cpe-lsm.o
 obj-$(CONFIG_SND_SOC_CPE) += snd-soc-cpe.o
 
-# for MSM8996 sound card driver
-snd-soc-msm8996-objs := msm8996.o
-obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-msm8996.o
-
 # for MSM8998 sound card driver
 snd-soc-msm8998-objs := msm8998.o
 obj-$(CONFIG_SND_SOC_MACHINE_MSM8998) += snd-soc-msm8998.o
diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c
deleted file mode 100644
index 0890037..0000000
--- a/sound/soc/msm/msm8996.c
+++ /dev/null
@@ -1,4007 +0,0 @@
-/*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/regulator/consumer.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/switch.h>
-#include <linux/input.h>
-#include <sound/core.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/pcm.h>
-#include <sound/jack.h>
-#include <sound/q6afe-v2.h>
-#include <sound/q6core.h>
-#include <sound/pcm_params.h>
-#include <sound/info.h>
-#include <device_event.h>
-#include "qdsp6v2/msm-pcm-routing-v2.h"
-#include "../codecs/wcd9xxx-common.h"
-#include "../codecs/wcd9330.h"
-#include "../codecs/wcd9335.h"
-#include "../codecs/wsa881x.h"
-
-#define DRV_NAME "msm8996-asoc-snd"
-
-#define SAMPLING_RATE_8KHZ      8000
-#define SAMPLING_RATE_16KHZ     16000
-#define SAMPLING_RATE_32KHZ     32000
-#define SAMPLING_RATE_48KHZ     48000
-#define SAMPLING_RATE_96KHZ     96000
-#define SAMPLING_RATE_192KHZ    192000
-#define SAMPLING_RATE_44P1KHZ   44100
-
-#define MSM8996_SPK_ON     1
-#define MSM8996_HIFI_ON    1
-
-#define WCD9XXX_MBHC_DEF_BUTTONS    8
-#define WCD9XXX_MBHC_DEF_RLOADS     5
-#define CODEC_EXT_CLK_RATE         9600000
-#define ADSP_STATE_READY_TIMEOUT_MS    3000
-#define DEV_NAME_STR_LEN            32
-
-#define WSA8810_NAME_1 "wsa881x.20170211"
-#define WSA8810_NAME_2 "wsa881x.20170212"
-
-static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim0_tx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim1_tx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int slim1_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
-static int slim5_rx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim5_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-static int slim6_rx_sample_rate = SAMPLING_RATE_48KHZ;
-static int slim6_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-
-static struct platform_device *spdev;
-static int ext_us_amp_gpio = -1;
-static int msm8996_spk_control = 1;
-static int msm_slim_0_rx_ch = 1;
-static int msm_slim_0_tx_ch = 1;
-static int msm_slim_1_tx_ch = 1;
-static int msm_slim_5_rx_ch = 1;
-static int msm_slim_6_rx_ch = 1;
-static int msm_hifi_control;
-static int msm_vi_feed_tx_ch = 2;
-
-static int msm_hdmi_rx_ch = 2;
-static int msm_proxy_rx_ch = 2;
-static int hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ;
-static int msm_tert_mi2s_tx_ch = 2;
-
-static bool codec_reg_done;
-
-static const char *const hifi_function[] = {"Off", "On"};
-static const char *const pin_states[] = {"Disable", "active"};
-static const char *const spk_function[] = {"Off", "On"};
-static const char *const slim0_rx_ch_text[] = {"One", "Two"};
-static const char *const slim5_rx_ch_text[] = {"One", "Two"};
-static const char *const slim6_rx_ch_text[] = {"One", "Two"};
-static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
-						"Five", "Six", "Seven",
-						"Eight"};
-static const char *const vi_feed_ch_text[] = {"One", "Two"};
-static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
-					"Six", "Seven", "Eight"};
-static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
-static char const *slim5_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
-static char const *slim6_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"};
-static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
-					"KHZ_192", "KHZ_44P1", "KHZ_8",
-					"KHZ_16", "KHZ_32"};
-static char const *slim5_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
-						  "KHZ_192", "KHZ_44P1"};
-static char const *slim6_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
-						  "KHZ_192", "KHZ_44P1"};
-static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
-	"Five", "Six", "Seven", "Eight"};
-
-static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
-					"KHZ_192"};
-
-static const char *const auxpcm_rate_text[] = {"8000", "16000"};
-static const struct soc_enum msm8996_auxpcm_enum[] = {
-		SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
-};
-
-static struct afe_clk_set mi2s_tx_clk = {
-	AFE_API_VERSION_I2S_CONFIG,
-	Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
-	Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ,
-	Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
-	Q6AFE_LPASS_CLK_ROOT_DEFAULT,
-	0,
-};
-
-struct msm8996_wsa881x_dev_info {
-	struct device_node *of_node;
-	u32 index;
-};
-
-static struct snd_soc_aux_dev *msm8996_aux_dev;
-static struct snd_soc_codec_conf *msm8996_codec_conf;
-
-struct msm8996_asoc_mach_data {
-	u32 mclk_freq;
-	int us_euro_gpio;
-	int hph_en1_gpio;
-	int hph_en0_gpio;
-	struct snd_info_entry *codec_root;
-};
-
-struct msm8996_asoc_wcd93xx_codec {
-	void* (*get_afe_config_fn)(struct snd_soc_codec *codec,
-				   enum afe_config_type config_type);
-	void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
-};
-
-static struct msm8996_asoc_wcd93xx_codec msm8996_codec_fn;
-
-struct msm8996_liquid_dock_dev {
-	int dock_plug_gpio;
-	int dock_plug_irq;
-	int dock_plug_det;
-	struct work_struct irq_work;
-	struct switch_dev audio_sdev;
-};
-static struct msm8996_liquid_dock_dev *msm8996_liquid_dock_dev;
-
-static void *adsp_state_notifier;
-static void *def_tasha_mbhc_cal(void);
-static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
-					int enable, bool dapm);
-static int msm8996_wsa881x_init(struct snd_soc_component *component);
-
-/*
- * Need to report LINEIN
- * if R/L channel impedance is larger than 5K ohm
- */
-static struct wcd_mbhc_config wcd_mbhc_cfg = {
-	.read_fw_bin = false,
-	.calibration = NULL,
-	.detect_extn_cable = true,
-	.mono_stero_detection = false,
-	.swap_gnd_mic = NULL,
-	.hs_ext_micbias = true,
-	.key_code[0] = KEY_MEDIA,
-	.key_code[1] = KEY_VOICECOMMAND,
-	.key_code[2] = KEY_VOLUMEUP,
-	.key_code[3] = KEY_VOLUMEDOWN,
-	.key_code[4] = 0,
-	.key_code[5] = 0,
-	.key_code[6] = 0,
-	.key_code[7] = 0,
-	.linein_th = 5000,
-	.moisture_en = true,
-	.mbhc_micbias = MIC_BIAS_2,
-	.anc_micbias = MIC_BIAS_2,
-	.enable_anc_mic_detect = false,
-};
-
-static inline int param_is_mask(int p)
-{
-	return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
-			(p <= SNDRV_PCM_HW_PARAM_LAST_MASK);
-}
-
-static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p,
-					     int n)
-{
-	return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
-}
-
-static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit)
-{
-	if (bit >= SNDRV_MASK_MAX)
-		return;
-	if (param_is_mask(n)) {
-		struct snd_mask *m = param_to_mask(p, n);
-
-		m->bits[0] = 0;
-		m->bits[1] = 0;
-		m->bits[bit >> 5] |= (1 << (bit & 31));
-	}
-}
-
-static void msm8996_liquid_docking_irq_work(struct work_struct *work)
-{
-	struct msm8996_liquid_dock_dev *dock_dev =
-		container_of(work, struct msm8996_liquid_dock_dev,
-			     irq_work);
-
-	dock_dev->dock_plug_det =
-		gpio_get_value(dock_dev->dock_plug_gpio);
-
-	switch_set_state(&dock_dev->audio_sdev, dock_dev->dock_plug_det);
-	/* notify to audio daemon */
-	sysfs_notify(&dock_dev->audio_sdev.dev->kobj, NULL, "state");
-}
-
-static irqreturn_t msm8996_liquid_docking_irq_handler(int irq, void *dev)
-{
-	struct msm8996_liquid_dock_dev *dock_dev = dev;
-
-	/* switch speakers should not run in interrupt context */
-	schedule_work(&dock_dev->irq_work);
-	return IRQ_HANDLED;
-}
-
-static int msm8996_liquid_init_docking(void)
-{
-	int ret = 0;
-	int dock_plug_gpio = 0;
-
-	/* plug in docking speaker+plug in device OR unplug one of them */
-	u32 dock_plug_irq_flags = IRQF_TRIGGER_RISING |
-				  IRQF_TRIGGER_FALLING |
-				  IRQF_SHARED;
-
-	dock_plug_gpio = of_get_named_gpio(spdev->dev.of_node,
-					   "qcom,dock-plug-det-irq", 0);
-
-	if (dock_plug_gpio >= 0) {
-		msm8996_liquid_dock_dev =
-		 kzalloc(sizeof(*msm8996_liquid_dock_dev), GFP_KERNEL);
-		if (!msm8996_liquid_dock_dev) {
-			ret = -ENOMEM;
-			goto exit;
-		}
-
-		msm8996_liquid_dock_dev->dock_plug_gpio = dock_plug_gpio;
-
-		ret = gpio_request(msm8996_liquid_dock_dev->dock_plug_gpio,
-					   "dock-plug-det-irq");
-		if (ret) {
-			pr_err("%s:failed request msm8996_liquid_dock_plug_gpio err = %d\n",
-				__func__, ret);
-			ret = -EINVAL;
-			goto fail_dock_gpio;
-		}
-
-		msm8996_liquid_dock_dev->dock_plug_det =
-			gpio_get_value(
-				msm8996_liquid_dock_dev->dock_plug_gpio);
-		msm8996_liquid_dock_dev->dock_plug_irq =
-			gpio_to_irq(
-				msm8996_liquid_dock_dev->dock_plug_gpio);
-
-		ret = request_irq(msm8996_liquid_dock_dev->dock_plug_irq,
-				  msm8996_liquid_docking_irq_handler,
-				  dock_plug_irq_flags,
-				  "liquid_dock_plug_irq",
-				  msm8996_liquid_dock_dev);
-		if (ret < 0) {
-			pr_err("%s: Request Irq Failed err = %d\n",
-				__func__, ret);
-			goto fail_dock_gpio;
-		}
-
-		msm8996_liquid_dock_dev->audio_sdev.name =
-						QC_AUDIO_EXTERNAL_SPK_1_EVENT;
-
-		if (switch_dev_register(
-			 &msm8996_liquid_dock_dev->audio_sdev) < 0) {
-			pr_err("%s: dock device register in switch diretory failed\n",
-				__func__);
-			goto fail_switch_dev;
-		}
-
-		INIT_WORK(
-			&msm8996_liquid_dock_dev->irq_work,
-			msm8996_liquid_docking_irq_work);
-	}
-	return 0;
-
-fail_switch_dev:
-	free_irq(msm8996_liquid_dock_dev->dock_plug_irq,
-				msm8996_liquid_dock_dev);
-fail_dock_gpio:
-	gpio_free(msm8996_liquid_dock_dev->dock_plug_gpio);
-exit:
-	kfree(msm8996_liquid_dock_dev);
-	msm8996_liquid_dock_dev = NULL;
-	return ret;
-}
-
-static void msm8996_ext_control(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-
-	pr_debug("%s: msm8996_spk_control = %d", __func__,
-		 msm8996_spk_control);
-	if (msm8996_spk_control == MSM8996_SPK_ON) {
-		snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
-		snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
-	} else {
-		snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
-		snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
-	}
-	snd_soc_dapm_sync(dapm);
-}
-
-static int msm8996_get_spk(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm8996_spk_control = %d\n",
-			 __func__, msm8996_spk_control);
-	ucontrol->value.integer.value[0] = msm8996_spk_control;
-	return 0;
-}
-
-static int msm8996_set_spk(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
-	pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n",
-		 __func__, ucontrol->value.integer.value[0]);
-	if (msm8996_spk_control == ucontrol->value.integer.value[0])
-		return 0;
-
-	msm8996_spk_control = ucontrol->value.integer.value[0];
-	msm8996_ext_control(codec);
-	return 1;
-}
-
-static int msm8996_hifi_ctrl(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_card *card = codec->component.card;
-	struct msm8996_asoc_mach_data *pdata =
-				snd_soc_card_get_drvdata(card);
-
-	pr_debug("%s: msm_hifi_control = %d", __func__,
-		 msm_hifi_control);
-	if (pdata->hph_en1_gpio < 0) {
-		pr_err("%s: hph_en1_gpio is invalid\n", __func__);
-		return -EINVAL;
-	}
-	if (msm_hifi_control == MSM8996_HIFI_ON) {
-		gpio_direction_output(pdata->hph_en1_gpio, 1);
-		/* 5msec delay needed as per HW requirement */
-		usleep_range(5000, 5010);
-	} else {
-		gpio_direction_output(pdata->hph_en1_gpio, 0);
-	}
-	snd_soc_dapm_sync(dapm);
-	return 0;
-}
-
-static int msm8996_hifi_get(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm_hifi_control = %d\n",
-			 __func__, msm_hifi_control);
-	ucontrol->value.integer.value[0] = msm_hifi_control;
-	return 0;
-}
-
-static int msm8996_hifi_put(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
-
-	pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n",
-		 __func__, ucontrol->value.integer.value[0]);
-
-	msm_hifi_control = ucontrol->value.integer.value[0];
-	msm8996_hifi_ctrl(codec);
-	return 1;
-}
-
-static int msm8996_ext_us_amp_init(void)
-{
-	int ret = 0;
-
-	ext_us_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
-				"qcom,ext-ult-spk-amp-gpio", 0);
-	if (ext_us_amp_gpio >= 0) {
-		ret = gpio_request(ext_us_amp_gpio, "ext_us_amp_gpio");
-		if (ret) {
-			pr_err("%s: ext_us_amp_gpio request failed, ret:%d\n",
-				__func__, ret);
-			return ret;
-		}
-		gpio_direction_output(ext_us_amp_gpio, 0);
-	}
-	return ret;
-}
-
-static void msm8996_ext_us_amp_enable(u32 on)
-{
-	if (on)
-		gpio_direction_output(ext_us_amp_gpio, 1);
-	else
-		gpio_direction_output(ext_us_amp_gpio, 0);
-
-	pr_debug("%s: US Emitter GPIO enable:%s\n", __func__,
-			on ? "Enable" : "Disable");
-}
-
-static int msm_ext_ultrasound_event(struct snd_soc_dapm_widget *w,
-				    struct snd_kcontrol *k, int event)
-{
-	pr_debug("%s()\n", __func__);
-	if (strcmp(w->name, "ultrasound amp")) {
-		if (!gpio_is_valid(ext_us_amp_gpio)) {
-			pr_err("%s: ext_us_amp_gpio isn't configured\n",
-				__func__);
-			return -EINVAL;
-		}
-		if (SND_SOC_DAPM_EVENT_ON(event))
-			msm8996_ext_us_amp_enable(1);
-		else
-			msm8996_ext_us_amp_enable(0);
-	} else {
-		pr_err("%s() Invalid Widget = %s\n",
-				__func__, w->name);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
-					int enable, bool dapm)
-{
-	int ret = 0;
-
-	if (!strcmp(dev_name(codec->dev), "tasha_codec")) {
-		ret = tasha_cdc_mclk_enable(codec, enable, dapm);
-	} else {
-		dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
-			__func__);
-		ret = -EINVAL;
-	}
-
-	return ret;
-}
-
-static int msm8996_mclk_event(struct snd_soc_dapm_widget *w,
-				 struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-	pr_debug("%s: event = %d\n", __func__, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		return msm_snd_enable_codec_ext_clk(codec, 1, true);
-	case SND_SOC_DAPM_POST_PMD:
-		return msm_snd_enable_codec_ext_clk(codec, 0, true);
-	}
-	return 0;
-}
-
-static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_codec *codec,
-					   int enable, bool dapm)
-{
-	int ret = 0;
-
-	if (!strcmp(dev_name(codec->dev), "tasha_codec"))
-		ret = tasha_cdc_mclk_tx_enable(codec, enable, dapm);
-	else {
-		dev_err(codec->dev, "%s: unknown codec to enable ext clk\n",
-			__func__);
-		ret = -EINVAL;
-	}
-	return ret;
-}
-
-static int msm8996_mclk_tx_event(struct snd_soc_dapm_widget *w,
-				 struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-	pr_debug("%s: event = %d\n", __func__, event);
-
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		return msm_snd_enable_codec_ext_tx_clk(codec, 1, true);
-	case SND_SOC_DAPM_POST_PMD:
-		return msm_snd_enable_codec_ext_tx_clk(codec, 0, true);
-	}
-	return 0;
-}
-
-static int msm_hifi_ctrl_event(struct snd_soc_dapm_widget *w,
-				    struct snd_kcontrol *k, int event)
-{
-	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-	struct snd_soc_card *card = codec->component.card;
-	struct msm8996_asoc_mach_data *pdata =
-				snd_soc_card_get_drvdata(card);
-	int ret = 0;
-
-	pr_debug("%s: msm_hifi_control = %d", __func__,
-		 msm_hifi_control);
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		if (msm_hifi_control == MSM8996_HIFI_ON) {
-			if (pdata->hph_en0_gpio < 0) {
-				pr_err("%s: hph_en0_gpio is invalid\n",
-					__func__);
-				ret = -EINVAL;
-				goto err;
-			}
-			gpio_direction_output(pdata->hph_en0_gpio, 1);
-		}
-		break;
-	case SND_SOC_DAPM_PRE_PMD:
-		if (msm_hifi_control == MSM8996_HIFI_ON) {
-			if (pdata->hph_en0_gpio < 0) {
-				pr_err("%s: hph_en0_gpio is invalid\n",
-					__func__);
-				ret = -EINVAL;
-				goto err;
-			}
-			gpio_direction_output(pdata->hph_en0_gpio, 0);
-		}
-		break;
-	}
-err:
-	return ret;
-}
-
-static const struct snd_soc_dapm_widget msm8996_dapm_widgets[] = {
-
-	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
-	msm8996_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SUPPLY("MCLK TX",  SND_SOC_NOPM, 0, 0,
-	msm8996_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
-	SND_SOC_DAPM_SPK("Lineout_1 amp", NULL),
-	SND_SOC_DAPM_SPK("Lineout_3 amp", NULL),
-	SND_SOC_DAPM_SPK("Lineout_2 amp", NULL),
-	SND_SOC_DAPM_SPK("Lineout_4 amp", NULL),
-	SND_SOC_DAPM_SPK("ultrasound amp", msm_ext_ultrasound_event),
-	SND_SOC_DAPM_SPK("hifi amp", msm_hifi_ctrl_event),
-	SND_SOC_DAPM_MIC("Handset Mic", NULL),
-	SND_SOC_DAPM_MIC("Headset Mic", NULL),
-	SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
-	SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
-	SND_SOC_DAPM_MIC("Analog Mic4", NULL),
-	SND_SOC_DAPM_MIC("Analog Mic6", NULL),
-	SND_SOC_DAPM_MIC("Analog Mic7", NULL),
-	SND_SOC_DAPM_MIC("Analog Mic8", NULL),
-
-	SND_SOC_DAPM_MIC("Digital Mic0", NULL),
-	SND_SOC_DAPM_MIC("Digital Mic1", NULL),
-	SND_SOC_DAPM_MIC("Digital Mic2", NULL),
-	SND_SOC_DAPM_MIC("Digital Mic3", NULL),
-	SND_SOC_DAPM_MIC("Digital Mic4", NULL),
-	SND_SOC_DAPM_MIC("Digital Mic5", NULL),
-	SND_SOC_DAPM_MIC("Digital Mic6", NULL),
-};
-
-static struct snd_soc_dapm_route wcd9335_audio_paths[] = {
-	{"MIC BIAS1", NULL, "MCLK TX"},
-	{"MIC BIAS2", NULL, "MCLK TX"},
-	{"MIC BIAS3", NULL, "MCLK TX"},
-	{"MIC BIAS4", NULL, "MCLK TX"},
-};
-
-static int slim5_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	int sample_rate_val = 0;
-
-	switch (slim5_rx_sample_rate) {
-	case SAMPLING_RATE_44P1KHZ:
-		sample_rate_val = 3;
-		break;
-
-	case SAMPLING_RATE_192KHZ:
-		sample_rate_val = 2;
-		break;
-
-	case SAMPLING_RATE_96KHZ:
-		sample_rate_val = 1;
-		break;
-
-	case SAMPLING_RATE_48KHZ:
-	default:
-		sample_rate_val = 0;
-		break;
-	}
-
-	ucontrol->value.integer.value[0] = sample_rate_val;
-	pr_debug("%s: slim5_rx_sample_rate = %d\n", __func__,
-		 slim5_rx_sample_rate);
-
-	return 0;
-}
-
-static int slim5_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: ucontrol value = %ld\n", __func__,
-		 ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 3:
-		slim5_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
-		break;
-	case 2:
-		slim5_rx_sample_rate = SAMPLING_RATE_192KHZ;
-		break;
-	case 1:
-		slim5_rx_sample_rate = SAMPLING_RATE_96KHZ;
-		break;
-	case 0:
-	default:
-		slim5_rx_sample_rate = SAMPLING_RATE_48KHZ;
-	}
-
-	pr_debug("%s: slim5_rx_sample_rate = %d\n", __func__,
-		 slim5_rx_sample_rate);
-
-	return 0;
-}
-
-static int slim6_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
-				     struct snd_ctl_elem_value *ucontrol)
-{
-	int sample_rate_val = 0;
-
-	switch (slim6_rx_sample_rate) {
-	case SAMPLING_RATE_44P1KHZ:
-		sample_rate_val = 3;
-		break;
-
-	case SAMPLING_RATE_192KHZ:
-		sample_rate_val = 2;
-		break;
-
-	case SAMPLING_RATE_96KHZ:
-		sample_rate_val = 1;
-		break;
-
-	case SAMPLING_RATE_48KHZ:
-	default:
-		sample_rate_val = 0;
-		break;
-	}
-
-	ucontrol->value.integer.value[0] = sample_rate_val;
-	pr_debug("%s: slim6_rx_sample_rate = %d\n", __func__,
-		 slim6_rx_sample_rate);
-
-	return 0;
-}
-
-static int slim6_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 3:
-		slim6_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
-		break;
-	case 2:
-		slim6_rx_sample_rate = SAMPLING_RATE_192KHZ;
-		break;
-	case 1:
-		slim6_rx_sample_rate = SAMPLING_RATE_96KHZ;
-		break;
-	case 0:
-	default:
-		slim6_rx_sample_rate = SAMPLING_RATE_48KHZ;
-		break;
-	}
-
-	pr_debug("%s: ucontrol value = %ld, slim6_rx_sample_rate = %d\n",
-		 __func__, ucontrol->value.integer.value[0],
-		 slim6_rx_sample_rate);
-
-	return 0;
-}
-
-static int slim0_tx_bit_format_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	switch (slim0_tx_bit_format) {
-	case SNDRV_PCM_FORMAT_S24_3LE:
-		ucontrol->value.integer.value[0] = 2;
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		ucontrol->value.integer.value[0] = 1;
-		break;
-	case SNDRV_PCM_FORMAT_S16_LE:
-	default:
-		ucontrol->value.integer.value[0] = 0;
-		break;
-	}
-
-	pr_debug("%s: slim0_tx_bit_format = %d, ucontrol value = %ld\n",
-			 __func__, slim0_tx_bit_format,
-			ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int slim0_tx_bit_format_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	int rc = 0;
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 2:
-		slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
-		break;
-	case 1:
-		slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
-		break;
-	case 0:
-		slim0_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-		break;
-	default:
-		pr_err("%s: invalid value %ld\n", __func__,
-		       ucontrol->value.integer.value[0]);
-		rc = -EINVAL;
-		break;
-	}
-
-	pr_debug("%s: ucontrol value = %ld, slim0_tx_bit_format = %d\n",
-		 __func__, ucontrol->value.integer.value[0],
-		 slim0_tx_bit_format);
-
-	return rc;
-}
-
-static int slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	int sample_rate_val = 0;
-
-	switch (slim0_rx_sample_rate) {
-	case SAMPLING_RATE_32KHZ:
-		sample_rate_val = 6;
-		break;
-
-	case SAMPLING_RATE_16KHZ:
-		sample_rate_val = 5;
-		break;
-
-	case SAMPLING_RATE_8KHZ:
-		sample_rate_val = 4;
-		break;
-
-	case SAMPLING_RATE_44P1KHZ:
-		sample_rate_val = 3;
-		break;
-
-	case SAMPLING_RATE_192KHZ:
-		sample_rate_val = 2;
-		break;
-
-	case SAMPLING_RATE_96KHZ:
-		sample_rate_val = 1;
-		break;
-
-	case SAMPLING_RATE_48KHZ:
-	default:
-		sample_rate_val = 0;
-		break;
-	}
-
-	ucontrol->value.integer.value[0] = sample_rate_val;
-	pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
-		 slim0_rx_sample_rate);
-
-	return 0;
-}
-
-static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: ucontrol value = %ld\n", __func__,
-		 ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 6:
-		slim0_rx_sample_rate = SAMPLING_RATE_32KHZ;
-		break;
-	case 5:
-		slim0_rx_sample_rate = SAMPLING_RATE_16KHZ;
-		break;
-	case 4:
-		slim0_rx_sample_rate = SAMPLING_RATE_8KHZ;
-		break;
-	case 3:
-		slim0_rx_sample_rate = SAMPLING_RATE_44P1KHZ;
-		break;
-	case 2:
-		slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
-		break;
-	case 1:
-		slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
-		break;
-	case 0:
-	default:
-		slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
-	}
-
-	pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
-		 slim0_rx_sample_rate);
-
-	return 0;
-}
-
-static int slim0_tx_sample_rate_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	int sample_rate_val = 0;
-
-	switch (slim0_tx_sample_rate) {
-	case SAMPLING_RATE_192KHZ:
-		sample_rate_val = 2;
-		break;
-	case SAMPLING_RATE_96KHZ:
-		sample_rate_val = 1;
-		break;
-	case SAMPLING_RATE_48KHZ:
-	default:
-		sample_rate_val = 0;
-		break;
-	}
-
-	ucontrol->value.integer.value[0] = sample_rate_val;
-	pr_debug("%s: slim0_tx_sample_rate = %d\n", __func__,
-				slim0_tx_sample_rate);
-	return 0;
-}
-
-static int slim0_tx_sample_rate_put(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	int rc = 0;
-
-	pr_debug("%s: ucontrol value = %ld\n", __func__,
-			ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 2:
-		slim0_tx_sample_rate = SAMPLING_RATE_192KHZ;
-		break;
-	case 1:
-		slim0_tx_sample_rate = SAMPLING_RATE_96KHZ;
-		break;
-	case 0:
-		slim0_tx_sample_rate = SAMPLING_RATE_48KHZ;
-		break;
-	default:
-		rc = -EINVAL;
-		pr_err("%s: invalid sample rate being passed\n", __func__);
-		break;
-	}
-
-	pr_debug("%s: slim0_tx_sample_rate = %d\n", __func__,
-			slim0_tx_sample_rate);
-	return rc;
-}
-
-static int slim5_rx_bit_format_get(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-
-	switch (slim5_rx_bit_format) {
-	case SNDRV_PCM_FORMAT_S24_3LE:
-		ucontrol->value.integer.value[0] = 2;
-		break;
-
-	case SNDRV_PCM_FORMAT_S24_LE:
-		ucontrol->value.integer.value[0] = 1;
-		break;
-
-	case SNDRV_PCM_FORMAT_S16_LE:
-	default:
-		ucontrol->value.integer.value[0] = 0;
-		break;
-	}
-
-	pr_debug("%s: slim5_rx_bit_format = %d, ucontrol value = %ld\n",
-		 __func__, slim5_rx_bit_format,
-			ucontrol->value.integer.value[0]);
-
-	return 0;
-}
-
-static int slim5_rx_bit_format_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 2:
-		slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
-		break;
-	case 1:
-		slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
-		break;
-	case 0:
-	default:
-		slim5_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-		break;
-	}
-	return 0;
-}
-
-static int slim6_rx_bit_format_get(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-
-	switch (slim6_rx_bit_format) {
-	case SNDRV_PCM_FORMAT_S24_3LE:
-		ucontrol->value.integer.value[0] = 2;
-		break;
-
-	case SNDRV_PCM_FORMAT_S24_LE:
-		ucontrol->value.integer.value[0] = 1;
-		break;
-
-	case SNDRV_PCM_FORMAT_S16_LE:
-	default:
-		ucontrol->value.integer.value[0] = 0;
-		break;
-	}
-
-	pr_debug("%s: slim6_rx_bit_format = %d, ucontrol value = %ld\n",
-		 __func__, slim6_rx_bit_format,
-		 ucontrol->value.integer.value[0]);
-
-	return 0;
-}
-
-static int slim6_rx_bit_format_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 2:
-		slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
-		break;
-	case 1:
-		slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
-		break;
-	case 0:
-	default:
-		slim6_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-		break;
-	}
-	return 0;
-}
-
-static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-
-	switch (slim0_rx_bit_format) {
-	case SNDRV_PCM_FORMAT_S24_3LE:
-		ucontrol->value.integer.value[0] = 2;
-		break;
-
-	case SNDRV_PCM_FORMAT_S24_LE:
-		ucontrol->value.integer.value[0] = 1;
-		break;
-
-	case SNDRV_PCM_FORMAT_S16_LE:
-	default:
-		ucontrol->value.integer.value[0] = 0;
-		break;
-	}
-
-	pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
-		 __func__, slim0_rx_bit_format,
-			ucontrol->value.integer.value[0]);
-
-	return 0;
-}
-
-static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 2:
-		slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
-		break;
-	case 1:
-		slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
-		break;
-	case 0:
-	default:
-		slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-		break;
-	}
-	return 0;
-}
-
-static int msm_slim_5_rx_ch_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm_slim_5_rx_ch  = %d\n", __func__,
-		 msm_slim_5_rx_ch);
-	ucontrol->value.integer.value[0] = msm_slim_5_rx_ch - 1;
-	return 0;
-}
-
-static int msm_slim_5_rx_ch_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	msm_slim_5_rx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s: msm_slim_5_rx_ch = %d\n", __func__,
-		 msm_slim_5_rx_ch);
-	return 1;
-}
-
-static int msm_slim_6_rx_ch_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm_slim_6_rx_ch  = %d\n", __func__,
-		 msm_slim_6_rx_ch);
-	ucontrol->value.integer.value[0] = msm_slim_6_rx_ch - 1;
-	return 0;
-}
-
-static int msm_slim_6_rx_ch_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	msm_slim_6_rx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s: msm_slim_6_rx_ch = %d\n", __func__,
-		 msm_slim_6_rx_ch);
-	return 1;
-}
-
-static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm_slim_0_rx_ch  = %d\n", __func__,
-		 msm_slim_0_rx_ch);
-	ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
-	return 0;
-}
-
-static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
-		 msm_slim_0_rx_ch);
-	return 1;
-}
-
-static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm_slim_0_tx_ch  = %d\n", __func__,
-		 msm_slim_0_tx_ch);
-	ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
-	return 0;
-}
-
-static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
-				struct snd_ctl_elem_value *ucontrol)
-{
-	msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__, msm_slim_0_tx_ch);
-	return 1;
-}
-
-static int msm_slim_1_tx_ch_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm_slim_1_tx_ch  = %d\n", __func__,
-		 msm_slim_1_tx_ch);
-	ucontrol->value.integer.value[0] = msm_slim_1_tx_ch - 1;
-	return 0;
-}
-
-static int msm_slim_1_tx_ch_put(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	msm_slim_1_tx_ch = ucontrol->value.integer.value[0] + 1;
-
-	pr_debug("%s: msm_slim_1_tx_ch = %d\n", __func__, msm_slim_1_tx_ch);
-	return 1;
-}
-
-static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1;
-	pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__,
-		 ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_value *ucontrol)
-{
-	msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1;
-
-	pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch);
-	return 1;
-}
-
-static int hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-
-	switch (hdmi_rx_bit_format) {
-	case SNDRV_PCM_FORMAT_S24_3LE:
-		ucontrol->value.integer.value[0] = 2;
-		break;
-
-	case SNDRV_PCM_FORMAT_S24_LE:
-		ucontrol->value.integer.value[0] = 1;
-		break;
-
-	case SNDRV_PCM_FORMAT_S16_LE:
-	default:
-		ucontrol->value.integer.value[0] = 0;
-		break;
-	}
-
-	pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
-		 __func__, hdmi_rx_bit_format,
-			ucontrol->value.integer.value[0]);
-
-	return 0;
-}
-
-static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 2:
-		hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE;
-		break;
-	case 1:
-		hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
-		break;
-	case 0:
-	default:
-		hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
-		break;
-	}
-	pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
-		 __func__, hdmi_rx_bit_format,
-			ucontrol->value.integer.value[0]);
-	return 0;
-}
-
-static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm_hdmi_rx_ch  = %d\n", __func__,
-		 msm_hdmi_rx_ch);
-	ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
-
-	return 0;
-}
-
-static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol)
-{
-	msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
-	if (msm_hdmi_rx_ch > 8) {
-		pr_err("%s: channels %d exceeded 8.Limiting to max chs-8\n",
-			__func__, msm_hdmi_rx_ch);
-		msm_hdmi_rx_ch = 8;
-	}
-	pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, msm_hdmi_rx_ch);
-
-	return 1;
-}
-
-static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	int sample_rate_val = 0;
-
-	switch (hdmi_rx_sample_rate) {
-	case SAMPLING_RATE_192KHZ:
-		sample_rate_val = 2;
-		break;
-
-	case SAMPLING_RATE_96KHZ:
-		sample_rate_val = 1;
-		break;
-
-	case SAMPLING_RATE_48KHZ:
-	default:
-		sample_rate_val = 0;
-		break;
-	}
-
-	ucontrol->value.integer.value[0] = sample_rate_val;
-	pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
-		 hdmi_rx_sample_rate);
-
-	return 0;
-}
-
-static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: ucontrol value = %ld\n", __func__,
-		 ucontrol->value.integer.value[0]);
-
-	switch (ucontrol->value.integer.value[0]) {
-	case 2:
-		hdmi_rx_sample_rate = SAMPLING_RATE_192KHZ;
-		break;
-	case 1:
-		hdmi_rx_sample_rate = SAMPLING_RATE_96KHZ;
-		break;
-	case 0:
-	default:
-		hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ;
-	}
-
-	pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
-		 hdmi_rx_sample_rate);
-
-	return 0;
-}
-
-static int msm8996_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
-				      struct snd_ctl_elem_value *ucontrol)
-{
-	ucontrol->value.integer.value[0] = msm8996_auxpcm_rate;
-	return 0;
-}
-
-static int msm8996_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
-				      struct snd_ctl_elem_value *ucontrol)
-{
-	switch (ucontrol->value.integer.value[0]) {
-	case 0:
-		msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
-		break;
-	case 1:
-		msm8996_auxpcm_rate = SAMPLING_RATE_16KHZ;
-		break;
-	default:
-		msm8996_auxpcm_rate = SAMPLING_RATE_8KHZ;
-		break;
-	}
-	return 0;
-}
-
-static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, msm_proxy_rx_ch);
-	ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1;
-	return 0;
-}
-
-static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1;
-	pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__, msm_proxy_rx_ch);
-	return 1;
-}
-
-static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
-				      struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate =
-	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-
-	struct snd_interval *channels =
-	    hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	rate->min = rate->max = msm8996_auxpcm_rate;
-	channels->min = channels->max = 1;
-
-	return 0;
-}
-
-static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					   struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
-
-	if (channels->max < 2)
-		channels->min = channels->max = 2;
-	channels->min = channels->max = msm_proxy_rx_ch;
-	rate->min = rate->max = SAMPLING_RATE_48KHZ;
-	return 0;
-}
-
-static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					   struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-
-	rate->min = rate->max = SAMPLING_RATE_48KHZ;
-	return 0;
-}
-
-static int msm8996_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					      struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
-		 channels->min, channels->max);
-
-	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
-				hdmi_rx_bit_format);
-	if (channels->max < 2)
-		channels->min = channels->max = 2;
-	rate->min = rate->max = hdmi_rx_sample_rate;
-	channels->min = channels->max = msm_hdmi_rx_ch;
-
-	return 0;
-}
-
-static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-				     struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	pr_debug("%s: channel:%d\n", __func__, msm_tert_mi2s_tx_ch);
-	rate->min = rate->max = SAMPLING_RATE_48KHZ;
-	channels->min = channels->max = msm_tert_mi2s_tx_ch;
-	return 0;
-}
-
-static int msm8996_mi2s_snd_startup(struct snd_pcm_substream *substream)
-{
-	int ret = 0;
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s: substream = %s  stream = %d\n", __func__,
-		 substream->name, substream->stream);
-
-	mi2s_tx_clk.enable = 1;
-	ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX,
-				&mi2s_tx_clk);
-	if (ret < 0) {
-		pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret);
-		goto err;
-	}
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
-	if (ret < 0)
-		pr_err("%s: set fmt cpu dai failed, err:%d\n", __func__, ret);
-err:
-	return ret;
-}
-
-static void msm8996_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
-{
-	int ret = 0;
-
-	pr_debug("%s: substream = %s  stream = %d\n", __func__,
-		substream->name, substream->stream);
-
-	mi2s_tx_clk.enable = 0;
-	ret = afe_set_lpass_clock_v2(AFE_PORT_ID_TERTIARY_MI2S_TX,
-				&mi2s_tx_clk);
-	if (ret < 0)
-		pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret);
-}
-
-static struct snd_soc_ops msm8996_mi2s_be_ops = {
-	.startup = msm8996_mi2s_snd_startup,
-	.shutdown = msm8996_mi2s_snd_shutdown,
-};
-
-static int msm_slim_5_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					    struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
-				   slim5_rx_bit_format);
-	rate->min = rate->max = slim5_rx_sample_rate;
-	channels->min = channels->max = msm_slim_5_rx_ch;
-
-	 pr_debug("%s: format = %d, rate = %d, channels = %d\n",
-		  __func__, params_format(params), params_rate(params),
-		  msm_slim_5_rx_ch);
-
-	return 0;
-}
-
-static int msm_slim_6_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					    struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
-				   slim6_rx_bit_format);
-	rate->min = rate->max = slim6_rx_sample_rate;
-	channels->min = channels->max = msm_slim_6_rx_ch;
-
-	pr_debug("%s: format = %d, rate = %d, channels = %d\n",
-		 __func__, params_format(params), params_rate(params),
-		 msm_slim_6_rx_ch);
-
-	return 0;
-}
-
-static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					    struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
-				   slim0_rx_bit_format);
-	rate->min = rate->max = slim0_rx_sample_rate;
-	channels->min = channels->max = msm_slim_0_rx_ch;
-
-	 pr_debug("%s: format = %d, rate = %d, channels = %d\n",
-		  __func__, params_format(params), params_rate(params),
-		  msm_slim_0_rx_ch);
-
-	return 0;
-}
-
-static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					    struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	pr_debug("%s()\n", __func__);
-	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, slim0_tx_bit_format);
-	rate->min = rate->max = slim0_tx_sample_rate;
-	channels->min = channels->max = msm_slim_0_tx_ch;
-
-	return 0;
-}
-
-static int msm_slim_1_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					    struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	pr_debug("%s()\n", __func__);
-	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, slim1_tx_bit_format);
-	rate->min = rate->max = slim1_tx_sample_rate;
-	channels->min = channels->max = msm_slim_1_tx_ch;
-
-	return 0;
-}
-
-static int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					    struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
-		       SNDRV_PCM_FORMAT_S32_LE);
-
-	rate->min = rate->max = SAMPLING_RATE_8KHZ;
-	channels->min = channels->max = msm_vi_feed_tx_ch;
-	pr_debug("%s: msm_vi_feed_tx_ch: %d\n", __func__, msm_vi_feed_tx_ch);
-
-	return 0;
-}
-
-static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-					    struct snd_pcm_hw_params *params)
-{
-	int rc = 0;
-	void *config = NULL;
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	pr_debug("%s: enter\n", __func__);
-	rate->min = rate->max = SAMPLING_RATE_16KHZ;
-	channels->min = channels->max = 1;
-
-	config = msm8996_codec_fn.get_afe_config_fn(codec,
-				AFE_SLIMBUS_SLAVE_PORT_CONFIG);
-	if (config) {
-		rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
-				    SLIMBUS_5_TX);
-		if (rc) {
-			pr_err("%s: Failed to set slimbus slave port config %d\n",
-				__func__, rc);
-		}
-	}
-
-	return rc;
-}
-
-static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-				  struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-
-	pr_debug("%s:\n", __func__);
-	rate->min = rate->max = SAMPLING_RATE_48KHZ;
-	return 0;
-}
-
-static const struct soc_enum msm_snd_enum[] = {
-	SOC_ENUM_SINGLE_EXT(2, spk_function),
-	SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
-	SOC_ENUM_SINGLE_EXT(8, slim0_tx_ch_text),
-	SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_bit_format_text),
-			    rx_bit_format_text),
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim0_rx_sample_rate_text),
-			    slim0_rx_sample_rate_text),
-	SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
-	SOC_ENUM_SINGLE_EXT(3, hdmi_rx_sample_rate_text),
-	SOC_ENUM_SINGLE_EXT(4, slim5_rx_sample_rate_text),
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim5_rx_bit_format_text),
-			    slim5_rx_bit_format_text),
-	SOC_ENUM_SINGLE_EXT(2, slim5_rx_ch_text),
-	SOC_ENUM_SINGLE_EXT(2, hifi_function),
-	SOC_ENUM_SINGLE_EXT(2, vi_feed_ch_text),
-	SOC_ENUM_SINGLE_EXT(4, slim6_rx_sample_rate_text),
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim6_rx_bit_format_text),
-			    slim6_rx_bit_format_text),
-	SOC_ENUM_SINGLE_EXT(2, slim6_rx_ch_text),
-};
-
-static const struct snd_kcontrol_new msm_snd_controls[] = {
-	SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8996_get_spk,
-			msm8996_set_spk),
-	SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
-			msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
-	SOC_ENUM_EXT("SLIM_5_RX Channels", msm_snd_enum[10],
-			msm_slim_5_rx_ch_get, msm_slim_5_rx_ch_put),
-	SOC_ENUM_EXT("SLIM_6_RX Channels", msm_snd_enum[15],
-			msm_slim_6_rx_ch_get, msm_slim_6_rx_ch_put),
-	SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
-			msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
-	SOC_ENUM_EXT("SLIM_1_TX Channels", msm_snd_enum[2],
-			msm_slim_1_tx_ch_get, msm_slim_1_tx_ch_put),
-	SOC_ENUM_EXT("AUX PCM SampleRate", msm8996_auxpcm_enum[0],
-			msm8996_auxpcm_rate_get,
-			msm8996_auxpcm_rate_put),
-	SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
-			msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
-	SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
-			slim0_rx_bit_format_get, slim0_rx_bit_format_put),
-	SOC_ENUM_EXT("SLIM_5_RX Format", msm_snd_enum[9],
-			slim5_rx_bit_format_get, slim5_rx_bit_format_put),
-	SOC_ENUM_EXT("SLIM_6_RX Format", msm_snd_enum[14],
-			slim6_rx_bit_format_get, slim6_rx_bit_format_put),
-	SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
-			slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
-	SOC_ENUM_EXT("SLIM_5_RX SampleRate", msm_snd_enum[8],
-			slim5_rx_sample_rate_get, slim5_rx_sample_rate_put),
-	SOC_ENUM_EXT("SLIM_6_RX SampleRate", msm_snd_enum[13],
-			slim6_rx_sample_rate_get, slim6_rx_sample_rate_put),
-	SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
-			hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
-	SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
-			msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
-	SOC_ENUM_EXT("HDMI_RX SampleRate", msm_snd_enum[7],
-			hdmi_rx_sample_rate_get, hdmi_rx_sample_rate_put),
-	SOC_ENUM_EXT("SLIM_0_TX SampleRate", msm_snd_enum[5],
-			slim0_tx_sample_rate_get, slim0_tx_sample_rate_put),
-	SOC_ENUM_EXT("SLIM_0_TX Format", msm_snd_enum[4],
-			slim0_tx_bit_format_get, slim0_tx_bit_format_put),
-	SOC_ENUM_EXT("HiFi Function", msm_snd_enum[11], msm8996_hifi_get,
-			msm8996_hifi_put),
-	SOC_ENUM_EXT("VI_FEED_TX Channels", msm_snd_enum[12],
-			msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put),
-};
-
-static bool msm8996_swap_gnd_mic(struct snd_soc_codec *codec)
-{
-	struct snd_soc_card *card = codec->component.card;
-	struct msm8996_asoc_mach_data *pdata =
-				snd_soc_card_get_drvdata(card);
-	int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
-
-	pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
-	gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
-	return true;
-}
-
-static int msm_afe_set_config(struct snd_soc_codec *codec)
-{
-	int rc;
-	void *config_data = NULL;
-
-	pr_debug("%s: enter\n", __func__);
-
-	if (!msm8996_codec_fn.get_afe_config_fn) {
-		dev_err(codec->dev, "%s: codec get afe config not init'ed\n",
-			__func__);
-		return -EINVAL;
-	}
-
-	config_data = msm8996_codec_fn.get_afe_config_fn(codec,
-			AFE_CDC_REGISTERS_CONFIG);
-	if (config_data) {
-		rc = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
-		if (rc) {
-			pr_err("%s: Failed to set codec registers config %d\n",
-					__func__, rc);
-			return rc;
-		}
-	}
-
-	config_data = msm8996_codec_fn.get_afe_config_fn(codec,
-			AFE_CDC_REGISTER_PAGE_CONFIG);
-	if (config_data) {
-		rc = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data,
-				    0);
-		if (rc)
-			pr_err("%s: Failed to set cdc register page config\n",
-				__func__);
-	}
-
-	config_data = msm8996_codec_fn.get_afe_config_fn(codec,
-			AFE_SLIMBUS_SLAVE_CONFIG);
-	if (config_data) {
-		rc = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
-		if (rc) {
-			pr_err("%s: Failed to set slimbus slave config %d\n",
-					__func__, rc);
-			return rc;
-		}
-	}
-
-	return 0;
-}
-
-static void msm_afe_clear_config(void)
-{
-	afe_clear_config(AFE_CDC_REGISTERS_CONFIG);
-	afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG);
-}
-
-static int  msm8996_adsp_state_callback(struct notifier_block *nb,
-					   unsigned long value, void *priv)
-{
-	if (value == SUBSYS_BEFORE_SHUTDOWN) {
-		pr_debug("%s: ADSP is about to shutdown. Clearing AFE config\n",
-			 __func__);
-		msm_afe_clear_config();
-	} else if (value == SUBSYS_AFTER_POWERUP) {
-		pr_debug("%s: ADSP is up\n", __func__);
-	}
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block adsp_state_notifier_block = {
-	.notifier_call = msm8996_adsp_state_callback,
-	.priority = -INT_MAX,
-};
-
-static int msm8996_wcd93xx_codec_up(struct snd_soc_codec *codec)
-{
-	int err;
-	unsigned long timeout;
-	int adsp_ready = 0;
-
-	timeout = jiffies +
-		msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
-
-	do {
-		if (!q6core_is_adsp_ready()) {
-			pr_err_ratelimited("%s: ADSP Audio isn't ready\n",
-					   __func__);
-			/*
-			 * ADSP will be coming up after subsystem restart and
-			 * it might not be fully up when the control reaches
-			 * here. So, wait for 50msec before checking ADSP state
-			 */
-			msleep(50);
-		} else {
-			pr_debug("%s: ADSP Audio is ready\n", __func__);
-			adsp_ready = 1;
-			break;
-		}
-	} while (time_after(timeout, jiffies));
-
-	if (!adsp_ready) {
-		pr_err("%s: timed out waiting for ADSP Audio\n", __func__);
-		return -ETIMEDOUT;
-	}
-
-	err = msm_afe_set_config(codec);
-	if (err)
-		pr_err("%s: Failed to set AFE config. err %d\n",
-			__func__, err);
-	return err;
-}
-
-static int msm8996_tasha_codec_event_cb(struct snd_soc_codec *codec,
-					enum wcd9335_codec_event codec_event)
-{
-	switch (codec_event) {
-	case WCD9335_CODEC_EVENT_CODEC_UP:
-		return msm8996_wcd93xx_codec_up(codec);
-	default:
-		pr_err("%s: UnSupported codec event %d\n",
-			__func__, codec_event);
-		return -EINVAL;
-	}
-}
-
-static int msm8996_config_hph_en0_gpio(struct snd_soc_codec *codec, bool high)
-{
-	struct snd_soc_card *card = codec->component.card;
-	struct msm8996_asoc_mach_data *pdata;
-	int val;
-
-	if (!card)
-		return 0;
-
-	pdata = snd_soc_card_get_drvdata(card);
-	if (!pdata || !gpio_is_valid(pdata->hph_en0_gpio))
-		return 0;
-
-	val = gpio_get_value_cansleep(pdata->hph_en0_gpio);
-	if ((!!val) == high)
-		return 0;
-
-	gpio_direction_output(pdata->hph_en0_gpio, (int)high);
-
-	return 1;
-}
-
-static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
-{
-	int err;
-	void *config_data;
-	struct snd_soc_codec *codec = rtd->codec;
-	struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_component *aux_comp;
-	void *mbhc_calibration;
-	struct snd_card *card;
-	struct snd_info_entry *entry;
-	struct msm8996_asoc_mach_data *pdata =
-				snd_soc_card_get_drvdata(rtd->card);
-
-	/* Codec SLIMBUS configuration
-	 * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
-	 * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
-	 * TX14, TX15, TX16
-	 */
-	unsigned int rx_ch[TASHA_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
-					    151, 152, 153, 154, 155, 156};
-	unsigned int tx_ch[TASHA_TX_MAX] = {128, 129, 130, 131, 132, 133,
-					    134, 135, 136, 137, 138, 139,
-					    140, 141, 142, 143};
-
-	pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev));
-
-	rtd->pmdown_time = 0;
-
-	err = snd_soc_add_codec_controls(codec, msm_snd_controls,
-					 ARRAY_SIZE(msm_snd_controls));
-	if (err < 0) {
-		pr_err("%s: add_codec_controls failed, err %d\n",
-			__func__, err);
-		return err;
-	}
-
-	err = msm8996_liquid_init_docking();
-	if (err) {
-		pr_err("%s: 8996 init Docking stat IRQ failed (%d)\n",
-			__func__, err);
-		return err;
-	}
-
-	err = msm8996_ext_us_amp_init();
-	if (err) {
-		pr_err("%s: 8996 US Emitter GPIO init failed (%d)\n",
-			__func__, err);
-		return err;
-	}
-
-	snd_soc_dapm_new_controls(dapm, msm8996_dapm_widgets,
-				ARRAY_SIZE(msm8996_dapm_widgets));
-
-	snd_soc_dapm_add_routes(dapm, wcd9335_audio_paths,
-				ARRAY_SIZE(wcd9335_audio_paths));
-	snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
-	snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
-	snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
-	snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
-
-	snd_soc_dapm_ignore_suspend(dapm, "Lineout_1 amp");
-	snd_soc_dapm_ignore_suspend(dapm, "Lineout_3 amp");
-	snd_soc_dapm_ignore_suspend(dapm, "Lineout_2 amp");
-	snd_soc_dapm_ignore_suspend(dapm, "Lineout_4 amp");
-	snd_soc_dapm_ignore_suspend(dapm, "ultrasound amp");
-	snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
-	snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
-	snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic");
-	snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic");
-	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1");
-	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2");
-	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3");
-	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4");
-	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5");
-	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic4");
-	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic6");
-	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic7");
-	snd_soc_dapm_ignore_suspend(dapm, "Analog Mic8");
-	snd_soc_dapm_ignore_suspend(dapm, "MADINPUT");
-	snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT");
-	snd_soc_dapm_ignore_suspend(dapm, "EAR");
-	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1");
-	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2");
-	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT3");
-	snd_soc_dapm_ignore_suspend(dapm, "LINEOUT4");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC EAR");
-	snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
-	snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
-	snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
-	snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
-	snd_soc_dapm_ignore_suspend(dapm, "AMIC5");
-	snd_soc_dapm_ignore_suspend(dapm, "AMIC6");
-	snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
-	snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
-	snd_soc_dapm_ignore_suspend(dapm, "DMIC3");
-	snd_soc_dapm_ignore_suspend(dapm, "DMIC4");
-	snd_soc_dapm_ignore_suspend(dapm, "DMIC5");
-	snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0");
-	snd_soc_dapm_ignore_suspend(dapm, "DMIC0");
-	snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT");
-	snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT");
-	snd_soc_dapm_ignore_suspend(dapm, "HPHL");
-	snd_soc_dapm_ignore_suspend(dapm, "HPHR");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT1");
-	snd_soc_dapm_ignore_suspend(dapm, "ANC LINEOUT2");
-	snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI");
-	snd_soc_dapm_ignore_suspend(dapm, "VIINPUT");
-
-	snd_soc_dapm_sync(dapm);
-
-	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
-				    tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
-
-	msm8996_codec_fn.get_afe_config_fn = tasha_get_afe_config;
-	msm8996_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit;
-
-	err = msm_afe_set_config(codec);
-	if (err) {
-		pr_err("%s: Failed to set AFE config %d\n", __func__, err);
-		goto out;
-	}
-
-	config_data = msm8996_codec_fn.get_afe_config_fn(codec,
-						AFE_AANC_VERSION);
-	if (config_data) {
-		err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
-		if (err) {
-			pr_err("%s: Failed to set aanc version %d\n",
-				__func__, err);
-			goto out;
-		}
-	}
-	config_data = msm8996_codec_fn.get_afe_config_fn(codec,
-					    AFE_CDC_CLIP_REGISTERS_CONFIG);
-	if (config_data) {
-		err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
-				     config_data, 0);
-		if (err) {
-			pr_err("%s: Failed to set clip registers %d\n",
-				__func__, err);
-			goto out;
-		}
-	}
-	config_data = msm8996_codec_fn.get_afe_config_fn(codec,
-			AFE_CLIP_BANK_SEL);
-	if (config_data) {
-		err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
-		if (err) {
-			pr_err("%s: Failed to set AFE bank selection %d\n",
-				__func__, err);
-			goto out;
-		}
-	}
-	/* Start mbhc */
-	tasha_mbhc_zdet_gpio_ctrl(msm8996_config_hph_en0_gpio, rtd->codec);
-	mbhc_calibration = def_tasha_mbhc_cal();
-	if (mbhc_calibration) {
-		wcd_mbhc_cfg.calibration = mbhc_calibration;
-		err = tasha_mbhc_hs_detect(codec, &wcd_mbhc_cfg);
-		if (err) {
-			pr_err("%s: mbhc hs detect failed, err:%d\n",
-				__func__, err);
-			goto out;
-		}
-	} else {
-		pr_err("%s: mbhc_cfg calibration is NULL\n", __func__);
-		err = -ENOMEM;
-		goto out;
-	}
-	adsp_state_notifier = subsys_notif_register_notifier("adsp",
-						&adsp_state_notifier_block);
-	if (!adsp_state_notifier) {
-		pr_err("%s: Failed to register adsp state notifier\n",
-		       __func__);
-		err = -EFAULT;
-		msm8996_codec_fn.mbhc_hs_detect_exit(codec);
-		goto out;
-	}
-
-	tasha_event_register(msm8996_tasha_codec_event_cb, rtd->codec);
-
-	/*
-	 * Send speaker configuration only for WSA8810.
-	 * Defalut configuration is for WSA8815.
-	 */
-	if (!list_empty(&rtd->card->aux_comp_list)) {
-		aux_comp = list_first_entry(&rtd->card->aux_comp_list,
-				struct snd_soc_component, list_aux);
-		if (!strcmp(aux_comp->name, WSA8810_NAME_1) ||
-		    !strcmp(aux_comp->name, WSA8810_NAME_2)) {
-			tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1);
-			tasha_set_spkr_gain_offset(rtd->codec,
-						   RX_GAIN_OFFSET_M1P5_DB);
-		}
-	}
-	codec_reg_done = true;
-
-	card = rtd->card->snd_card;
-	entry = snd_info_create_subdir(card->module, "codecs",
-					 card->proc_root);
-	if (!entry) {
-		pr_debug("%s: Cannot create codecs module entry\n",
-			 __func__);
-		err = 0;
-		goto out;
-	}
-	pdata->codec_root = entry;
-	tasha_codec_info_create_codec_entry(pdata->codec_root, codec);
-
-	return 0;
-out:
-	return err;
-}
-
-static void *def_tasha_mbhc_cal(void)
-{
-	void *tasha_wcd_cal;
-	struct wcd_mbhc_btn_detect_cfg *btn_cfg;
-	u16 *btn_high;
-
-	tasha_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS,
-				WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL);
-	if (!tasha_wcd_cal)
-		return NULL;
-
-#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tasha_wcd_cal)->X) = (Y))
-	S(v_hs_max, 1500);
-#undef S
-#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal)->X) = (Y))
-	S(num_btn, WCD_MBHC_DEF_BUTTONS);
-#undef S
-
-	btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tasha_wcd_cal);
-	btn_high = ((void *)&btn_cfg->_v_btn_low) +
-		(sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn);
-
-	btn_high[0] = 75;
-	btn_high[1] = 150;
-	btn_high[2] = 237;
-	btn_high[3] = 500;
-	btn_high[4] = 500;
-	btn_high[5] = 500;
-	btn_high[6] = 500;
-	btn_high[7] = 500;
-
-	return tasha_wcd_cal;
-}
-
-static int msm_snd_hw_params(struct snd_pcm_substream *substream,
-			     struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai_link *dai_link = rtd->dai_link;
-
-	int ret = 0;
-	u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
-	u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
-	u32 user_set_tx_ch = 0;
-	u32 rx_ch_count;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		ret = snd_soc_dai_get_channel_map(codec_dai,
-					&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
-		if (ret < 0) {
-			pr_err("%s: failed to get codec chan map, err:%d\n",
-				__func__, ret);
-			goto end;
-		}
-		if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_5_RX) {
-			pr_debug("%s: rx_5_ch=%d\n", __func__,
-				  msm_slim_5_rx_ch);
-			rx_ch_count = msm_slim_5_rx_ch;
-		} else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_6_RX) {
-			pr_debug("%s: rx_6_ch=%d\n", __func__,
-				  msm_slim_6_rx_ch);
-			rx_ch_count = msm_slim_6_rx_ch;
-		} else {
-			pr_debug("%s: rx_0_ch=%d\n", __func__,
-				  msm_slim_0_rx_ch);
-			rx_ch_count = msm_slim_0_rx_ch;
-		}
-		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
-						  rx_ch_count, rx_ch);
-		if (ret < 0) {
-			pr_err("%s: failed to set cpu chan map, err:%d\n",
-				__func__, ret);
-			goto end;
-		}
-	} else {
-
-		pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
-			 codec_dai->name, codec_dai->id, user_set_tx_ch);
-		ret = snd_soc_dai_get_channel_map(codec_dai,
-					 &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
-		if (ret < 0) {
-			pr_err("%s: failed to get codec chan map\n, err:%d\n",
-				__func__, ret);
-			goto end;
-		}
-		/* For <codec>_tx1 case */
-		if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_0_TX)
-			user_set_tx_ch = msm_slim_0_tx_ch;
-		/* For <codec>_tx3 case */
-		else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_1_TX)
-			user_set_tx_ch = msm_slim_1_tx_ch;
-		else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_3_TX)
-			/* DAI 5 is used for external EC reference from codec.
-			 * Since Rx is fed as reference for EC, the config of
-			 * this DAI is based on that of the Rx path.
-			 */
-			user_set_tx_ch = msm_slim_0_rx_ch;
-		else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_4_TX)
-			user_set_tx_ch = msm_vi_feed_tx_ch;
-		else
-			user_set_tx_ch = tx_ch_cnt;
-
-		pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), BE id (%d)\n",
-			 __func__, msm_slim_0_tx_ch, user_set_tx_ch,
-			 tx_ch_cnt, dai_link->id);
-
-		ret = snd_soc_dai_set_channel_map(cpu_dai,
-						  user_set_tx_ch, tx_ch, 0, 0);
-		if (ret < 0) {
-			pr_err("%s: failed to set cpu chan map, err:%d\n",
-				__func__, ret);
-			goto end;
-		}
-	}
-end:
-	return ret;
-}
-
-static int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream,
-				 struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai_link *dai_link = rtd->dai_link;
-
-	int ret = 0;
-	u32 tx_ch[SLIM_MAX_TX_PORTS];
-	u32 tx_ch_cnt = 0;
-	u32 user_set_tx_ch = 0;
-
-	if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
-		pr_err("%s: Invalid stream type %d\n",
-			__func__, substream->stream);
-		ret = -EINVAL;
-		goto end;
-	}
-
-	pr_debug("%s: %s_tx_dai_id_%d\n", __func__,
-		 codec_dai->name, codec_dai->id);
-	ret = snd_soc_dai_get_channel_map(codec_dai,
-				 &tx_ch_cnt, tx_ch, NULL, NULL);
-	if (ret < 0) {
-		pr_err("%s: failed to get codec chan map\n, err:%d\n",
-			__func__, ret);
-		goto end;
-	}
-
-	user_set_tx_ch = tx_ch_cnt;
-
-	pr_debug("%s: tx_ch_cnt(%d) BE id %d\n",
-		 __func__, tx_ch_cnt, dai_link->id);
-
-	ret = snd_soc_dai_set_channel_map(cpu_dai,
-					  user_set_tx_ch, tx_ch, 0, 0);
-	if (ret < 0)
-		pr_err("%s: failed to set cpu chan map, err:%d\n",
-			__func__, ret);
-end:
-	return ret;
-}
-
-static struct snd_soc_ops msm8996_be_ops = {
-	.hw_params = msm_snd_hw_params,
-};
-
-static struct snd_soc_ops msm8996_cpe_ops = {
-	.hw_params = msm_snd_cpe_hw_params,
-};
-
-static int msm8996_slimbus_2_hw_params(struct snd_pcm_substream *substream,
-					  struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	int ret = 0;
-	unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
-	unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
-	unsigned int num_tx_ch = 0;
-	unsigned int num_rx_ch = 0;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		num_rx_ch =  params_channels(params);
-		pr_debug("%s: %s rx_dai_id = %d  num_ch = %d\n", __func__,
-			codec_dai->name, codec_dai->id, num_rx_ch);
-		ret = snd_soc_dai_get_channel_map(codec_dai,
-				&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
-		if (ret < 0) {
-			pr_err("%s: failed to get codec chan map, err:%d\n",
-				__func__, ret);
-			goto end;
-		}
-		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
-				num_rx_ch, rx_ch);
-		if (ret < 0) {
-			pr_err("%s: failed to set cpu chan map, err:%d\n",
-				__func__, ret);
-			goto end;
-		}
-	} else {
-		num_tx_ch =  params_channels(params);
-		pr_debug("%s: %s  tx_dai_id = %d  num_ch = %d\n", __func__,
-			codec_dai->name, codec_dai->id, num_tx_ch);
-		ret = snd_soc_dai_get_channel_map(codec_dai,
-				&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
-		if (ret < 0) {
-			pr_err("%s: failed to get codec chan map, err:%d\n",
-				__func__, ret);
-			goto end;
-		}
-		ret = snd_soc_dai_set_channel_map(cpu_dai,
-				num_tx_ch, tx_ch, 0, 0);
-		if (ret < 0) {
-			pr_err("%s: failed to set cpu chan map, err:%d\n",
-				__func__, ret);
-			goto end;
-		}
-	}
-end:
-	return ret;
-}
-
-static struct snd_soc_ops msm8996_slimbus_2_be_ops = {
-	.hw_params = msm8996_slimbus_2_hw_params,
-};
-
-static int msm8996_get_ll_qos_val(struct snd_pcm_runtime *runtime)
-{
-	int usecs;
-
-	/* take 10% of period time as the deadline */
-	usecs = (100000 / runtime->rate) * runtime->period_size;
-	usecs += ((100000 % runtime->rate) * runtime->period_size) /
-		runtime->rate;
-
-	return usecs;
-}
-
-static int msm8996_mm5_prepare(struct snd_pcm_substream *substream)
-{
-	if (pm_qos_request_active(&substream->latency_pm_qos_req))
-		pm_qos_remove_request(&substream->latency_pm_qos_req);
-	pm_qos_add_request(&substream->latency_pm_qos_req,
-			   PM_QOS_CPU_DMA_LATENCY,
-			   msm8996_get_ll_qos_val(substream->runtime));
-	return 0;
-}
-
-static struct snd_soc_ops msm8996_mm5_ops = {
-	.prepare = msm8996_mm5_prepare,
-};
-
-/* Digital audio interface glue - connects codec <---> CPU */
-static struct snd_soc_dai_link msm8996_common_dai_links[] = {
-	/* FrontEnd DAI Links */
-	{
-		.name = "MSM8996 Media1",
-		.stream_name = "MultiMedia1",
-		.cpu_dai_name = "MultiMedia1",
-		.platform_name = "msm-pcm-dsp.0",
-		.dynamic = 1,
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA1
-	},
-	{
-		.name = "MSM8996 Media2",
-		.stream_name = "MultiMedia2",
-		.cpu_dai_name = "MultiMedia2",
-		.platform_name = "msm-pcm-dsp.0",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA2,
-	},
-	{
-		.name = "VoiceMMode1",
-		.stream_name = "VoiceMMode1",
-		.cpu_dai_name = "VoiceMMode1",
-		.platform_name = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_VOICEMMODE1,
-	},
-	{
-		.name = "MSM VoIP",
-		.stream_name = "VoIP",
-		.cpu_dai_name = "VoIP",
-		.platform_name = "msm-voip-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.id = MSM_FRONTEND_DAI_VOIP,
-	},
-	{
-		.name = "MSM8996 ULL",
-		.stream_name = "MultiMedia3",
-		.cpu_dai_name = "MultiMedia3",
-		.platform_name = "msm-pcm-dsp.2",
-		.dynamic = 1,
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA3,
-	},
-	/* Hostless PCM purpose */
-	{
-		.name = "SLIMBUS_0 Hostless",
-		.stream_name = "SLIMBUS_0 Hostless",
-		.cpu_dai_name = "SLIMBUS0_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		 /* this dailink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "Tertiary MI2S TX_Hostless",
-		.stream_name = "Tertiary MI2S_TX Hostless Capture",
-		.cpu_dai_name = "TERT_MI2S_TX_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "MSM AFE-PCM RX",
-		.stream_name = "AFE-PROXY RX",
-		.cpu_dai_name = "msm-dai-q6-dev.241",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.platform_name = "msm-pcm-afe",
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-	},
-	{
-		.name = "MSM AFE-PCM TX",
-		.stream_name = "AFE-PROXY TX",
-		.cpu_dai_name = "msm-dai-q6-dev.240",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.platform_name  = "msm-pcm-afe",
-		.ignore_suspend = 1,
-	},
-	{
-		.name = "MSM8996 Compress1",
-		.stream_name = "Compress1",
-		.cpu_dai_name = "MultiMedia4",
-		.platform_name = "msm-compress-dsp",
-		.dynamic = 1,
-		.async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA4,
-	},
-	{
-		.name = "AUXPCM Hostless",
-		.stream_name = "AUXPCM Hostless",
-		.cpu_dai_name = "AUXPCM_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "SLIMBUS_1 Hostless",
-		.stream_name = "SLIMBUS_1 Hostless",
-		.cpu_dai_name = "SLIMBUS1_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		 /* this dailink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "SLIMBUS_3 Hostless",
-		.stream_name = "SLIMBUS_3 Hostless",
-		.cpu_dai_name = "SLIMBUS3_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		 /* this dailink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "SLIMBUS_4 Hostless",
-		.stream_name = "SLIMBUS_4 Hostless",
-		.cpu_dai_name = "SLIMBUS4_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		 /* this dailink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "VoLTE",
-		.stream_name = "VoLTE",
-		.cpu_dai_name = "VoLTE",
-		.platform_name = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_VOLTE,
-	},
-	{
-		.name = "MSM8996 LowLatency",
-		.stream_name = "MultiMedia5",
-		.cpu_dai_name = "MultiMedia5",
-		.platform_name = "msm-pcm-dsp.1",
-		.dynamic = 1,
-		.async_ops = ASYNC_DPCM_SND_SOC_PREPARE,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-				SND_SOC_DPCM_TRIGGER_POST},
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA5,
-		.ops = &msm8996_mm5_ops,
-	},
-	{
-		.name = "Listen 1 Audio Service",
-		.stream_name = "Listen 1 Audio Service",
-		.cpu_dai_name = "LSM1",
-		.platform_name = "msm-lsm-client",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
-			     SND_SOC_DPCM_TRIGGER_POST },
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_LSM1,
-	},
-	/* Multiple Tunnel instances */
-	{
-		.name = "MSM8996 Compress2",
-		.stream_name = "Compress2",
-		.cpu_dai_name = "MultiMedia7",
-		.platform_name = "msm-compress-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA7,
-	},
-	{
-		.name = "MSM8996 Compress3",
-		.stream_name = "Compress3",
-		.cpu_dai_name = "MultiMedia10",
-		.platform_name = "msm-compress-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA10,
-	},
-	{
-		.name = "MSM8996 ULL NOIRQ",
-		.stream_name = "MM_NOIRQ",
-		.cpu_dai_name = "MultiMedia8",
-		.platform_name = "msm-pcm-dsp-noirq",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA8,
-	},
-	{
-		.name = "QCHAT",
-		.stream_name = "QCHAT",
-		.cpu_dai_name = "QCHAT",
-		.platform_name = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_QCHAT,
-	},
-	/* HDMI Hostless */
-	{
-		.name = "HDMI_RX_HOSTLESS",
-		.stream_name = "HDMI_RX_HOSTLESS",
-		.cpu_dai_name = "HDMI_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "VoiceMMode2",
-		.stream_name = "VoiceMMode2",
-		.cpu_dai_name = "VoiceMMode2",
-		.platform_name = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_VOICEMMODE2,
-	},
-	{
-		.name = "INT_HFP_BT Hostless",
-		.stream_name = "INT_HFP_BT Hostless",
-		.cpu_dai_name = "INT_HFP_BT_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	{
-		.name = "MSM8996 HFP TX",
-		.stream_name = "MultiMedia6",
-		.cpu_dai_name = "MultiMedia6",
-		.platform_name = "msm-pcm-loopback",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.ignore_suspend = 1,
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA6,
-	},
-	/* LSM FE */
-	{
-		.name = "Listen 2 Audio Service",
-		.stream_name = "Listen 2 Audio Service",
-		.cpu_dai_name = "LSM2",
-		.platform_name = "msm-lsm-client",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
-				 SND_SOC_DPCM_TRIGGER_POST },
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_LSM2,
-	},
-	{
-		.name = "Listen 3 Audio Service",
-		.stream_name = "Listen 3 Audio Service",
-		.cpu_dai_name = "LSM3",
-		.platform_name = "msm-lsm-client",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
-				 SND_SOC_DPCM_TRIGGER_POST },
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_LSM3,
-	},
-	{
-		.name = "Listen 4 Audio Service",
-		.stream_name = "Listen 4 Audio Service",
-		.cpu_dai_name = "LSM4",
-		.platform_name = "msm-lsm-client",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
-				 SND_SOC_DPCM_TRIGGER_POST },
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_LSM4,
-	},
-	{
-		.name = "Listen 5 Audio Service",
-		.stream_name = "Listen 5 Audio Service",
-		.cpu_dai_name = "LSM5",
-		.platform_name = "msm-lsm-client",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
-				 SND_SOC_DPCM_TRIGGER_POST },
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_LSM5,
-	},
-	{
-		.name = "Listen 6 Audio Service",
-		.stream_name = "Listen 6 Audio Service",
-		.cpu_dai_name = "LSM6",
-		.platform_name = "msm-lsm-client",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
-				 SND_SOC_DPCM_TRIGGER_POST },
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_LSM6,
-	},
-	{
-		.name = "Listen 7 Audio Service",
-		.stream_name = "Listen 7 Audio Service",
-		.cpu_dai_name = "LSM7",
-		.platform_name = "msm-lsm-client",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
-				 SND_SOC_DPCM_TRIGGER_POST },
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_LSM7,
-	},
-	{
-		.name = "Listen 8 Audio Service",
-		.stream_name = "Listen 8 Audio Service",
-		.cpu_dai_name = "LSM8",
-		.platform_name = "msm-lsm-client",
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		.trigger = { SND_SOC_DPCM_TRIGGER_POST,
-				 SND_SOC_DPCM_TRIGGER_POST },
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_LSM8,
-	},
-	{
-		.name = "MSM8996 Media9",
-		.stream_name = "MultiMedia9",
-		.cpu_dai_name = "MultiMedia9",
-		.platform_name = "msm-pcm-dsp.0",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-				SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA9,
-	},
-	{
-		.name = "VoWLAN",
-		.stream_name = "VoWLAN",
-		.cpu_dai_name = "VoWLAN",
-		.platform_name = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_VOWLAN,
-	},
-	{
-		.name = "MSM8996 Compress4",
-		.stream_name = "Compress4",
-		.cpu_dai_name = "MultiMedia11",
-		.platform_name = "msm-compress-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA11,
-	},
-	{
-		.name = "MSM8996 Compress5",
-		.stream_name = "Compress5",
-		.cpu_dai_name = "MultiMedia12",
-		.platform_name = "msm-compress-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA12,
-	},
-	{
-		.name = "MSM8996 Compress6",
-		.stream_name = "Compress6",
-		.cpu_dai_name = "MultiMedia13",
-		.platform_name = "msm-compress-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA13,
-	},
-	{
-		.name = "MSM8996 Compress7",
-		.stream_name = "Compress7",
-		.cpu_dai_name = "MultiMedia14",
-		.platform_name = "msm-compress-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA14,
-	},
-	{
-		.name = "MSM8996 Compress8",
-		.stream_name = "Compress8",
-		.cpu_dai_name = "MultiMedia15",
-		.platform_name = "msm-compress-dsp",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA15,
-	},
-	{
-		.name = "MSM8996 ULL NOIRQ_2",
-		.stream_name = "MM_NOIRQ_2",
-		.cpu_dai_name = "MultiMedia16",
-		.platform_name = "msm-pcm-dsp-noirq",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			 SND_SOC_DPCM_TRIGGER_POST},
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		 /* this dainlink has playback support */
-		.id = MSM_FRONTEND_DAI_MULTIMEDIA16,
-	},
-	{
-		.name = "Circuit-Switch Voice",
-		.stream_name = "CS-Voice",
-		.cpu_dai_name   = "CS-VOICE",
-		.platform_name  = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.id = MSM_FRONTEND_DAI_CS_VOICE,
-	},
-	{
-		.name = "Voice2",
-		.stream_name = "Voice2",
-		.cpu_dai_name = "Voice2",
-		.platform_name = "msm-pcm-voice",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-		.id = MSM_FRONTEND_DAI_VOICE2,
-	},
-};
-
-static struct snd_soc_dai_link msm8996_tasha_fe_dai_links[] = {
-	{
-		.name = LPASS_BE_SLIMBUS_4_TX,
-		.stream_name = "Slimbus4 Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.16393",
-		.platform_name = "msm-pcm-hostless",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_vifeedback",
-		.id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
-		.be_hw_params_fixup = msm_slim_4_tx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-	},
-	/* Ultrasound RX DAI Link */
-	{
-		.name = "SLIMBUS_2 Hostless Playback",
-		.stream_name = "SLIMBUS_2 Hostless Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.16388",
-		.platform_name = "msm-pcm-hostless",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_rx2",
-		.ignore_suspend = 1,
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ops = &msm8996_slimbus_2_be_ops,
-	},
-	/* Ultrasound TX DAI Link */
-	{
-		.name = "SLIMBUS_2 Hostless Capture",
-		.stream_name = "SLIMBUS_2 Hostless Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.16389",
-		.platform_name = "msm-pcm-hostless",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_tx2",
-		.ignore_suspend = 1,
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ops = &msm8996_slimbus_2_be_ops,
-	},
-	/* CPE LSM direct dai-link */
-	{
-		.name = "CPE Listen service",
-		.stream_name = "CPE Listen Audio Service",
-		.cpu_dai_name = "msm-dai-slim",
-		.platform_name = "msm-cpe-lsm",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "tasha_mad1",
-		.codec_name = "tasha_codec",
-		.ops = &msm8996_cpe_ops,
-	},
-	/* slimbus rx 6 hostless */
-	{
-		.name = "SLIMBUS_6 Hostless Playback",
-		.stream_name = "SLIMBUS_6 Hostless",
-		.cpu_dai_name = "SLIMBUS6_HOSTLESS",
-		.platform_name = "msm-pcm-hostless",
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		 /* this dailink has playback support */
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "snd-soc-dummy-dai",
-		.codec_name = "snd-soc-dummy",
-	},
-	/* CPE LSM EC PP direct dai-link */
-	{
-		.name = "CPE Listen service ECPP",
-		.stream_name = "CPE Listen Audio Service ECPP",
-		.cpu_dai_name = "CPE_LSM_NOHOST",
-		.platform_name = "msm-cpe-lsm.3",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
-		.ignore_suspend = 1,
-		.ignore_pmdown_time = 1,
-		.codec_dai_name = "tasha_cpe",
-		.codec_name = "tasha_codec",
-	},
-};
-
-static struct snd_soc_dai_link msm8996_common_be_dai_links[] = {
-	/* Backend AFE DAI Links */
-	{
-		.name = LPASS_BE_AFE_PCM_RX,
-		.stream_name = "AFE Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.224",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_AFE_PCM_RX,
-		.be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_AFE_PCM_TX,
-		.stream_name = "AFE Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.225",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_AFE_PCM_TX,
-		.be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	/* Primary AUX PCM Backend DAI Links */
-	{
-		.name = LPASS_BE_AUXPCM_RX,
-		.stream_name = "AUX PCM Playback",
-		.cpu_dai_name = "msm-dai-q6-auxpcm.1",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_AUXPCM_RX,
-		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-		/* this dainlink has playback support */
-	},
-	{
-		.name = LPASS_BE_AUXPCM_TX,
-		.stream_name = "AUX PCM Capture",
-		.cpu_dai_name = "msm-dai-q6-auxpcm.1",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_AUXPCM_TX,
-		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
-		.ignore_suspend = 1,
-	},
-	/* Incall Record Uplink BACK END DAI Link */
-	{
-		.name = LPASS_BE_INCALL_RECORD_TX,
-		.stream_name = "Voice Uplink Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.32772",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	/* Incall Record Downlink BACK END DAI Link */
-	{
-		.name = LPASS_BE_INCALL_RECORD_RX,
-		.stream_name = "Voice Downlink Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.32771",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	/* Incall Music BACK END DAI Link */
-	{
-		.name = LPASS_BE_VOICE_PLAYBACK_TX,
-		.stream_name = "Voice Farend Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.32773",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	/* Incall Music 2 BACK END DAI Link */
-	{
-		.name = LPASS_BE_VOICE2_PLAYBACK_TX,
-		.stream_name = "Voice2 Farend Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.32770",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-rx",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_TERT_MI2S_TX,
-		.stream_name = "Tertiary MI2S Capture",
-		.cpu_dai_name = "msm-dai-q6-mi2s.2",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-stub-codec.1",
-		.codec_dai_name = "msm-stub-tx",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX,
-		.be_hw_params_fixup = msm_tx_be_hw_params_fixup,
-		.ops = &msm8996_mi2s_be_ops,
-		.ignore_suspend = 1,
-	}
-};
-
-static struct snd_soc_dai_link msm8996_tasha_be_dai_links[] = {
-	/* Backend DAI Links */
-	{
-		.name = LPASS_BE_SLIMBUS_0_RX,
-		.stream_name = "Slimbus Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.16384",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_mix_rx1",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
-		.init = &msm_audrx_init,
-		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
-		/* this dainlink has playback support */
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-		.ops = &msm8996_be_ops,
-	},
-	{
-		.name = LPASS_BE_SLIMBUS_0_TX,
-		.stream_name = "Slimbus Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.16385",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_tx1",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
-		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
-		.ignore_suspend = 1,
-		.ops = &msm8996_be_ops,
-	},
-	{
-		.name = LPASS_BE_SLIMBUS_1_RX,
-		.stream_name = "Slimbus1 Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.16386",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_mix_rx1",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
-		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		/* dai link has playback support */
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SLIMBUS_1_TX,
-		.stream_name = "Slimbus1 Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.16387",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_tx3",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
-		.be_hw_params_fixup = msm_slim_1_tx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SLIMBUS_3_RX,
-		.stream_name = "Slimbus3 Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.16390",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_mix_rx1",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
-		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		/* dai link has playback support */
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SLIMBUS_3_TX,
-		.stream_name = "Slimbus3 Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.16391",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_tx1",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
-		.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SLIMBUS_4_RX,
-		.stream_name = "Slimbus4 Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.16392",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_mix_rx1",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
-		.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		/* dai link has playback support */
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SLIMBUS_5_RX,
-		.stream_name = "Slimbus5 Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.16394",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_rx3",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_5_RX,
-		.be_hw_params_fixup = msm_slim_5_rx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		/* dai link has playback support */
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-	/* MAD BE */
-	{
-		.name = LPASS_BE_SLIMBUS_5_TX,
-		.stream_name = "Slimbus5 Capture",
-		.cpu_dai_name = "msm-dai-q6-dev.16395",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_mad1",
-		.no_pcm = 1,
-		.dpcm_capture = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
-		.be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		.ignore_suspend = 1,
-	},
-	{
-		.name = LPASS_BE_SLIMBUS_6_RX,
-		.stream_name = "Slimbus6 Playback",
-		.cpu_dai_name = "msm-dai-q6-dev.16396",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "tasha_codec",
-		.codec_dai_name = "tasha_rx4",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_SLIMBUS_6_RX,
-		.be_hw_params_fixup = msm_slim_6_rx_be_hw_params_fixup,
-		.ops = &msm8996_be_ops,
-		/* dai link has playback support */
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-};
-
-static struct snd_soc_dai_link msm8996_hdmi_dai_link[] = {
-	/* HDMI BACK END DAI Link */
-	{
-		.name = LPASS_BE_HDMI,
-		.stream_name = "HDMI Playback",
-		.cpu_dai_name = "msm-dai-q6-hdmi.8",
-		.platform_name = "msm-pcm-routing",
-		.codec_name = "msm-hdmi-audio-codec-rx",
-		.codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
-		.no_pcm = 1,
-		.dpcm_playback = 1,
-		.id = MSM_BACKEND_DAI_HDMI_RX,
-		.be_hw_params_fixup = msm8996_hdmi_be_hw_params_fixup,
-		.ignore_pmdown_time = 1,
-		.ignore_suspend = 1,
-	},
-};
-
-static struct snd_soc_dai_link msm8996_tasha_dai_links[
-			 ARRAY_SIZE(msm8996_common_dai_links) +
-			 ARRAY_SIZE(msm8996_tasha_fe_dai_links) +
-			 ARRAY_SIZE(msm8996_common_be_dai_links) +
-			 ARRAY_SIZE(msm8996_tasha_be_dai_links) +
-			 ARRAY_SIZE(msm8996_hdmi_dai_link)];
-
-static int msm8996_wsa881x_init(struct snd_soc_component *component)
-{
-	u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106};
-	u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107};
-	unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
-	unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
-	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
-	struct msm8996_asoc_mach_data *pdata;
-	struct snd_soc_dapm_context *dapm;
-
-	if (!codec) {
-		pr_err("%s codec is NULL\n", __func__);
-		return -EINVAL;
-	}
-
-	dapm = snd_soc_codec_get_dapm(codec);
-
-	if (!strcmp(component->name_prefix, "SpkrLeft")) {
-		dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n",
-			__func__, codec->component.name);
-		wsa881x_set_channel_map(codec, &spkleft_ports[0],
-				WSA881X_MAX_SWR_PORTS, &ch_mask[0],
-				&ch_rate[0]);
-		if (dapm->component) {
-			snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
-			snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
-		}
-	} else if (!strcmp(component->name_prefix, "SpkrRight")) {
-		dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n",
-			__func__, codec->component.name);
-		wsa881x_set_channel_map(codec, &spkright_ports[0],
-				WSA881X_MAX_SWR_PORTS, &ch_mask[0],
-				&ch_rate[0]);
-		if (dapm->component) {
-			snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
-			snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
-		}
-	} else {
-		dev_err(codec->dev, "%s: wrong codec name %s\n", __func__,
-			codec->component.name);
-		return -EINVAL;
-	}
-	pdata = snd_soc_card_get_drvdata(component->card);
-	if (pdata && pdata->codec_root)
-		wsa881x_codec_info_create_codec_entry(pdata->codec_root,
-						      codec);
-
-	return 0;
-}
-
-struct snd_soc_card snd_soc_card_tasha_msm8996 = {
-	.name		= "msm8996-tasha-snd-card",
-};
-
-static int msm8996_populate_dai_link_component_of_node(
-					struct snd_soc_card *card)
-{
-	int i, index, ret = 0;
-	struct device *cdev = card->dev;
-	struct snd_soc_dai_link *dai_link = card->dai_link;
-	struct device_node *np;
-
-	if (!cdev) {
-		pr_err("%s: Sound card device memory NULL\n", __func__);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < card->num_links; i++) {
-		if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node)
-			continue;
-
-		/* populate platform_of_node for snd card dai links */
-		if (dai_link[i].platform_name &&
-		    !dai_link[i].platform_of_node) {
-			index = of_property_match_string(cdev->of_node,
-						"asoc-platform-names",
-						dai_link[i].platform_name);
-			if (index < 0) {
-				pr_err("%s: No match found for platform name: %s\n",
-					__func__, dai_link[i].platform_name);
-				ret = index;
-				goto err;
-			}
-			np = of_parse_phandle(cdev->of_node, "asoc-platform",
-					      index);
-			if (!np) {
-				pr_err("%s: retrieving phandle for platform %s, index %d failed\n",
-					__func__, dai_link[i].platform_name,
-					index);
-				ret = -ENODEV;
-				goto err;
-			}
-			dai_link[i].platform_of_node = np;
-			dai_link[i].platform_name = NULL;
-		}
-
-		/* populate cpu_of_node for snd card dai links */
-		if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) {
-			index = of_property_match_string(cdev->of_node,
-						 "asoc-cpu-names",
-						 dai_link[i].cpu_dai_name);
-			if (index >= 0) {
-				np = of_parse_phandle(cdev->of_node, "asoc-cpu",
-						index);
-				if (!np) {
-					pr_err("%s: retrieving phandle for cpu dai %s failed\n",
-						__func__,
-						dai_link[i].cpu_dai_name);
-					ret = -ENODEV;
-					goto err;
-				}
-				dai_link[i].cpu_of_node = np;
-				dai_link[i].cpu_dai_name = NULL;
-			}
-		}
-
-		/* populate codec_of_node for snd card dai links */
-		if (dai_link[i].codec_name && !dai_link[i].codec_of_node) {
-			index = of_property_match_string(cdev->of_node,
-						 "asoc-codec-names",
-						 dai_link[i].codec_name);
-			if (index < 0)
-				continue;
-			np = of_parse_phandle(cdev->of_node, "asoc-codec",
-					      index);
-			if (!np) {
-				pr_err("%s: retrieving phandle for codec %s failed\n",
-					__func__, dai_link[i].codec_name);
-				ret = -ENODEV;
-				goto err;
-			}
-			dai_link[i].codec_of_node = np;
-			dai_link[i].codec_name = NULL;
-		}
-	}
-
-err:
-	return ret;
-}
-
-static int msm8996_prepare_us_euro(struct snd_soc_card *card)
-{
-	struct msm8996_asoc_mach_data *pdata =
-				snd_soc_card_get_drvdata(card);
-	int ret;
-
-	if (pdata->us_euro_gpio >= 0) {
-		dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__,
-			pdata->us_euro_gpio);
-		ret = gpio_request(pdata->us_euro_gpio, "TASHA_CODEC_US_EURO");
-		if (ret) {
-			dev_err(card->dev,
-				"%s: Failed to request codec US/EURO gpio %d error %d\n",
-				__func__, pdata->us_euro_gpio, ret);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int msm8996_prepare_hifi(struct snd_soc_card *card)
-{
-	struct msm8996_asoc_mach_data *pdata =
-				snd_soc_card_get_drvdata(card);
-	int ret;
-
-	if (gpio_is_valid(pdata->hph_en1_gpio)) {
-		dev_dbg(card->dev, "%s: hph_en1_gpio request %d\n", __func__,
-			pdata->hph_en1_gpio);
-		ret = gpio_request(pdata->hph_en1_gpio, "hph_en1_gpio");
-		if (ret) {
-			dev_err(card->dev,
-				"%s: hph_en1_gpio request failed, ret:%d\n",
-				__func__, ret);
-			return ret;
-		}
-	}
-	if (gpio_is_valid(pdata->hph_en0_gpio)) {
-		dev_dbg(card->dev, "%s: hph_en0_gpio request %d\n", __func__,
-			pdata->hph_en0_gpio);
-		ret = gpio_request(pdata->hph_en0_gpio, "hph_en0_gpio");
-		if (ret) {
-			dev_err(card->dev,
-				"%s: hph_en0_gpio request failed, ret:%d\n",
-				__func__, ret);
-			return ret;
-		}
-	}
-	return 0;
-}
-
-static const struct of_device_id msm8996_asoc_machine_of_match[]  = {
-	{ .compatible = "qcom,msm8996-asoc-snd-tasha",
-	  .data = "tasha_codec"},
-	{},
-};
-
-static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
-{
-	struct snd_soc_card *card = NULL;
-	struct snd_soc_dai_link *dailink;
-	int len_1, len_2, len_3, len_4;
-	const struct of_device_id *match;
-
-	match = of_match_node(msm8996_asoc_machine_of_match, dev->of_node);
-	if (!match) {
-		dev_err(dev, "%s: No DT match found for sound card\n",
-			__func__);
-		return NULL;
-	}
-
-	if (!strcmp(match->data, "tasha_codec")) {
-		card = &snd_soc_card_tasha_msm8996;
-		len_1 = ARRAY_SIZE(msm8996_common_dai_links);
-		len_2 = len_1 + ARRAY_SIZE(msm8996_tasha_fe_dai_links);
-		len_3 = len_2 + ARRAY_SIZE(msm8996_common_be_dai_links);
-
-		memcpy(msm8996_tasha_dai_links,
-		       msm8996_common_dai_links,
-		       sizeof(msm8996_common_dai_links));
-		memcpy(msm8996_tasha_dai_links + len_1,
-		       msm8996_tasha_fe_dai_links,
-		       sizeof(msm8996_tasha_fe_dai_links));
-		memcpy(msm8996_tasha_dai_links + len_2,
-		       msm8996_common_be_dai_links,
-		       sizeof(msm8996_common_be_dai_links));
-		memcpy(msm8996_tasha_dai_links + len_3,
-		       msm8996_tasha_be_dai_links,
-		       sizeof(msm8996_tasha_be_dai_links));
-
-		dailink = msm8996_tasha_dai_links;
-		len_4 = len_3 + ARRAY_SIZE(msm8996_tasha_be_dai_links);
-	}
-
-	if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) {
-		dev_dbg(dev, "%s(): hdmi audio support present\n",
-				__func__);
-		memcpy(dailink + len_4, msm8996_hdmi_dai_link,
-			sizeof(msm8996_hdmi_dai_link));
-		len_4 += ARRAY_SIZE(msm8996_hdmi_dai_link);
-	} else {
-		dev_dbg(dev, "%s(): No hdmi audio support\n", __func__);
-	}
-
-	if (card) {
-		card->dai_link = dailink;
-		card->num_links = len_4;
-	}
-
-	return card;
-}
-
-static int msm8996_init_wsa_dev(struct platform_device *pdev,
-				struct snd_soc_card *card)
-{
-	struct device_node *wsa_of_node;
-	u32 wsa_max_devs;
-	u32 wsa_dev_cnt;
-	char *dev_name_str = NULL;
-	struct msm8996_wsa881x_dev_info *wsa881x_dev_info;
-	const char *wsa_auxdev_name_prefix[1];
-	int found = 0;
-	int i;
-	int ret;
-
-	/* Get maximum WSA device count for this platform */
-	ret = of_property_read_u32(pdev->dev.of_node,
-				   "qcom,wsa-max-devs", &wsa_max_devs);
-	if (ret) {
-		dev_dbg(&pdev->dev,
-			 "%s: wsa-max-devs property missing in DT %s, ret = %d\n",
-			 __func__, pdev->dev.of_node->full_name, ret);
-		return 0;
-	}
-	if (wsa_max_devs == 0) {
-		dev_warn(&pdev->dev,
-			 "%s: Max WSA devices is 0 for this target?\n",
-			 __func__);
-		return 0;
-	}
-
-	/* Get count of WSA device phandles for this platform */
-	wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
-						 "qcom,wsa-devs", NULL);
-	if (wsa_dev_cnt == -ENOENT) {
-		dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
-			 __func__);
-		return 0;
-	} else if (wsa_dev_cnt <= 0) {
-		dev_err(&pdev->dev,
-			"%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
-			__func__, wsa_dev_cnt);
-		return -EINVAL;
-	}
-
-	/*
-	 * Expect total phandles count to be NOT less than maximum possible
-	 * WSA count. However, if it is less, then assign same value to
-	 * max count as well.
-	 */
-	if (wsa_dev_cnt < wsa_max_devs) {
-		dev_dbg(&pdev->dev,
-			"%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
-			__func__, wsa_max_devs, wsa_dev_cnt);
-		wsa_max_devs = wsa_dev_cnt;
-	}
-
-	/* Make sure prefix string passed for each WSA device */
-	ret = of_property_count_strings(pdev->dev.of_node,
-					"qcom,wsa-aux-dev-prefix");
-	if (ret != wsa_dev_cnt) {
-		dev_err(&pdev->dev,
-			"%s: expecting %d wsa prefix. Defined only %d in DT\n",
-			__func__, wsa_dev_cnt, ret);
-		return -EINVAL;
-	}
-
-	/*
-	 * Alloc mem to store phandle and index info of WSA device, if already
-	 * registered with ALSA core
-	 */
-	wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
-					sizeof(struct msm8996_wsa881x_dev_info),
-					GFP_KERNEL);
-	if (!wsa881x_dev_info)
-		return -ENOMEM;
-
-	/*
-	 * search and check whether all WSA devices are already
-	 * registered with ALSA core or not. If found a node, store
-	 * the node and the index in a local array of struct for later
-	 * use.
-	 */
-	for (i = 0; i < wsa_dev_cnt; i++) {
-		wsa_of_node = of_parse_phandle(pdev->dev.of_node,
-					    "qcom,wsa-devs", i);
-		if (unlikely(!wsa_of_node)) {
-			/* we should not be here */
-			dev_err(&pdev->dev,
-				"%s: wsa dev node is not present\n",
-				__func__);
-			return -EINVAL;
-		}
-		if (soc_find_component(wsa_of_node, NULL)) {
-			/* WSA device registered with ALSA core */
-			wsa881x_dev_info[found].of_node = wsa_of_node;
-			wsa881x_dev_info[found].index = i;
-			found++;
-			if (found == wsa_max_devs)
-				break;
-		}
-	}
-
-	if (found < wsa_max_devs) {
-		dev_dbg(&pdev->dev,
-			"%s: failed to find %d components. Found only %d\n",
-			__func__, wsa_max_devs, found);
-		return -EPROBE_DEFER;
-	}
-	dev_info(&pdev->dev,
-		"%s: found %d wsa881x devices registered with ALSA core\n",
-		__func__, found);
-
-	card->num_aux_devs = wsa_max_devs;
-	card->num_configs = wsa_max_devs;
-
-	/* Alloc array of AUX devs struct */
-	msm8996_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
-				       sizeof(struct snd_soc_aux_dev),
-				       GFP_KERNEL);
-	if (!msm8996_aux_dev)
-		return -ENOMEM;
-
-	/* Alloc array of codec conf struct */
-	msm8996_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs,
-					  sizeof(struct snd_soc_codec_conf),
-					  GFP_KERNEL);
-	if (!msm8996_codec_conf)
-		return -ENOMEM;
-
-	for (i = 0; i < card->num_aux_devs; i++) {
-		dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
-					    GFP_KERNEL);
-		if (!dev_name_str)
-			return -ENOMEM;
-
-		ret = of_property_read_string_index(pdev->dev.of_node,
-						    "qcom,wsa-aux-dev-prefix",
-						    wsa881x_dev_info[i].index,
-						    wsa_auxdev_name_prefix);
-		if (ret) {
-			dev_err(&pdev->dev,
-				"%s: failed to read wsa aux dev prefix, ret = %d\n",
-				__func__, ret);
-			return -EINVAL;
-		}
-
-		snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
-		msm8996_aux_dev[i].name = dev_name_str;
-		msm8996_aux_dev[i].codec_name = NULL;
-		msm8996_aux_dev[i].codec_of_node =
-					wsa881x_dev_info[i].of_node;
-		msm8996_aux_dev[i].init = msm8996_wsa881x_init;
-		msm8996_codec_conf[i].dev_name = NULL;
-		msm8996_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0];
-		msm8996_codec_conf[i].of_node =
-					wsa881x_dev_info[i].of_node;
-	}
-	card->codec_conf = msm8996_codec_conf;
-	card->aux_dev = msm8996_aux_dev;
-
-	return 0;
-}
-
-static int msm8996_asoc_machine_probe(struct platform_device *pdev)
-{
-	struct snd_soc_card *card;
-	struct msm8996_asoc_mach_data *pdata;
-	const char *mbhc_audio_jack_type = NULL;
-	char *mclk_freq_prop_name;
-	const struct of_device_id *match;
-	int ret;
-
-	if (!pdev->dev.of_node) {
-		dev_err(&pdev->dev, "No platform supplied from device tree\n");
-		return -EINVAL;
-	}
-
-	pdata = devm_kzalloc(&pdev->dev,
-			sizeof(struct msm8996_asoc_mach_data), GFP_KERNEL);
-	if (!pdata)
-		return -ENOMEM;
-
-	card = populate_snd_card_dailinks(&pdev->dev);
-	if (!card) {
-		dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
-		ret = -EINVAL;
-		goto err;
-	}
-	card->dev = &pdev->dev;
-	platform_set_drvdata(pdev, card);
-	snd_soc_card_set_drvdata(card, pdata);
-
-	ret = snd_soc_of_parse_card_name(card, "qcom,model");
-	if (ret) {
-		dev_err(&pdev->dev, "parse card name failed, err:%d\n",
-			ret);
-		goto err;
-	}
-
-	ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
-	if (ret) {
-		dev_err(&pdev->dev, "parse audio routing failed, err:%d\n",
-			ret);
-		goto err;
-	}
-
-	match = of_match_node(msm8996_asoc_machine_of_match,
-			pdev->dev.of_node);
-	if (!match) {
-		dev_err(&pdev->dev, "%s: no matched codec is found.\n",
-			__func__);
-		goto err;
-	}
-
-	mclk_freq_prop_name = "qcom,tasha-mclk-clk-freq";
-
-	ret = of_property_read_u32(pdev->dev.of_node,
-			mclk_freq_prop_name, &pdata->mclk_freq);
-	if (ret) {
-		dev_err(&pdev->dev,
-			"Looking up %s property in node %s failed, err%d\n",
-			mclk_freq_prop_name,
-			pdev->dev.of_node->full_name, ret);
-		goto err;
-	}
-
-	if (pdata->mclk_freq != CODEC_EXT_CLK_RATE) {
-		dev_err(&pdev->dev, "unsupported mclk freq %u\n",
-			pdata->mclk_freq);
-		ret = -EINVAL;
-		goto err;
-	}
-
-	spdev = pdev;
-
-	ret = msm8996_populate_dai_link_component_of_node(card);
-	if (ret) {
-		ret = -EPROBE_DEFER;
-		goto err;
-	}
-
-	ret = msm8996_init_wsa_dev(pdev, card);
-	if (ret)
-		goto err;
-
-	pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node,
-						"qcom,hph-en1-gpio", 0);
-	if (pdata->hph_en1_gpio < 0) {
-		dev_dbg(&pdev->dev, "%s: %s property not found %d\n",
-			__func__, "qcom,hph-en1-gpio", pdata->hph_en1_gpio);
-	}
-
-	pdata->hph_en0_gpio = of_get_named_gpio(pdev->dev.of_node,
-						"qcom,hph-en0-gpio", 0);
-	if (pdata->hph_en0_gpio < 0) {
-		dev_dbg(&pdev->dev, "%s: %s property not found %d\n",
-			__func__, "qcom,hph-en0-gpio", pdata->hph_en0_gpio);
-	}
-	ret = msm8996_prepare_hifi(card);
-	if (ret)
-		dev_dbg(&pdev->dev, "msm8996_prepare_hifi failed (%d)\n",
-			ret);
-
-	ret = snd_soc_register_card(card);
-	if (ret == -EPROBE_DEFER) {
-		if (codec_reg_done)
-			ret = -EINVAL;
-		goto err;
-	} else if (ret) {
-		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
-			ret);
-		goto err;
-	}
-	dev_info(&pdev->dev, "Sound card %s registered\n", card->name);
-
-	ret = of_property_read_string(pdev->dev.of_node,
-		"qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type);
-	if (ret) {
-		dev_dbg(&pdev->dev, "Looking up %s property in node %s failed",
-			"qcom,mbhc-audio-jack-type",
-			pdev->dev.of_node->full_name);
-		dev_dbg(&pdev->dev, "Jack type properties set to default");
-	} else {
-		if (!strcmp(mbhc_audio_jack_type, "4-pole-jack"))
-			dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
-		else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack"))
-			dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
-		else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack"))
-			dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
-		else
-			dev_dbg(&pdev->dev, "Unknown value, set to default");
-	}
-	/*
-	 * Parse US-Euro gpio info from DT. Report no error if us-euro
-	 * entry is not found in DT file as some targets do not support
-	 * US-Euro detection
-	 */
-	pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
-				"qcom,us-euro-gpios", 0);
-	if (pdata->us_euro_gpio < 0) {
-		dev_info(&pdev->dev, "property %s not detected in node %s",
-			"qcom,us-euro-gpios",
-			pdev->dev.of_node->full_name);
-	} else {
-		dev_dbg(&pdev->dev, "%s detected %d",
-			"qcom,us-euro-gpios", pdata->us_euro_gpio);
-		wcd_mbhc_cfg.swap_gnd_mic = msm8996_swap_gnd_mic;
-	}
-
-	ret = msm8996_prepare_us_euro(card);
-	if (ret)
-		dev_info(&pdev->dev, "msm8996_prepare_us_euro failed (%d)\n",
-			ret);
-	return 0;
-err:
-	if (pdata->us_euro_gpio > 0) {
-		dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
-			__func__, pdata->us_euro_gpio);
-		gpio_free(pdata->us_euro_gpio);
-		pdata->us_euro_gpio = 0;
-	}
-	if (pdata->hph_en1_gpio > 0) {
-		dev_dbg(&pdev->dev, "%s free hph_en1_gpio %d\n",
-			__func__, pdata->hph_en1_gpio);
-		gpio_free(pdata->hph_en1_gpio);
-		pdata->hph_en1_gpio = 0;
-	}
-	if (pdata->hph_en0_gpio > 0) {
-		dev_dbg(&pdev->dev, "%s free hph_en0_gpio %d\n",
-			__func__, pdata->hph_en0_gpio);
-		gpio_free(pdata->hph_en0_gpio);
-		pdata->hph_en0_gpio = 0;
-	}
-	devm_kfree(&pdev->dev, pdata);
-	return ret;
-}
-
-static int msm8996_asoc_machine_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct msm8996_asoc_mach_data *pdata =
-				snd_soc_card_get_drvdata(card);
-
-	if (gpio_is_valid(ext_us_amp_gpio))
-		gpio_free(ext_us_amp_gpio);
-
-	gpio_free(pdata->us_euro_gpio);
-	gpio_free(pdata->hph_en1_gpio);
-	gpio_free(pdata->hph_en0_gpio);
-
-	if (msm8996_liquid_dock_dev != NULL) {
-		switch_dev_unregister(&msm8996_liquid_dock_dev->audio_sdev);
-
-		if (msm8996_liquid_dock_dev->dock_plug_irq)
-			free_irq(msm8996_liquid_dock_dev->dock_plug_irq,
-				 msm8996_liquid_dock_dev);
-
-		if (msm8996_liquid_dock_dev->dock_plug_gpio)
-			gpio_free(msm8996_liquid_dock_dev->dock_plug_gpio);
-
-		kfree(msm8996_liquid_dock_dev);
-		msm8996_liquid_dock_dev = NULL;
-	}
-	snd_soc_unregister_card(card);
-
-	return 0;
-}
-
-static struct platform_driver msm8996_asoc_machine_driver = {
-	.driver = {
-		.name = DRV_NAME,
-		.owner = THIS_MODULE,
-		.pm = &snd_soc_pm_ops,
-		.of_match_table = msm8996_asoc_machine_of_match,
-	},
-	.probe = msm8996_asoc_machine_probe,
-	.remove = msm8996_asoc_machine_remove,
-};
-module_platform_driver(msm8996_asoc_machine_driver);
-
-MODULE_DESCRIPTION("ALSA SoC msm");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, msm8996_asoc_machine_of_match);
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index c885265..503af58 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -1282,6 +1282,9 @@
 		.step = SOFT_VOLUME_STEP,
 		.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
 	};
+	struct snd_kcontrol *kctl;
+	struct snd_ctl_elem_value kctl_elem_value;
+	uint16_t target_asm_bit_width = 0;
 
 	pr_debug("%s: stream_id %d\n", __func__, ac->stream_id);
 	stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
@@ -1290,6 +1293,23 @@
 		return -EINVAL;
 	}
 
+	kctl = snd_soc_card_get_kcontrol(soc_prtd->card,
+		DSP_BIT_WIDTH_MIXER_CTL);
+	if (kctl) {
+		kctl->get(kctl, &kctl_elem_value);
+		target_asm_bit_width = kctl_elem_value.value.integer.value[0];
+		if (target_asm_bit_width > 0) {
+			pr_debug("%s enforce ASM bitwidth to %d from %d\n",
+				__func__,
+				target_asm_bit_width,
+				bits_per_sample);
+			bits_per_sample = target_asm_bit_width;
+		}
+	} else {
+		pr_info("%s: failed to get mixer ctl for %s.\n",
+			__func__, DSP_BIT_WIDTH_MIXER_CTL);
+	}
+
 	if ((prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_LE) ||
 		(prtd->codec_param.codec.format == SNDRV_PCM_FORMAT_S24_3LE))
 		bits_per_sample = 24;
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index a885e1e..53826fe 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -392,6 +392,7 @@
 static int msm_afe_quat_mi2s_lb_vol_ctrl;
 static int msm_afe_slimbus_7_lb_vol_ctrl;
 static int msm_afe_slimbus_8_lb_vol_ctrl;
+static int msm_asm_bit_width;
 static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
 static const DECLARE_TLV_DB_LINEAR(afe_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
 
@@ -412,6 +413,38 @@
 	return 0;
 }
 
+static int msm_asm_bit_width_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s get ASM bitwidth = %d\n",
+		__func__, msm_asm_bit_width);
+
+	ucontrol->value.integer.value[0] = msm_asm_bit_width;
+
+	return 0;
+}
+
+static int msm_asm_bit_width_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 16:
+		msm_asm_bit_width = 16;
+		break;
+	case 24:
+		msm_asm_bit_width = 24;
+		break;
+	case 32:
+		msm_asm_bit_width = 32;
+		break;
+	default:
+		msm_asm_bit_width = 0;
+		break;
+	}
+
+	return 0;
+}
+
 static int msm_qti_pp_get_pri_mi2s_lb_vol_mixer(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_value *ucontrol)
 {
@@ -1132,6 +1165,11 @@
 	msm_qti_pp_set_quat_mi2s_fm_vol_mixer, fm_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new dsp_bit_width_controls[] = {
+	SOC_SINGLE_EXT(DSP_BIT_WIDTH_MIXER_CTL, SND_SOC_NOPM, 0, 0x20,
+	0, msm_asm_bit_width_get, msm_asm_bit_width_put),
+};
+
 static const struct snd_kcontrol_new pri_mi2s_lb_vol_mixer_controls[] = {
 	SOC_SINGLE_EXT_TLV("PRI MI2S LOOPBACK Volume", SND_SOC_NOPM, 0,
 	INT_RX_VOL_GAIN, 0, msm_qti_pp_get_pri_mi2s_lb_vol_mixer,
@@ -1403,5 +1441,8 @@
 
 	snd_soc_add_platform_controls(platform, msm_multichannel_ec_controls,
 			ARRAY_SIZE(msm_multichannel_ec_controls));
+
+	snd_soc_add_platform_controls(platform, dsp_bit_width_controls,
+			ARRAY_SIZE(dsp_bit_width_controls));
 }
 #endif /* CONFIG_QTI_PP */
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
index b67e873..ec69d37 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
@@ -13,6 +13,7 @@
 #define _MSM_QTI_PP_H_
 
 #include <sound/soc.h>
+#define DSP_BIT_WIDTH_MIXER_CTL "ASM Bit Width"
 int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
 			uint32_t *payload);
 int msm_adsp_init_mixer_ctl_pp_event_queue(struct snd_soc_pcm_runtime *rtd);