Merge "msm: gsi: check channel state on timeout"
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/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/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-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 377f2fe..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];
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 64d6d52..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";
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index 3d66fff..f0a6d9e 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -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 */
@@ -144,9 +156,15 @@
 
 	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)
 		BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
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/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index e9de729..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(
@@ -449,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);
 
@@ -458,6 +461,7 @@
 
 	c->dev = state->dev;
 	c->state = state;
+	c->nonblock = nonblock;
 
 	kthread_init_work(&c->commit_work, _msm_drm_commit_work_cb);
 
@@ -502,6 +506,11 @@
 			break;
 	}
 
+	if (!ret && !commit->nonblock) {
+		kthread_flush_work(&commit->commit_work);
+		kfree(commit);
+	}
+
 	return ret;
 }
 
@@ -535,7 +544,7 @@
 		return ret;
 	}
 
-	c = commit_init(state);
+	c = commit_init(state, nonblock);
 	if (!c) {
 		ret = -ENOMEM;
 		goto error;
@@ -603,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/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 6f1d2b7..0f08296 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -2952,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,
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 3b92f7a..d2637a4 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1927,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(
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_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 07628a17..1a00517 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -685,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;
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_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 8a39a34..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++;
@@ -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)
@@ -2251,7 +2310,9 @@
 		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);
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/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/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index d36d601..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>
@@ -1663,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;
 	}
 
@@ -1723,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;
 }
 
@@ -1843,6 +1847,7 @@
 {
 	struct sde_mdp_format_params *in_fmt, *out_fmt;
 	bool rotation;
+	u32 mode;
 
 	if (!mgr || !config) {
 		SDEROT_ERR("null parameters\n");
@@ -1851,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;
@@ -1859,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,
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_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index bf7a917..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>
@@ -1433,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)
@@ -1610,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;
 			}
@@ -1621,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;
 		}
@@ -1857,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;
 
@@ -1901,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;
 
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_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/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 69a9fc1..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",
@@ -5698,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_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index 027e76e..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),
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 69fc2e0..82c3ffc 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1090,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);
 		}
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 6852587..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 {
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/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/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index b3de8d0..faca084 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -1034,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;
@@ -1111,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 5ae653e..c57f7ef 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -1634,6 +1634,12 @@
 	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",
@@ -1887,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)
 {
@@ -4719,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:
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 5b59597..2746555 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -307,6 +307,7 @@
 	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;
@@ -427,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/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/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/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/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/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/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 5fbfe3d..66ecd6a 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -202,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/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);