Merge "drm/msm/sde: add mutex to the sde resource manager"
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index d0d7fff..59fa6a0 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -16,7 +16,7 @@
                         "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8",
                         "qcom,mdss_edp_pll_8996_v3", "qcom,mdss_edp_pll_8996_v3_1p8",
                         "qcom,mdss_dsi_pll_10nm", "qcom,mdss_dp_pll_8998",
-                        "qcom,mdss_hdmi_pll_8998"
+                        "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dp_pll_10nm".
 - cell-index:		Specifies the controller used
 - reg:			offset and length of the register set for the device.
 - reg-names :		names to refer to register sets related to this device
diff --git a/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi
new file mode 100644
index 0000000..61ef7ff
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi
@@ -0,0 +1,53 @@
+/* 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 {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		system_heap: qcom,ion-heap@25 {
+			reg = <25>;
+			qcom,ion-heap-type = "SYSTEM";
+		};
+
+		qcom,ion-heap@22 { /* ADSP HEAP */
+			reg = <22>;
+			memory-region = <&adsp_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+
+		qcom,ion-heap@27 { /* QSEECOM HEAP */
+			reg = <27>;
+			memory-region = <&qseecom_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+
+		qcom,ion-heap@13 { /* SPSS HEAP */
+			reg = <13>;
+			memory-region = <&sp_mem>;
+			qcom,ion-heap-type = "DMA";
+		};
+
+		qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */
+			reg = <10>;
+			memory-region = <&secure_display_memory>;
+			qcom,ion-heap-type = "HYP_CMA";
+		};
+
+		qcom,ion-heap@9 {
+			reg = <9>;
+			qcom,ion-heap-type = "SYSTEM_SECURE";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 2cbb990..7bef48d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -279,9 +279,113 @@
 		#address-cells = <2>;
 		#size-cells = <2>;
 		ranges;
+
+		removed_regions: removed_regions@85700000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x85700000 0 0x3800000>;
+		};
+
+		pil_camera_mem: camera_region@8ab00000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x8ab00000 0 0x500000>;
+		};
+
+		pil_modem_mem: modem_region@8b000000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x8b000000 0 0x7e00000>;
+		};
+
+		pil_video_mem: pil_video_region@92e00000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x92e00000 0 0x500000>;
+		};
+
+		pil_cdsp_mem: cdsp_regions@93300000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x93300000 0 0x600000>;
+		};
+
+		pil_mba_mem: pil_mba_region@0x93900000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x93900000 0 0x200000>;
+		};
+
+		pil_adsp_mem: pil_adsp_region@93b00000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x93b00000 0 0x1e00000>;
+		};
+
+		pil_ipa_fw_mem: pil_ipa_fw_region@95900000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x95900000 0 0x10000>;
+		};
+
+		pil_ipa_gsi_mem: pil_ipa_gsi_region@95910000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x95910000 0 0x5000>;
+		};
+
+		pil_gpu_mem: pil_gpu_region@95915000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x95915000 0 0x1000>;
+		};
+
+		adsp_mem: adsp_region {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0xc00000>;
+		};
+
+		qseecom_mem: qseecom_region {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x1400000>;
+		};
+
+		sp_mem: sp_region {  /* SPSS-HLOS ION shared mem */
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>; /* 32-bit */
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x800000>;
+		};
+
+		secure_display_memory: secure_display_region {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x5c00000>;
+		};
+
+		/* global autoconfigured region for contiguous allocations */
+		linux,cma {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x00000000 0 0xffffffff>;
+			reusable;
+			alignment = <0 0x400000>;
+			size = <0 0x2000000>;
+			linux,cma-default;
+		};
 	};
 };
 
+#include "sdm670-ion.dtsi"
+
 &soc {
 	#address-cells = <1>;
 	#size-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
index fff9160..ef964ae 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-overlay.dts
@@ -13,8 +13,13 @@
 /dts-v1/;
 /plugin/;
 
-#include "sdm845.dtsi"
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
 #include "sdm845-cdp.dtsi"
+#include "sdm845-qupv3.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM845 v1 CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
index 79fa580..548bd49 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts
@@ -13,8 +13,13 @@
 /dts-v1/;
 /plugin/;
 
-#include "sdm845.dtsi"
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
 #include "sdm845-mtp.dtsi"
+#include "sdm845-qupv3.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM845 v1 MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index bf58da6..1500bb5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -368,10 +368,106 @@
 		cell-index = <0>;
 		label = "wb_display";
 	};
+
+	sde_dp: qcom,dp_display@0{
+		cell-index = <0>;
+		compatible = "qcom,dp-display";
+
+		gdsc-supply = <&mdss_core_gdsc>;
+		vdda-1p2-supply = <&pm8998_l26>;
+		vdda-0p9-supply = <&pm8998_l1>;
+
+		reg =	<0xae90000 0xa84>,
+			<0x88eaa00 0x200>,
+			<0x88ea200 0x200>,
+			<0x88ea600 0x200>,
+			<0xaf02000 0x1a0>,
+			<0x780000 0x621c>,
+			<0x88ea030 0x10>,
+			<0x0aee1000 0x034>;
+		reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+			"dp_mmss_cc", "qfprom_physical", "dp_pll",
+			"hdcp_physical";
+
+		interrupt-parent = <&mdss_mdp>;
+		interrupts = <12 0>;
+
+		clocks =  <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+			 <&clock_rpmh RPMH_CXO_CLK>,
+			 <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
+			 <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			 <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+			 <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+			 <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+			 <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+			 <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+			 <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>,
+			 <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>;
+		clock-names = "core_aux_clk", "core_usb_ref_clk_src",
+			"core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+			"core_usb_pipe_clk", "ctrl_link_clk",
+			"ctrl_link_iface_clk", "ctrl_crypto_clk",
+			"ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent";
+
+		qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+
+		qcom,aux-cfg-settings = [00 13 04 00 0a 26 0a 03 bb 03];
+
+		qcom,core-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,core-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+
+		qcom,ctrl-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,ctrl-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda-1p2";
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <21800>;
+				qcom,supply-disable-load = <4>;
+			};
+		};
+
+		qcom,phy-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,phy-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "vdda-0p9";
+				qcom,supply-min-voltage = <880000>;
+				qcom,supply-max-voltage = <880000>;
+				qcom,supply-enable-load = <36000>;
+				qcom,supply-disable-load = <32>;
+			};
+		};
+	};
+};
+
+&sde_dp {
+	pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
+	pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>;
+	pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>;
+	qcom,aux-en-gpio = <&tlmm 43 0>;
+	qcom,aux-sel-gpio = <&tlmm 51 0>;
+	qcom,usbplug-cc-gpio = <&tlmm 38 0>;
 };
 
 &mdss_mdp {
-	connectors = <&sde_rscc &sde_wb>;
+	connectors = <&sde_rscc &sde_wb &sde_dp>;
 };
 
 &dsi_dual_nt35597_truly_video {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
index 168f2a9..b9eac3c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
@@ -64,4 +64,46 @@
 			};
 		};
 	};
+
+	mdss_dp_pll: qcom,mdss_dp_pll@c011000 {
+		compatible = "qcom,mdss_dp_pll_10nm";
+		label = "MDSS DP PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+
+		reg = <0x088ea000 0x200>,
+		      <0x088eaa00 0x200>,
+		      <0x088ea200 0x200>,
+		      <0x088ea600 0x200>,
+		      <0xaf03000 0x8>;
+		reg-names = "pll_base", "phy_base", "ln_tx0_base",
+			"ln_tx1_base", "gdsc_base";
+
+		gdsc-supply = <&mdss_core_gdsc>;
+
+		clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>,
+			 <&clock_rpmh RPMH_CXO_CLK>,
+			 <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
+			 <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+			 <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+		clock-names = "iface_clk", "ref_clk_src", "ref_clk",
+			"cfg_ahb_clk", "pipe_clk";
+		clock-rate = <0>;
+
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+
+		};
+	};
+
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index 4fe9282..af12224 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -27,6 +27,10 @@
 		qcom,max-secure-instances = <5>;
 		qcom,max-hw-load = <2563200>; /* Full 4k @ 60 + 1080p @ 60 */
 
+		/* LLCC Info */
+		cache-slice-names = "vidsc0", "vidsc1";
+		cache-slices = <&llcc 2>, <&llcc 3>;
+
 		/* Supply */
 		venus-supply = <&venus_gdsc>;
 		venus-core0-supply = <&vcodec0_gdsc>;
@@ -91,6 +95,14 @@
 			qcom,bus-governor = "performance";
 			qcom,bus-range-kbps = <1000 1000>;
 		};
+		venus_bus_llcc {
+			compatible = "qcom,msm-vidc,bus";
+			label = "venus-llcc";
+			qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+			qcom,bus-slave = <MSM_BUS_SLAVE_LLCC>;
+			qcom,bus-governor = "performance";
+			qcom,bus-range-kbps = <17000 125700>;
+		};
 
 		/* MMUs */
 		non_secure_cb {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 16bd53a..c89a05e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -459,6 +459,22 @@
 		compatible = "simple-bus";
 	};
 
+	firmware: firmware {
+		android {
+			compatible = "android,firmware";
+			fstab {
+				compatible = "android,fstab";
+				vendor {
+					compatible = "android,vendor";
+					dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor";
+					type = "ext4";
+					mnt_flags = "ro,barrier=1,discard";
+					fsmgr_flags = "wait,slotselect";
+				};
+			};
+		};
+	};
+
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
diff --git a/drivers/clk/qcom/mdss/Makefile b/drivers/clk/qcom/mdss/Makefile
index d183393..87feee6 100644
--- a/drivers/clk/qcom/mdss/Makefile
+++ b/drivers/clk/qcom/mdss/Makefile
@@ -1,3 +1,6 @@
 obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll-util.o
 obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-pll.o
 obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-10nm.o
+obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-10nm.o
+obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-10nm-util.o
+
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c
new file mode 100644
index 0000000..eb2092a
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm-util.c
@@ -0,0 +1,766 @@
+/* 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/kernel.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/delay.h>
+#include <linux/usb/usbpd.h>
+
+#include "mdss-pll.h"
+#include "mdss-dp-pll.h"
+#include "mdss-dp-pll-10nm.h"
+
+#define DP_PHY_REVISION_ID0			0x0000
+#define DP_PHY_REVISION_ID1			0x0004
+#define DP_PHY_REVISION_ID2			0x0008
+#define DP_PHY_REVISION_ID3			0x000C
+
+#define DP_PHY_CFG				0x0010
+#define DP_PHY_PD_CTL				0x0018
+#define DP_PHY_MODE				0x001C
+
+#define DP_PHY_AUX_CFG0				0x0020
+#define DP_PHY_AUX_CFG1				0x0024
+#define DP_PHY_AUX_CFG2				0x0028
+#define DP_PHY_AUX_CFG3				0x002C
+#define DP_PHY_AUX_CFG4				0x0030
+#define DP_PHY_AUX_CFG5				0x0034
+#define DP_PHY_AUX_CFG6				0x0038
+#define DP_PHY_AUX_CFG7				0x003C
+#define DP_PHY_AUX_CFG8				0x0040
+#define DP_PHY_AUX_CFG9				0x0044
+#define DP_PHY_AUX_INTERRUPT_MASK		0x0048
+#define DP_PHY_AUX_INTERRUPT_CLEAR		0x004C
+#define DP_PHY_AUX_BIST_CFG			0x0050
+
+#define DP_PHY_VCO_DIV				0x0064
+#define DP_PHY_TX0_TX1_LANE_CTL			0x006C
+#define DP_PHY_TX2_TX3_LANE_CTL			0x0088
+
+#define DP_PHY_SPARE0				0x00AC
+#define DP_PHY_STATUS				0x00C0
+
+/* Tx registers */
+#define TXn_BIST_MODE_LANENO			0x0000
+#define TXn_CLKBUF_ENABLE			0x0008
+#define TXn_TX_EMP_POST1_LVL			0x000C
+
+#define TXn_TX_DRV_LVL				0x001C
+
+#define TXn_RESET_TSYNC_EN			0x0024
+#define TXn_PRE_STALL_LDO_BOOST_EN		0x0028
+#define TXn_TX_BAND				0x002C
+#define TXn_SLEW_CNTL				0x0030
+#define TXn_INTERFACE_SELECT			0x0034
+
+#define TXn_RES_CODE_LANE_TX			0x003C
+#define TXn_RES_CODE_LANE_RX			0x0040
+#define TXn_RES_CODE_LANE_OFFSET_TX		0x0044
+#define TXn_RES_CODE_LANE_OFFSET_RX		0x0048
+
+#define TXn_DEBUG_BUS_SEL			0x0058
+#define TXn_TRANSCEIVER_BIAS_EN			0x005C
+#define TXn_HIGHZ_DRVR_EN			0x0060
+#define TXn_TX_POL_INV				0x0064
+#define TXn_PARRATE_REC_DETECT_IDLE_EN		0x0068
+
+#define TXn_LANE_MODE_1				0x008C
+
+#define TXn_TRAN_DRVR_EMP_EN			0x00C0
+#define TXn_TX_INTERFACE_MODE			0x00C4
+
+#define TXn_VMODE_CTRL1				0x00F0
+
+/* PLL register offset */
+#define QSERDES_COM_ATB_SEL1			0x0000
+#define QSERDES_COM_ATB_SEL2			0x0004
+#define QSERDES_COM_FREQ_UPDATE			0x0008
+#define QSERDES_COM_BG_TIMER			0x000C
+#define QSERDES_COM_SSC_EN_CENTER		0x0010
+#define QSERDES_COM_SSC_ADJ_PER1		0x0014
+#define QSERDES_COM_SSC_ADJ_PER2		0x0018
+#define QSERDES_COM_SSC_PER1			0x001C
+#define QSERDES_COM_SSC_PER2			0x0020
+#define QSERDES_COM_SSC_STEP_SIZE1		0x0024
+#define QSERDES_COM_SSC_STEP_SIZE2		0x0028
+#define QSERDES_COM_POST_DIV			0x002C
+#define QSERDES_COM_POST_DIV_MUX		0x0030
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN		0x0034
+#define QSERDES_COM_CLK_ENABLE1			0x0038
+#define QSERDES_COM_SYS_CLK_CTRL		0x003C
+#define QSERDES_COM_SYSCLK_BUF_ENABLE		0x0040
+#define QSERDES_COM_PLL_EN			0x0044
+#define QSERDES_COM_PLL_IVCO			0x0048
+#define QSERDES_COM_CMN_IETRIM			0x004C
+#define QSERDES_COM_CMN_IPTRIM			0x0050
+
+#define QSERDES_COM_CP_CTRL_MODE0		0x0060
+#define QSERDES_COM_CP_CTRL_MODE1		0x0064
+#define QSERDES_COM_PLL_RCTRL_MODE0		0x0068
+#define QSERDES_COM_PLL_RCTRL_MODE1		0x006C
+#define QSERDES_COM_PLL_CCTRL_MODE0		0x0070
+#define QSERDES_COM_PLL_CCTRL_MODE1		0x0074
+#define QSERDES_COM_PLL_CNTRL			0x0078
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM		0x007C
+#define QSERDES_COM_SYSCLK_EN_SEL		0x0080
+#define QSERDES_COM_CML_SYSCLK_SEL		0x0084
+#define QSERDES_COM_RESETSM_CNTRL		0x0088
+#define QSERDES_COM_RESETSM_CNTRL2		0x008C
+#define QSERDES_COM_LOCK_CMP_EN			0x0090
+#define QSERDES_COM_LOCK_CMP_CFG		0x0094
+#define QSERDES_COM_LOCK_CMP1_MODE0		0x0098
+#define QSERDES_COM_LOCK_CMP2_MODE0		0x009C
+#define QSERDES_COM_LOCK_CMP3_MODE0		0x00A0
+
+#define QSERDES_COM_DEC_START_MODE0		0x00B0
+#define QSERDES_COM_DEC_START_MODE1		0x00B4
+#define QSERDES_COM_DIV_FRAC_START1_MODE0	0x00B8
+#define QSERDES_COM_DIV_FRAC_START2_MODE0	0x00BC
+#define QSERDES_COM_DIV_FRAC_START3_MODE0	0x00C0
+#define QSERDES_COM_DIV_FRAC_START1_MODE1	0x00C4
+#define QSERDES_COM_DIV_FRAC_START2_MODE1	0x00C8
+#define QSERDES_COM_DIV_FRAC_START3_MODE1	0x00CC
+#define QSERDES_COM_INTEGLOOP_INITVAL		0x00D0
+#define QSERDES_COM_INTEGLOOP_EN		0x00D4
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0	0x00D8
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0	0x00DC
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1	0x00E0
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1	0x00E4
+#define QSERDES_COM_VCOCAL_DEADMAN_CTRL		0x00E8
+#define QSERDES_COM_VCO_TUNE_CTRL		0x00EC
+#define QSERDES_COM_VCO_TUNE_MAP		0x00F0
+
+#define QSERDES_COM_CMN_STATUS			0x0124
+#define QSERDES_COM_RESET_SM_STATUS		0x0128
+
+#define QSERDES_COM_CLK_SEL			0x0138
+#define QSERDES_COM_HSCLK_SEL			0x013C
+
+#define QSERDES_COM_CORECLK_DIV_MODE0		0x0148
+
+#define QSERDES_COM_SW_RESET			0x0150
+#define QSERDES_COM_CORE_CLK_EN			0x0154
+#define QSERDES_COM_C_READY_STATUS		0x0158
+#define QSERDES_COM_CMN_CONFIG			0x015C
+
+#define QSERDES_COM_SVS_MODE_CLK_SEL		0x0164
+
+#define DP_PHY_PLL_POLL_SLEEP_US		500
+#define DP_PHY_PLL_POLL_TIMEOUT_US		10000
+
+#define DP_VCO_RATE_8100MHZDIV1000		8100000UL
+#define DP_VCO_RATE_9720MHZDIV1000		9720000UL
+#define DP_VCO_RATE_10800MHZDIV1000		10800000UL
+
+int dp_mux_set_parent_10nm(void *context, unsigned int reg, unsigned int val)
+{
+	struct mdss_pll_resources *dp_res = context;
+	int rc;
+	u32 auxclk_div;
+
+	rc = mdss_pll_resource_enable(dp_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss DP PLL resources\n");
+		return rc;
+	}
+
+	auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV);
+	auxclk_div &= ~0x03;	/* bits 0 to 1 */
+
+	if (val == 0) /* mux parent index = 0 */
+		auxclk_div |= 1;
+	else if (val == 1) /* mux parent index = 1 */
+		auxclk_div |= 2;
+	else if (val == 2) /* mux parent index = 2 */
+		auxclk_div |= 0;
+
+	MDSS_PLL_REG_W(dp_res->phy_base,
+			DP_PHY_VCO_DIV, auxclk_div);
+	/* Make sure the PHY registers writes are done */
+	wmb();
+	pr_debug("%s: mux=%d auxclk_div=%x\n", __func__, val, auxclk_div);
+
+	mdss_pll_resource_enable(dp_res, false);
+
+	return 0;
+}
+
+int dp_mux_get_parent_10nm(void *context, unsigned int reg, unsigned int *val)
+{
+	int rc;
+	u32 auxclk_div = 0;
+	struct mdss_pll_resources *dp_res = context;
+
+	rc = mdss_pll_resource_enable(dp_res, true);
+	if (rc) {
+		pr_err("Failed to enable dp_res resources\n");
+		return rc;
+	}
+
+	auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV);
+	auxclk_div &= 0x03;
+
+	if (auxclk_div == 1) /* Default divider */
+		*val = 0;
+	else if (auxclk_div == 2)
+		*val = 1;
+	else if (auxclk_div == 0)
+		*val = 2;
+
+	mdss_pll_resource_enable(dp_res, false);
+
+	pr_debug("%s: auxclk_div=%d, val=%d\n", __func__, auxclk_div, *val);
+
+	return 0;
+}
+
+static int dp_vco_pll_init_db_10nm(struct dp_pll_db *pdb,
+		unsigned long rate)
+{
+	struct mdss_pll_resources *dp_res = pdb->pll;
+	u32 spare_value = 0;
+
+	spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0);
+	pdb->lane_cnt = spare_value & 0x0F;
+	pdb->orientation = (spare_value & 0xF0) >> 4;
+
+	pr_debug("%s: spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n",
+			__func__, spare_value, pdb->lane_cnt, pdb->orientation);
+
+	switch (rate) {
+	case DP_VCO_HSCLK_RATE_1620MHZDIV1000:
+		pr_debug("%s: VCO rate: %ld\n", __func__,
+				DP_VCO_RATE_9720MHZDIV1000);
+		pdb->hsclk_sel = 0x0c;
+		pdb->dec_start_mode0 = 0x69;
+		pdb->div_frac_start1_mode0 = 0x00;
+		pdb->div_frac_start2_mode0 = 0x80;
+		pdb->div_frac_start3_mode0 = 0x07;
+		pdb->integloop_gain0_mode0 = 0x3f;
+		pdb->integloop_gain1_mode0 = 0x00;
+		pdb->vco_tune_map = 0x00;
+		pdb->lock_cmp1_mode0 = 0x6f;
+		pdb->lock_cmp2_mode0 = 0x08;
+		pdb->lock_cmp3_mode0 = 0x00;
+		pdb->phy_vco_div = 0x1;
+		pdb->lock_cmp_en = 0x00;
+		break;
+	case DP_VCO_HSCLK_RATE_2700MHZDIV1000:
+		pr_debug("%s: VCO rate: %ld\n", __func__,
+				DP_VCO_RATE_10800MHZDIV1000);
+		pdb->hsclk_sel = 0x04;
+		pdb->dec_start_mode0 = 0x69;
+		pdb->div_frac_start1_mode0 = 0x00;
+		pdb->div_frac_start2_mode0 = 0x80;
+		pdb->div_frac_start3_mode0 = 0x07;
+		pdb->integloop_gain0_mode0 = 0x3f;
+		pdb->integloop_gain1_mode0 = 0x00;
+		pdb->vco_tune_map = 0x00;
+		pdb->lock_cmp1_mode0 = 0x0f;
+		pdb->lock_cmp2_mode0 = 0x0e;
+		pdb->lock_cmp3_mode0 = 0x00;
+		pdb->phy_vco_div = 0x1;
+		pdb->lock_cmp_en = 0x00;
+		break;
+	case DP_VCO_HSCLK_RATE_5400MHZDIV1000:
+		pr_debug("%s: VCO rate: %ld\n", __func__,
+				DP_VCO_RATE_10800MHZDIV1000);
+		pdb->hsclk_sel = 0x00;
+		pdb->dec_start_mode0 = 0x8c;
+		pdb->div_frac_start1_mode0 = 0x00;
+		pdb->div_frac_start2_mode0 = 0x00;
+		pdb->div_frac_start3_mode0 = 0x0a;
+		pdb->integloop_gain0_mode0 = 0x3f;
+		pdb->integloop_gain1_mode0 = 0x00;
+		pdb->vco_tune_map = 0x00;
+		pdb->lock_cmp1_mode0 = 0x1f;
+		pdb->lock_cmp2_mode0 = 0x1c;
+		pdb->lock_cmp3_mode0 = 0x00;
+		pdb->phy_vco_div = 0x2;
+		pdb->lock_cmp_en = 0x00;
+		break;
+	case DP_VCO_HSCLK_RATE_8100MHZDIV1000:
+		pr_debug("%s: VCO rate: %ld\n", __func__,
+				DP_VCO_RATE_8100MHZDIV1000);
+		pdb->hsclk_sel = 0x03;
+		pdb->dec_start_mode0 = 0x69;
+		pdb->div_frac_start1_mode0 = 0x00;
+		pdb->div_frac_start2_mode0 = 0x80;
+		pdb->div_frac_start3_mode0 = 0x07;
+		pdb->integloop_gain0_mode0 = 0x3f;
+		pdb->integloop_gain1_mode0 = 0x00;
+		pdb->vco_tune_map = 0x00;
+		pdb->lock_cmp1_mode0 = 0x2f;
+		pdb->lock_cmp2_mode0 = 0x2a;
+		pdb->lock_cmp3_mode0 = 0x00;
+		pdb->phy_vco_div = 0x0;
+		pdb->lock_cmp_en = 0x08;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int dp_config_vco_rate_10nm(struct dp_pll_vco_clk *vco,
+		unsigned long rate)
+{
+	u32 res = 0;
+	struct mdss_pll_resources *dp_res = vco->priv;
+	struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv;
+
+	res = dp_vco_pll_init_db_10nm(pdb, rate);
+	if (res) {
+		pr_err("VCO Init DB failed\n");
+		return res;
+	}
+
+	if (pdb->lane_cnt != 4) {
+		if (pdb->orientation == ORIENTATION_CC2)
+			MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x6d);
+		else
+			MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x75);
+	} else {
+		MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x7d);
+	}
+
+	/* Make sure the PHY register writes are done */
+	wmb();
+
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, 0x01);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x37);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0e);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_SEL, 0x30);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CMN_CONFIG, 0x02);
+
+	/* Different for each clock rates */
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_HSCLK_SEL, pdb->hsclk_sel);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_DEC_START_MODE0, pdb->dec_start_mode0);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_DIV_FRAC_START1_MODE0, pdb->div_frac_start1_mode0);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_DIV_FRAC_START2_MODE0, pdb->div_frac_start2_mode0);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_DIV_FRAC_START3_MODE0, pdb->div_frac_start3_mode0);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_INTEGLOOP_GAIN0_MODE0, pdb->integloop_gain0_mode0);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_INTEGLOOP_GAIN1_MODE0, pdb->integloop_gain1_mode0);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_VCO_TUNE_MAP, pdb->vco_tune_map);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_LOCK_CMP1_MODE0, pdb->lock_cmp1_mode0);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_LOCK_CMP2_MODE0, pdb->lock_cmp2_mode0);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_LOCK_CMP3_MODE0, pdb->lock_cmp3_mode0);
+	/* Make sure the PLL register writes are done */
+	wmb();
+
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BG_TIMER, 0x0a);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORECLK_DIV_MODE0, 0x0a);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_VCO_TUNE_CTRL, 0x00);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORE_CLK_EN, 0x1f);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_IVCO, 0x07);
+	MDSS_PLL_REG_W(dp_res->pll_base,
+		QSERDES_COM_LOCK_CMP_EN, pdb->lock_cmp_en);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_CCTRL_MODE0, 0x36);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_RCTRL_MODE0, 0x16);
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CP_CTRL_MODE0, 0x06);
+	/* Make sure the PHY register writes are done */
+	wmb();
+
+	if (pdb->orientation == ORIENTATION_CC2)
+		MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x4c);
+	else
+		MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x5c);
+	/* Make sure the PLL register writes are done */
+	wmb();
+
+	/* TX Lane configuration */
+	MDSS_PLL_REG_W(dp_res->phy_base,
+			DP_PHY_TX0_TX1_LANE_CTL, 0x05);
+	MDSS_PLL_REG_W(dp_res->phy_base,
+			DP_PHY_TX2_TX3_LANE_CTL, 0x05);
+
+	/* TX-0 register configuration */
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TRANSCEIVER_BIAS_EN, 0x1a);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_VMODE_CTRL1, 0x40);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_INTERFACE_SELECT, 0x3d);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_CLKBUF_ENABLE, 0x0f);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RESET_TSYNC_EN, 0x03);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TRAN_DRVR_EMP_EN, 0x03);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base,
+		TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_INTERFACE_MODE, 0x00);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_BAND, 0x4);
+
+	/* TX-1 register configuration */
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TRANSCEIVER_BIAS_EN, 0x1a);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_VMODE_CTRL1, 0x40);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_INTERFACE_SELECT, 0x3d);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_CLKBUF_ENABLE, 0x0f);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RESET_TSYNC_EN, 0x03);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TRAN_DRVR_EMP_EN, 0x03);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base,
+		TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_INTERFACE_MODE, 0x00);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_BAND, 0x4);
+	/* Make sure the PHY register writes are done */
+	wmb();
+
+	/* dependent on the vco frequency */
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_VCO_DIV, pdb->phy_vco_div);
+
+	return res;
+}
+
+static bool dp_10nm_pll_lock_status(struct mdss_pll_resources *dp_res)
+{
+	u32 status;
+	bool pll_locked;
+
+	/* poll for PLL lock status */
+	if (readl_poll_timeout_atomic((dp_res->pll_base +
+			QSERDES_COM_C_READY_STATUS),
+			status,
+			((status & BIT(0)) > 0),
+			DP_PHY_PLL_POLL_SLEEP_US,
+			DP_PHY_PLL_POLL_TIMEOUT_US)) {
+		pr_err("%s: C_READY status is not high. Status=%x\n",
+				__func__, status);
+		pll_locked = false;
+	} else {
+		pll_locked = true;
+	}
+
+	return pll_locked;
+}
+
+static bool dp_10nm_phy_rdy_status(struct mdss_pll_resources *dp_res)
+{
+	u32 status;
+	bool phy_ready = true;
+
+	/* poll for PHY ready status */
+	if (readl_poll_timeout_atomic((dp_res->phy_base +
+			DP_PHY_STATUS),
+			status,
+			((status & (BIT(1))) > 0),
+			DP_PHY_PLL_POLL_SLEEP_US,
+			DP_PHY_PLL_POLL_TIMEOUT_US)) {
+		pr_err("%s: Phy_ready is not high. Status=%x\n",
+				__func__, status);
+		phy_ready = false;
+	}
+
+	return phy_ready;
+}
+
+static int dp_pll_enable_10nm(struct clk_hw *hw)
+{
+	int rc = 0;
+	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+	struct mdss_pll_resources *dp_res = vco->priv;
+	struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv;
+	u32 bias_en, drvr_en;
+
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_AUX_CFG2, 0x04);
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01);
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x05);
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01);
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x09);
+	wmb(); /* Make sure the PHY register writes are done */
+
+	MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20);
+	wmb();	/* Make sure the PLL register writes are done */
+
+	if (!dp_10nm_pll_lock_status(dp_res)) {
+		rc = -EINVAL;
+		goto lock_err;
+	}
+
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19);
+	/* Make sure the PHY register writes are done */
+	wmb();
+	/* poll for PHY ready status */
+	if (!dp_10nm_phy_rdy_status(dp_res)) {
+		rc = -EINVAL;
+		goto lock_err;
+	}
+
+	pr_debug("%s: PLL is locked\n", __func__);
+
+	if (pdb->lane_cnt == 1) {
+		bias_en = 0x3e;
+		drvr_en = 0x13;
+	} else {
+		bias_en = 0x3f;
+		drvr_en = 0x10;
+	}
+
+	if (pdb->lane_cnt != 4) {
+		if (pdb->orientation == ORIENTATION_CC1) {
+			MDSS_PLL_REG_W(dp_res->ln_tx1_base,
+				TXn_HIGHZ_DRVR_EN, drvr_en);
+			MDSS_PLL_REG_W(dp_res->ln_tx1_base,
+				TXn_TRANSCEIVER_BIAS_EN, bias_en);
+		} else {
+			MDSS_PLL_REG_W(dp_res->ln_tx0_base,
+				TXn_HIGHZ_DRVR_EN, drvr_en);
+			MDSS_PLL_REG_W(dp_res->ln_tx0_base,
+				TXn_TRANSCEIVER_BIAS_EN, bias_en);
+		}
+	} else {
+		MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_HIGHZ_DRVR_EN, drvr_en);
+		MDSS_PLL_REG_W(dp_res->ln_tx0_base,
+			TXn_TRANSCEIVER_BIAS_EN, bias_en);
+		MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_HIGHZ_DRVR_EN, drvr_en);
+		MDSS_PLL_REG_W(dp_res->ln_tx1_base,
+			TXn_TRANSCEIVER_BIAS_EN, bias_en);
+	}
+
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_POL_INV, 0x0a);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_POL_INV, 0x0a);
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x18);
+	udelay(2000);
+
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19);
+
+	/*
+	 * Make sure all the register writes are completed before
+	 * doing any other operation
+	 */
+	wmb();
+
+	/* poll for PHY ready status */
+	if (!dp_10nm_phy_rdy_status(dp_res)) {
+		rc = -EINVAL;
+		goto lock_err;
+	}
+
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_DRV_LVL, 0x38);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_DRV_LVL, 0x38);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_EMP_POST1_LVL, 0x20);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_EMP_POST1_LVL, 0x20);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x06);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x06);
+	MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x07);
+	MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x07);
+	/* Make sure the PHY register writes are done */
+	wmb();
+
+lock_err:
+	return rc;
+}
+
+static int dp_pll_disable_10nm(struct clk_hw *hw)
+{
+	int rc = 0;
+	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+	struct mdss_pll_resources *dp_res = vco->priv;
+
+	/* Assert DP PHY power down */
+	MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x2);
+	/*
+	 * Make sure all the register writes to disable PLL are
+	 * completed before doing any other operation
+	 */
+	wmb();
+
+	return rc;
+}
+
+
+int dp_vco_prepare_10nm(struct clk_hw *hw)
+{
+	int rc = 0;
+	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+	struct mdss_pll_resources *dp_res = vco->priv;
+
+	pr_debug("rate=%ld\n", vco->rate);
+	rc = mdss_pll_resource_enable(dp_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss DP pll resources\n");
+		goto error;
+	}
+
+	if ((dp_res->vco_cached_rate != 0)
+		&& (dp_res->vco_cached_rate == vco->rate)) {
+		rc = vco->hw.init->ops->set_rate(hw,
+			dp_res->vco_cached_rate, dp_res->vco_cached_rate);
+		if (rc) {
+			pr_err("index=%d vco_set_rate failed. rc=%d\n",
+				rc, dp_res->index);
+			mdss_pll_resource_enable(dp_res, false);
+			goto error;
+		}
+	}
+
+	rc = dp_pll_enable_10nm(hw);
+	if (rc) {
+		mdss_pll_resource_enable(dp_res, false);
+		pr_err("ndx=%d failed to enable dp pll\n",
+					dp_res->index);
+		goto error;
+	}
+
+	mdss_pll_resource_enable(dp_res, false);
+error:
+	return rc;
+}
+
+void dp_vco_unprepare_10nm(struct clk_hw *hw)
+{
+	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+	struct mdss_pll_resources *dp_res = vco->priv;
+
+	if (!dp_res) {
+		pr_err("Invalid input parameter\n");
+		return;
+	}
+
+	if (!dp_res->pll_on &&
+		mdss_pll_resource_enable(dp_res, true)) {
+		pr_err("pll resource can't be enabled\n");
+		return;
+	}
+	dp_res->vco_cached_rate = vco->rate;
+	dp_pll_disable_10nm(hw);
+
+	dp_res->handoff_resources = false;
+	mdss_pll_resource_enable(dp_res, false);
+	dp_res->pll_on = false;
+}
+
+int dp_vco_set_rate_10nm(struct clk_hw *hw, unsigned long rate,
+					unsigned long parent_rate)
+{
+	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+	struct mdss_pll_resources *dp_res = vco->priv;
+	int rc;
+
+	rc = mdss_pll_resource_enable(dp_res, true);
+	if (rc) {
+		pr_err("pll resource can't be enabled\n");
+		return rc;
+	}
+
+	pr_debug("DP lane CLK rate=%ld\n", rate);
+
+	rc = dp_config_vco_rate_10nm(vco, rate);
+	if (rc)
+		pr_err("%s: Failed to set clk rate\n", __func__);
+
+	mdss_pll_resource_enable(dp_res, false);
+
+	vco->rate = rate;
+
+	return 0;
+}
+
+unsigned long dp_vco_recalc_rate_10nm(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+	int rc;
+	u32 div, hsclk_div, link_clk_div = 0;
+	u64 vco_rate;
+	struct mdss_pll_resources *dp_res = vco->priv;
+
+	rc = mdss_pll_resource_enable(dp_res, true);
+	if (rc) {
+		pr_err("Failed to enable mdss DP pll=%d\n", dp_res->index);
+		return rc;
+	}
+
+	div = MDSS_PLL_REG_R(dp_res->pll_base, QSERDES_COM_HSCLK_SEL);
+	div &= 0x0f;
+
+	if (div == 12)
+		hsclk_div = 6; /* Default */
+	else if (div == 4)
+		hsclk_div = 4;
+	else if (div == 0)
+		hsclk_div = 2;
+	else if (div == 3)
+		hsclk_div = 1;
+	else {
+		pr_debug("unknown divider. forcing to default\n");
+		hsclk_div = 5;
+	}
+
+	div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_AUX_CFG2);
+	div >>= 2;
+
+	if ((div & 0x3) == 0)
+		link_clk_div = 5;
+	else if ((div & 0x3) == 1)
+		link_clk_div = 10;
+	else if ((div & 0x3) == 2)
+		link_clk_div = 20;
+	else
+		pr_err("%s: unsupported div. Phy_mode: %d\n", __func__, div);
+
+	if (link_clk_div == 20) {
+		vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
+	} else {
+		if (hsclk_div == 6)
+			vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000;
+		else if (hsclk_div == 4)
+			vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
+		else if (hsclk_div == 2)
+			vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000;
+		else
+			vco_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000;
+	}
+
+	pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+
+	mdss_pll_resource_enable(dp_res, false);
+
+	dp_res->vco_cached_rate = vco->rate = vco_rate;
+	return (unsigned long)vco_rate;
+}
+
+long dp_vco_round_rate_10nm(struct clk_hw *hw, unsigned long rate,
+			unsigned long *parent_rate)
+{
+	unsigned long rrate = rate;
+	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
+
+	if (rate <= vco->min_rate)
+		rrate = vco->min_rate;
+	else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000)
+		rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
+	else if (rate <= DP_VCO_HSCLK_RATE_5400MHZDIV1000)
+		rrate = DP_VCO_HSCLK_RATE_5400MHZDIV1000;
+	else
+		rrate = vco->max_rate;
+
+	pr_debug("%s: rrate=%ld\n", __func__, rrate);
+
+	*parent_rate = rrate;
+	return rrate;
+}
+
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c
new file mode 100644
index 0000000..e30ef82
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c
@@ -0,0 +1,310 @@
+/* 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.
+ *
+ */
+
+/*
+ * Display Port PLL driver block diagram for branch clocks
+ *
+ *		+------------------------------+
+ *		|         DP_VCO_CLK           |
+ *		|                              |
+ *		|    +-------------------+     |
+ *		|    |   (DP PLL/VCO)    |     |
+ *		|    +---------+---------+     |
+ *		|              v               |
+ *		|   +----------+-----------+   |
+ *		|   | hsclk_divsel_clk_src |   |
+ *		|   +----------+-----------+   |
+ *		+------------------------------+
+ *				|
+ *	 +------------<---------v------------>----------+
+ *	 |                                              |
+ * +-----v------------+                                 |
+ * | dp_link_clk_src  |                                 |
+ * |    divsel_ten    |                                 |
+ * +---------+--------+                                 |
+ *	|                                               |
+ *	|                                               |
+ *	v                                               v
+ * Input to DISPCC block                                |
+ * for link clk, crypto clk                             |
+ * and interface clock                                  |
+ *							|
+ *							|
+ *	+--------<------------+-----------------+---<---+
+ *	|                     |                 |
+ * +-------v------+  +--------v-----+  +--------v------+
+ * | vco_divided  |  | vco_divided  |  | vco_divided   |
+ * |    _clk_src  |  |    _clk_src  |  |    _clk_src   |
+ * |              |  |              |  |               |
+ * |divsel_six    |  |  divsel_two  |  |  divsel_four  |
+ * +-------+------+  +-----+--------+  +--------+------+
+ *         |	           |		        |
+ *	v------->----------v-------------<------v
+ *                         |
+ *		+----------+---------+
+ *		|   vco_divided_clk  |
+ *		|       _src_mux     |
+ *		+---------+----------+
+ *                        |
+ *                        v
+ *              Input to DISPCC block
+ *              for DP pixel clock
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+
+#include "mdss-pll.h"
+#include "mdss-dp-pll.h"
+#include "mdss-dp-pll-10nm.h"
+
+static struct dp_pll_db dp_pdb;
+static struct clk_ops mux_clk_ops;
+
+static struct regmap_config dp_pll_10nm_cfg = {
+	.reg_bits	= 32,
+	.reg_stride	= 4,
+	.val_bits	= 32,
+	.max_register = 0x910,
+};
+
+static struct regmap_bus dp_pixel_mux_regmap_ops = {
+	.reg_write = dp_mux_set_parent_10nm,
+	.reg_read = dp_mux_get_parent_10nm,
+};
+
+/* Op structures */
+static const struct clk_ops dp_10nm_vco_clk_ops = {
+	.recalc_rate = dp_vco_recalc_rate_10nm,
+	.set_rate = dp_vco_set_rate_10nm,
+	.round_rate = dp_vco_round_rate_10nm,
+	.prepare = dp_vco_prepare_10nm,
+	.unprepare = dp_vco_unprepare_10nm,
+};
+
+static struct dp_pll_vco_clk dp_vco_clk = {
+	.min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000,
+	.max_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000,
+	.hw.init = &(struct clk_init_data){
+		.name = "dp_vco_clk",
+		.parent_names = (const char *[]){ "xo_board" },
+		.num_parents = 1,
+		.ops = &dp_10nm_vco_clk_ops,
+	},
+};
+
+static struct clk_fixed_factor dp_link_clk_divsel_ten = {
+	.div = 10,
+	.mult = 1,
+
+	.hw.init = &(struct clk_init_data){
+		.name = "dp_link_clk_divsel_ten",
+		.parent_names =
+			(const char *[]){ "dp_vco_clk" },
+		.num_parents = 1,
+		.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_fixed_factor dp_vco_divsel_two_clk_src = {
+	.div = 2,
+	.mult = 1,
+
+	.hw.init = &(struct clk_init_data){
+		.name = "dp_vco_divsel_two_clk_src",
+		.parent_names =
+			(const char *[]){ "dp_vco_clk" },
+		.num_parents = 1,
+		.flags = (CLK_GET_RATE_NOCACHE),
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_fixed_factor dp_vco_divsel_four_clk_src = {
+	.div = 4,
+	.mult = 1,
+
+	.hw.init = &(struct clk_init_data){
+		.name = "dp_vco_divsel_four_clk_src",
+		.parent_names =
+			(const char *[]){ "dp_vco_clk" },
+		.num_parents = 1,
+		.flags = (CLK_GET_RATE_NOCACHE),
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+static struct clk_fixed_factor dp_vco_divsel_six_clk_src = {
+	.div = 6,
+	.mult = 1,
+
+	.hw.init = &(struct clk_init_data){
+		.name = "dp_vco_divsel_six_clk_src",
+		.parent_names =
+			(const char *[]){ "dp_vco_clk" },
+		.num_parents = 1,
+		.flags = (CLK_GET_RATE_NOCACHE),
+		.ops = &clk_fixed_factor_ops,
+	},
+};
+
+
+static int clk_mux_determine_rate(struct clk_hw *hw,
+				     struct clk_rate_request *req)
+{
+	int ret = 0;
+
+	ret = __clk_mux_determine_rate_closest(hw, req);
+	if (ret)
+		return ret;
+
+	/* Set the new parent of mux if there is a new valid parent */
+	if (hw->clk && req->best_parent_hw->clk)
+		clk_set_parent(hw->clk, req->best_parent_hw->clk);
+
+	return 0;
+}
+
+static unsigned long mux_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
+{
+	struct clk *div_clk = NULL, *vco_clk = NULL;
+	struct dp_pll_vco_clk *vco = NULL;
+
+	div_clk = clk_get_parent(hw->clk);
+	if (!div_clk)
+		return 0;
+
+	vco_clk = clk_get_parent(div_clk);
+	if (!vco_clk)
+		return 0;
+
+	vco = to_dp_vco_hw(__clk_get_hw(vco_clk));
+	if (!vco)
+		return 0;
+
+	if (vco->rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000)
+		return (vco->rate / 6);
+	else if (vco->rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000)
+		return (vco->rate / 4);
+	else
+		return (vco->rate / 2);
+}
+
+static struct clk_regmap_mux dp_vco_divided_clk_src_mux = {
+	.reg = 0x64,
+	.shift = 0,
+	.width = 2,
+
+	.clkr = {
+		.hw.init = &(struct clk_init_data){
+			.name = "dp_vco_divided_clk_src_mux",
+			.parent_names =
+				(const char *[]){"dp_vco_divsel_two_clk_src",
+					"dp_vco_divsel_four_clk_src",
+					"dp_vco_divsel_six_clk_src"},
+			.num_parents = 3,
+			.ops = &mux_clk_ops,
+			.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
+		},
+	},
+};
+
+static struct clk_hw *mdss_dp_pllcc_10nm[] = {
+	[DP_VCO_CLK] = &dp_vco_clk.hw,
+	[DP_LINK_CLK_DIVSEL_TEN] = &dp_link_clk_divsel_ten.hw,
+	[DP_VCO_DIVIDED_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw,
+	[DP_VCO_DIVIDED_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw,
+	[DP_VCO_DIVIDED_SIX_CLK_SRC] = &dp_vco_divsel_six_clk_src.hw,
+	[DP_VCO_DIVIDED_CLK_SRC_MUX] = &dp_vco_divided_clk_src_mux.clkr.hw,
+};
+
+int dp_pll_clock_register_10nm(struct platform_device *pdev,
+				 struct mdss_pll_resources *pll_res)
+{
+	int rc = -ENOTSUPP, i = 0;
+	struct clk_onecell_data *clk_data;
+	struct clk *clk;
+	struct regmap *regmap;
+	int num_clks = ARRAY_SIZE(mdss_dp_pllcc_10nm);
+
+	if (!pdev || !pdev->dev.of_node) {
+		pr_err("Invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	if (!pll_res || !pll_res->pll_base || !pll_res->phy_base ||
+		!pll_res->ln_tx0_base || !pll_res->ln_tx1_base) {
+		pr_err("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
+					GFP_KERNEL);
+	if (!clk_data)
+		return -ENOMEM;
+
+	clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks *
+				sizeof(struct clk *)), GFP_KERNEL);
+	if (!clk_data->clks) {
+		devm_kfree(&pdev->dev, clk_data);
+		return -ENOMEM;
+	}
+	clk_data->clk_num = num_clks;
+
+	pll_res->priv = &dp_pdb;
+	dp_pdb.pll = pll_res;
+
+	/* Set client data for vco, mux and div clocks */
+	regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops,
+			pll_res, &dp_pll_10nm_cfg);
+	dp_vco_divided_clk_src_mux.clkr.regmap = regmap;
+	mux_clk_ops = clk_regmap_mux_closest_ops;
+	mux_clk_ops.determine_rate = clk_mux_determine_rate;
+	mux_clk_ops.recalc_rate = mux_recalc_rate;
+
+	dp_vco_clk.priv = pll_res;
+
+	for (i = DP_VCO_CLK; i <= DP_VCO_DIVIDED_CLK_SRC_MUX; i++) {
+		pr_debug("reg clk: %d index: %d\n", i, pll_res->index);
+		clk = devm_clk_register(&pdev->dev,
+				mdss_dp_pllcc_10nm[i]);
+		if (IS_ERR(clk)) {
+			pr_err("clk registration failed for DP: %d\n",
+					pll_res->index);
+			rc = -EINVAL;
+			goto clk_reg_fail;
+		}
+		clk_data->clks[i] = clk;
+	}
+
+	rc = of_clk_add_provider(pdev->dev.of_node,
+			of_clk_src_onecell_get, clk_data);
+	if (rc) {
+		pr_err("%s: Clock register failed rc=%d\n", __func__, rc);
+		rc = -EPROBE_DEFER;
+	} else {
+		pr_debug("%s SUCCESS\n", __func__);
+	}
+	return 0;
+clk_reg_fail:
+	devm_kfree(&pdev->dev, clk_data->clks);
+	devm_kfree(&pdev->dev, clk_data);
+	return rc;
+}
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.h b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.h
new file mode 100644
index 0000000..c3b5635
--- /dev/null
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.h
@@ -0,0 +1,59 @@
+/* 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 __MDSS_DP_PLL_10NM_H
+#define __MDSS_DP_PLL_10NM_H
+
+#define DP_VCO_HSCLK_RATE_1620MHZDIV1000	1620000UL
+#define DP_VCO_HSCLK_RATE_2700MHZDIV1000	2700000UL
+#define DP_VCO_HSCLK_RATE_5400MHZDIV1000	5400000UL
+#define DP_VCO_HSCLK_RATE_8100MHZDIV1000	8100000UL
+
+struct dp_pll_db {
+	struct mdss_pll_resources *pll;
+
+	/* lane and orientation settings */
+	u8 lane_cnt;
+	u8 orientation;
+
+	/* COM PHY settings */
+	u32 hsclk_sel;
+	u32 dec_start_mode0;
+	u32 div_frac_start1_mode0;
+	u32 div_frac_start2_mode0;
+	u32 div_frac_start3_mode0;
+	u32 integloop_gain0_mode0;
+	u32 integloop_gain1_mode0;
+	u32 vco_tune_map;
+	u32 lock_cmp1_mode0;
+	u32 lock_cmp2_mode0;
+	u32 lock_cmp3_mode0;
+	u32 lock_cmp_en;
+
+	/* PHY vco divider */
+	u32 phy_vco_div;
+};
+
+int dp_vco_set_rate_10nm(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate);
+unsigned long dp_vco_recalc_rate_10nm(struct clk_hw *hw,
+				unsigned long parent_rate);
+long dp_vco_round_rate_10nm(struct clk_hw *hw, unsigned long rate,
+				unsigned long *parent_rate);
+int dp_vco_prepare_10nm(struct clk_hw *hw);
+void dp_vco_unprepare_10nm(struct clk_hw *hw);
+int dp_mux_set_parent_10nm(void *context,
+				unsigned int reg, unsigned int val);
+int dp_mux_get_parent_10nm(void *context,
+				unsigned int reg, unsigned int *val);
+#endif /* __MDSS_DP_PLL_10NM_H */
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c b/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c
deleted file mode 100644
index a3ed8a8..0000000
--- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998-util.c
+++ /dev/null
@@ -1,774 +0,0 @@
-/* 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/kernel.h>
-#include <linux/err.h>
-#include <linux/iopoll.h>
-#include <linux/delay.h>
-#include <linux/clk/msm-clock-generic.h>
-
-#include "mdss-pll.h"
-#include "mdss-dp-pll.h"
-#include "mdss-dp-pll-8998.h"
-
-int link2xclk_divsel_set_div(struct div_clk *clk, int div)
-{
-	int rc;
-	u32 link2xclk_div_tx0, link2xclk_div_tx1;
-	u32 phy_mode;
-	struct mdss_pll_resources *dp_res = clk->priv;
-
-	rc = mdss_pll_resource_enable(dp_res, true);
-	if (rc) {
-		pr_err("Failed to enable mdss DP PLL resources\n");
-		return rc;
-	}
-
-	link2xclk_div_tx0 = MDSS_PLL_REG_R(dp_res->phy_base,
-				QSERDES_TX0_OFFSET + TXn_TX_BAND);
-	link2xclk_div_tx1 = MDSS_PLL_REG_R(dp_res->phy_base,
-				QSERDES_TX1_OFFSET + TXn_TX_BAND);
-
-	link2xclk_div_tx0 &= ~0x07;	/* bits 0 to 2 */
-	link2xclk_div_tx1 &= ~0x07;	/* bits 0 to 2 */
-
-	/* Configure TX band Mux */
-	link2xclk_div_tx0 |= 0x4;
-	link2xclk_div_tx1 |= 0x4;
-
-	/*configure DP PHY MODE */
-	phy_mode = 0x58;
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TX_BAND,
-			link2xclk_div_tx0);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TX_BAND,
-			link2xclk_div_tx1);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_MODE, phy_mode);
-	/* Make sure the PHY register writes are done */
-	wmb();
-
-	pr_debug("%s: div=%d link2xclk_div_tx0=%x, link2xclk_div_tx1=%x\n",
-			__func__, div, link2xclk_div_tx0, link2xclk_div_tx1);
-
-	mdss_pll_resource_enable(dp_res, false);
-
-	return rc;
-}
-
-int link2xclk_divsel_get_div(struct div_clk *clk)
-{
-	int rc;
-	u32 div = 0, phy_mode;
-	struct mdss_pll_resources *dp_res = clk->priv;
-
-	rc = mdss_pll_resource_enable(dp_res, true);
-	if (rc) {
-		pr_err("Failed to enable dp_res resources\n");
-		return rc;
-	}
-
-	phy_mode = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_MODE);
-
-	if (phy_mode & 0x48)
-		pr_err("%s: DP PAR Rate not correct\n", __func__);
-
-	if ((phy_mode & 0x3) == 1)
-		div = 10;
-	else if ((phy_mode & 0x3) == 0)
-		div = 5;
-	else
-		pr_err("%s: unsupported div: %d\n", __func__, phy_mode);
-
-	mdss_pll_resource_enable(dp_res, false);
-	pr_debug("%s: phy_mode=%d, div=%d\n", __func__,
-						phy_mode, div);
-
-	return div;
-}
-
-int vco_divided_clk_set_div(struct div_clk *clk, int div)
-{
-	int rc;
-	u32 auxclk_div;
-	struct mdss_pll_resources *dp_res = clk->priv;
-
-	rc = mdss_pll_resource_enable(dp_res, true);
-	if (rc) {
-		pr_err("Failed to enable mdss DP PLL resources\n");
-		return rc;
-	}
-
-	auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV);
-	auxclk_div &= ~0x03;	/* bits 0 to 1 */
-
-	auxclk_div |= 1; /* Default divider */
-
-	if (div == 4)
-		auxclk_div |= 2;
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_VCO_DIV, auxclk_div);
-	/* Make sure the PHY registers writes are done */
-	wmb();
-	pr_debug("%s: div=%d auxclk_div=%x\n", __func__, div, auxclk_div);
-
-	mdss_pll_resource_enable(dp_res, false);
-
-	return rc;
-}
-
-
-enum handoff vco_divided_clk_handoff(struct clk *c)
-{
-	/*
-	 * Since cont-splash is not enabled, disable handoff
-	 * for vco_divider_clk.
-	 */
-	return HANDOFF_DISABLED_CLK;
-}
-
-int vco_divided_clk_get_div(struct div_clk *clk)
-{
-	int rc;
-	u32 div, auxclk_div;
-	struct mdss_pll_resources *dp_res = clk->priv;
-
-	rc = mdss_pll_resource_enable(dp_res, true);
-	if (rc) {
-		pr_err("Failed to enable dp_res resources\n");
-		return rc;
-	}
-
-	auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV);
-	auxclk_div &= 0x03;
-
-	div = 2; /* Default divider */
-	if (auxclk_div == 2)
-		div = 4;
-
-	mdss_pll_resource_enable(dp_res, false);
-
-	pr_debug("%s: auxclk_div=%d, div=%d\n", __func__, auxclk_div, div);
-
-	return div;
-}
-
-int dp_config_vco_rate(struct dp_pll_vco_clk *vco, unsigned long rate)
-{
-	u32 res = 0;
-	struct mdss_pll_resources *dp_res = vco->priv;
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_PD_CTL, 0x3d);
-	/* Make sure the PHY register writes are done */
-	wmb();
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_SVS_MODE_CLK_SEL, 0x01);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_SYSCLK_EN_SEL, 0x37);
-
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_CLK_ENABLE1, 0x0e);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_CLK_SEL, 0x30);
-
-	/* Different for each clock rates */
-	if (rate == DP_VCO_HSCLK_RATE_1620MHZDIV1000) {
-		pr_debug("%s: VCO rate: %ld\n", __func__,
-				DP_VCO_RATE_8100MHZDIV1000);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_SYS_CLK_CTRL, 0x02);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_HSCLK_SEL, 0x2c);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP_EN, 0x04);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DEC_START_MODE0, 0x69);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_CMN_CONFIG, 0x42);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP1_MODE0, 0xbf);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP2_MODE0, 0x21);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP3_MODE0, 0x00);
-	} else if (rate == DP_VCO_HSCLK_RATE_2700MHZDIV1000) {
-		pr_debug("%s: VCO rate: %ld\n", __func__,
-				DP_VCO_RATE_8100MHZDIV1000);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_SYS_CLK_CTRL, 0x06);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_HSCLK_SEL, 0x84);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP_EN, 0x08);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DEC_START_MODE0, 0x69);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START2_MODE0, 0x80);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START3_MODE0, 0x07);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_CMN_CONFIG, 0x02);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP1_MODE0, 0x3f);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP2_MODE0, 0x38);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP3_MODE0, 0x00);
-	} else if (rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) {
-		pr_debug("%s: VCO rate: %ld\n", __func__,
-				DP_VCO_RATE_10800MHZDIV1000);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_SYS_CLK_CTRL, 0x06);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_HSCLK_SEL, 0x80);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP_EN, 0x08);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DEC_START_MODE0, 0x8c);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_DIV_FRAC_START3_MODE0, 0xa0);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_CMN_CONFIG, 0x12);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP1_MODE0, 0x7f);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP2_MODE0, 0x70);
-		MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_LOCK_CMP3_MODE0, 0x00);
-	} else {
-		pr_err("%s: unsupported rate: %ld\n", __func__, rate);
-		return -EINVAL;
-	}
-	/* Make sure the PLL register writes are done */
-	wmb();
-
-	if ((rate == DP_VCO_HSCLK_RATE_1620MHZDIV1000)
-	    || (rate == DP_VCO_HSCLK_RATE_2700MHZDIV1000)) {
-		MDSS_PLL_REG_W(dp_res->phy_base,
-				DP_PHY_VCO_DIV, 0x1);
-	} else {
-		MDSS_PLL_REG_W(dp_res->phy_base,
-				DP_PHY_VCO_DIV, 0x2);
-	}
-	/* Make sure the PHY register writes are done */
-	wmb();
-
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3f);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_VCO_TUNE_MAP, 0x00);
-
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_BG_TIMER, 0x00);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_BG_TIMER, 0x0a);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_CORECLK_DIV_MODE0, 0x05);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_VCO_TUNE_CTRL, 0x00);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_CP_CTRL_MODE0, 0x06);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_PLL_CCTRL_MODE0, 0x36);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_PLL_RCTRL_MODE0, 0x16);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_PLL_IVCO, 0x07);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x37);
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_CORE_CLK_EN, 0x0f);
-
-	/* Make sure the PLL register writes are done */
-	wmb();
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_MODE, 0x58);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_TX0_TX1_LANE_CTL, 0x05);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_TX2_TX3_LANE_CTL, 0x05);
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
-			0x1a);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
-			0x1a);
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_VMODE_CTRL1,
-			0x40);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_VMODE_CTRL1,
-			0x40);
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN,
-			0x30);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN,
-			0x30);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_INTERFACE_SELECT,
-			0x3d);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_INTERFACE_SELECT,
-			0x3d);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE,
-			0x0f);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE,
-			0x0f);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_RESET_TSYNC_EN,
-			0x03);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_RESET_TSYNC_EN,
-			0x03);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TRAN_DRVR_EMP_EN,
-			0x03);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TRAN_DRVR_EMP_EN,
-			0x03);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN,
-			0x00);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN,
-			0x00);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TX_INTERFACE_MODE,
-			0x00);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TX_INTERFACE_MODE,
-			0x00);
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TX_BAND,
-			0x4);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TX_BAND,
-			0x4);
-	/* Make sure the PHY register writes are done */
-	wmb();
-	return res;
-}
-
-static bool dp_pll_lock_status(struct mdss_pll_resources *dp_res)
-{
-	u32 status;
-	bool pll_locked;
-
-	/* poll for PLL ready status */
-	if (readl_poll_timeout_atomic((dp_res->pll_base +
-			QSERDES_COM_C_READY_STATUS),
-			status,
-			((status & BIT(0)) > 0),
-			DP_PLL_POLL_SLEEP_US,
-			DP_PLL_POLL_TIMEOUT_US)) {
-		pr_err("%s: C_READY status is not high. Status=%x\n",
-				__func__, status);
-		pll_locked = false;
-	} else if (readl_poll_timeout_atomic((dp_res->pll_base +
-			DP_PHY_STATUS),
-			status,
-			((status & BIT(1)) > 0),
-			DP_PLL_POLL_SLEEP_US,
-			DP_PLL_POLL_TIMEOUT_US)) {
-		pr_err("%s: Phy_ready is not high. Status=%x\n",
-				__func__, status);
-		pll_locked = false;
-	} else {
-		pll_locked = true;
-	}
-
-	return pll_locked;
-}
-
-
-static int dp_pll_enable(struct clk *c)
-{
-	int rc = 0;
-	u32 status;
-	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-	struct mdss_pll_resources *dp_res = vco->priv;
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x01);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x05);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x01);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x09);
-	/* Make sure the PHY register writes are done */
-	wmb();
-	MDSS_PLL_REG_W(dp_res->pll_base,
-			QSERDES_COM_RESETSM_CNTRL, 0x20);
-	/* Make sure the PLL register writes are done */
-	wmb();
-	/* poll for PLL ready status */
-	if (readl_poll_timeout_atomic((dp_res->pll_base +
-			QSERDES_COM_C_READY_STATUS),
-			status,
-			((status & BIT(0)) > 0),
-			DP_PLL_POLL_SLEEP_US,
-			DP_PLL_POLL_TIMEOUT_US)) {
-		pr_err("%s: C_READY status is not high. Status=%x\n",
-				__func__, status);
-		rc = -EINVAL;
-		goto lock_err;
-	}
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x19);
-	/* Make sure the PHY register writes are done */
-	wmb();
-	/* poll for PHY ready status */
-	if (readl_poll_timeout_atomic((dp_res->phy_base +
-			DP_PHY_STATUS),
-			status,
-			((status & BIT(1)) > 0),
-			DP_PLL_POLL_SLEEP_US,
-			DP_PLL_POLL_TIMEOUT_US)) {
-		pr_err("%s: Phy_ready is not high. Status=%x\n",
-				__func__, status);
-		rc = -EINVAL;
-		goto lock_err;
-	}
-
-	pr_debug("%s: PLL is locked\n", __func__);
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
-			0x3f);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN,
-			0x10);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN,
-			0x3f);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN,
-			0x10);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TX_POL_INV,
-			0x0a);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TX_POL_INV,
-			0x0a);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x18);
-	udelay(2000);
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x19);
-
-	/*
-	 * Make sure all the register writes are completed before
-	 * doing any other operation
-	 */
-	wmb();
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_LANE_MODE_1,
-			0xf6);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_LANE_MODE_1,
-			0xf6);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE,
-			0x1f);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE,
-			0x1f);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE,
-			0x0f);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE,
-			0x0f);
-	/*
-	 * Make sure all the register writes are completed before
-	 * doing any other operation
-	 */
-	wmb();
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x09);
-	udelay(2000);
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_CFG, 0x19);
-	udelay(2000);
-	/* poll for PHY ready status */
-	if (readl_poll_timeout_atomic((dp_res->phy_base +
-			DP_PHY_STATUS),
-			status,
-			((status & BIT(1)) > 0),
-			DP_PLL_POLL_SLEEP_US,
-			DP_PLL_POLL_TIMEOUT_US)) {
-		pr_err("%s: Lane_mode: Phy_ready is not high. Status=%x\n",
-				__func__, status);
-		rc = -EINVAL;
-		goto lock_err;
-	}
-
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TX_DRV_LVL,
-			0x2a);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TX_DRV_LVL,
-			0x2a);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_TX_EMP_POST1_LVL,
-			0x20);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_TX_EMP_POST1_LVL,
-			0x20);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_RES_CODE_LANE_OFFSET_TX,
-			0x11);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_RES_CODE_LANE_OFFSET_TX,
-			0x11);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX0_OFFSET + TXn_RES_CODE_LANE_OFFSET_RX,
-			0x11);
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			QSERDES_TX1_OFFSET + TXn_RES_CODE_LANE_OFFSET_RX,
-			0x11);
-	/* Make sure the PHY register writes are done */
-	wmb();
-
-lock_err:
-	return rc;
-}
-
-static int dp_pll_disable(struct clk *c)
-{
-	int rc = 0;
-	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-	struct mdss_pll_resources *dp_res = vco->priv;
-
-	/* Assert DP PHY power down */
-	MDSS_PLL_REG_W(dp_res->phy_base,
-			DP_PHY_PD_CTL, 0x2);
-	/*
-	 * Make sure all the register writes to disable PLL are
-	 * completed before doing any other operation
-	 */
-	wmb();
-
-	return rc;
-}
-
-
-int dp_vco_prepare(struct clk *c)
-{
-	int rc = 0;
-	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-	struct mdss_pll_resources *dp_pll_res = vco->priv;
-
-	DEV_DBG("rate=%ld\n", vco->rate);
-	rc = mdss_pll_resource_enable(dp_pll_res, true);
-	if (rc) {
-		pr_err("Failed to enable mdss DP pll resources\n");
-		goto error;
-	}
-
-	rc = dp_pll_enable(c);
-	if (rc) {
-		mdss_pll_resource_enable(dp_pll_res, false);
-		pr_err("ndx=%d failed to enable dsi pll\n",
-					dp_pll_res->index);
-		goto error;
-	}
-
-	mdss_pll_resource_enable(dp_pll_res, false);
-error:
-	return rc;
-}
-
-void dp_vco_unprepare(struct clk *c)
-{
-	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-	struct mdss_pll_resources *io = vco->priv;
-
-	if (!io) {
-		DEV_ERR("Invalid input parameter\n");
-		return;
-	}
-
-	if (!io->pll_on &&
-		mdss_pll_resource_enable(io, true)) {
-		DEV_ERR("pll resource can't be enabled\n");
-		return;
-	}
-	dp_pll_disable(c);
-
-	io->handoff_resources = false;
-	mdss_pll_resource_enable(io, false);
-	io->pll_on = false;
-}
-
-int dp_vco_set_rate(struct clk *c, unsigned long rate)
-{
-	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-	struct mdss_pll_resources *io = vco->priv;
-	int rc;
-
-	rc = mdss_pll_resource_enable(io, true);
-	if (rc) {
-		DEV_ERR("pll resource can't be enabled\n");
-		return rc;
-	}
-
-	DEV_DBG("DP lane CLK rate=%ld\n", rate);
-
-	rc = dp_config_vco_rate(vco, rate);
-	if (rc)
-		DEV_ERR("%s: Failed to set clk rate\n", __func__);
-
-	mdss_pll_resource_enable(io, false);
-
-	vco->rate = rate;
-
-	return 0;
-}
-
-unsigned long dp_vco_get_rate(struct clk *c)
-{
-	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-	int rc;
-	u32 div, hsclk_div, link2xclk_div;
-	u64 vco_rate;
-	struct mdss_pll_resources *pll = vco->priv;
-
-	rc = mdss_pll_resource_enable(pll, true);
-	if (rc) {
-		pr_err("Failed to enable mdss DP pll=%d\n", pll->index);
-		return rc;
-	}
-
-	div = MDSS_PLL_REG_R(pll->pll_base, QSERDES_COM_HSCLK_SEL);
-	div &= 0x0f;
-
-	if (div == 12)
-		hsclk_div = 5; /* Default */
-	else if (div == 4)
-		hsclk_div = 3;
-	else if (div == 0)
-		hsclk_div = 2;
-	else {
-		pr_debug("unknown divider. forcing to default\n");
-		hsclk_div = 5;
-	}
-
-	div = MDSS_PLL_REG_R(pll->phy_base, DP_PHY_MODE);
-
-	if (div & 0x58)
-		pr_err("%s: DP PAR Rate not correct\n", __func__);
-
-	if ((div & 0x3) == 1)
-		link2xclk_div = 10;
-	else if ((div & 0x3) == 0)
-		link2xclk_div = 5;
-	else
-		pr_err("%s: unsupported div. Phy_mode: %d\n", __func__, div);
-
-	if (link2xclk_div == 10) {
-		vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
-	} else {
-		if (hsclk_div == 5)
-			vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000;
-		else if (hsclk_div == 3)
-			vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
-		else
-			vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000;
-	}
-
-	pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
-
-	mdss_pll_resource_enable(pll, false);
-
-	return (unsigned long)vco_rate;
-}
-
-long dp_vco_round_rate(struct clk *c, unsigned long rate)
-{
-	unsigned long rrate = rate;
-	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-
-	if (rate <= vco->min_rate)
-		rrate = vco->min_rate;
-	else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000)
-		rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
-	else
-		rrate = vco->max_rate;
-
-	pr_debug("%s: rrate=%ld\n", __func__, rrate);
-
-	return rrate;
-}
-
-enum handoff dp_vco_handoff(struct clk *c)
-{
-	enum handoff ret = HANDOFF_DISABLED_CLK;
-	struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c);
-	struct mdss_pll_resources *io = vco->priv;
-
-	if (mdss_pll_resource_enable(io, true)) {
-		DEV_ERR("pll resource can't be enabled\n");
-		return ret;
-	}
-
-	if (dp_pll_lock_status(io)) {
-		io->pll_on = true;
-		c->rate = dp_vco_get_rate(c);
-		io->handoff_resources = true;
-		ret = HANDOFF_ENABLED_CLK;
-	} else {
-		io->handoff_resources = false;
-		mdss_pll_resource_enable(io, false);
-		DEV_DBG("%s: PLL not locked\n", __func__);
-	}
-
-	DEV_DBG("done, ret=%d\n", ret);
-	return ret;
-}
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c b/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c
deleted file mode 100644
index 6a49d15..0000000
--- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/* 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.
- *
- */
-
-/*
- ***************************************************************************
- ******** Display Port PLL driver block diagram for branch clocks **********
- ***************************************************************************
-
-			+--------------------------+
-			|       DP_VCO_CLK         |
-			|			   |
-			|  +-------------------+   |
-			|  |   (DP PLL/VCO)    |   |
-			|  +---------+---------+   |
-			|	     v		   |
-			| +----------+-----------+ |
-			| | hsclk_divsel_clk_src | |
-			| +----------+-----------+ |
-			+--------------------------+
-				     |
-				     v
-	   +------------<------------|------------>-------------+
-	   |                         |                          |
-+----------v----------+	  +----------v----------+    +----------v----------+
-|   dp_link_2x_clk    |	  | vco_divided_clk_src	|    | vco_divided_clk_src |
-|     divsel_five     |	  |			|    |			   |
-v----------+----------v	  |	divsel_two	|    |	   divsel_four	   |
-	   |		  +----------+----------+    +----------+----------+
-	   |                         |                          |
-	   v			     v				v
-				     |	+---------------------+	|
-  Input to MMSSCC block		     |	|    (aux_clk_ops)    |	|
-  for link clk, crypto clk	     +-->   vco_divided_clk   <-+
-  and interface clock			|	_src_mux      |
-					+----------+----------+
-						   |
-						   v
-					 Input to MMSSCC block
-					 for DP pixel clock
-
- ******************************************************************************
- */
-
-#define pr_fmt(fmt)	"%s: " fmt, __func__
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/clk/msm-clk-provider.h>
-#include <linux/clk/msm-clk.h>
-#include <linux/clk/msm-clock-generic.h>
-#include <dt-bindings/clock/msm-clocks-8998.h>
-
-#include "mdss-pll.h"
-#include "mdss-dp-pll.h"
-#include "mdss-dp-pll-8998.h"
-
-static const struct clk_ops clk_ops_vco_divided_clk_src_c;
-static const struct clk_ops clk_ops_link_2x_clk_div_c;
-static const struct clk_ops clk_ops_gen_mux_dp;
-
-static struct clk_div_ops link2xclk_divsel_ops = {
-	.set_div = link2xclk_divsel_set_div,
-	.get_div = link2xclk_divsel_get_div,
-};
-
-static struct clk_div_ops vco_divided_clk_ops = {
-	.set_div = vco_divided_clk_set_div,
-	.get_div = vco_divided_clk_get_div,
-};
-
-static const struct clk_ops dp_8998_vco_clk_ops = {
-	.set_rate = dp_vco_set_rate,
-	.round_rate = dp_vco_round_rate,
-	.prepare = dp_vco_prepare,
-	.unprepare = dp_vco_unprepare,
-	.handoff = dp_vco_handoff,
-};
-
-static struct clk_mux_ops mdss_mux_ops = {
-	.set_mux_sel = mdss_set_mux_sel,
-	.get_mux_sel = mdss_get_mux_sel,
-};
-
-static struct dp_pll_vco_clk dp_vco_clk = {
-	.min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000,
-	.max_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000,
-	.c = {
-		.dbg_name = "dp_vco_clk",
-		.ops = &dp_8998_vco_clk_ops,
-		.flags = CLKFLAG_NO_RATE_CACHE,
-		CLK_INIT(dp_vco_clk.c),
-	},
-};
-
-static struct div_clk dp_link_2x_clk_divsel_five = {
-	.data = {
-		.div = 5,
-		.min_div = 5,
-		.max_div = 5,
-	},
-	.ops = &link2xclk_divsel_ops,
-	.c = {
-		.parent = &dp_vco_clk.c,
-		.dbg_name = "dp_link_2x_clk_divsel_five",
-		.ops = &clk_ops_link_2x_clk_div_c,
-		.flags = CLKFLAG_NO_RATE_CACHE,
-		CLK_INIT(dp_link_2x_clk_divsel_five.c),
-	},
-};
-
-static struct div_clk vco_divsel_four_clk_src = {
-	.data = {
-		.div = 4,
-		.min_div = 4,
-		.max_div = 4,
-	},
-	.ops = &vco_divided_clk_ops,
-	.c = {
-		.parent = &dp_vco_clk.c,
-		.dbg_name = "vco_divsel_four_clk_src",
-		.ops = &clk_ops_vco_divided_clk_src_c,
-		.flags = CLKFLAG_NO_RATE_CACHE,
-		CLK_INIT(vco_divsel_four_clk_src.c),
-	},
-};
-
-static struct div_clk vco_divsel_two_clk_src = {
-	.data = {
-		.div = 2,
-		.min_div = 2,
-		.max_div = 2,
-	},
-	.ops = &vco_divided_clk_ops,
-	.c = {
-		.parent = &dp_vco_clk.c,
-		.dbg_name = "vco_divsel_two_clk_src",
-		.ops = &clk_ops_vco_divided_clk_src_c,
-		.flags = CLKFLAG_NO_RATE_CACHE,
-		CLK_INIT(vco_divsel_two_clk_src.c),
-	},
-};
-
-static struct mux_clk vco_divided_clk_src_mux = {
-	.num_parents = 2,
-	.parents = (struct clk_src[]) {
-		{&vco_divsel_two_clk_src.c, 0},
-		{&vco_divsel_four_clk_src.c, 1},
-	},
-	.ops = &mdss_mux_ops,
-	.c = {
-		.parent = &vco_divsel_two_clk_src.c,
-		.dbg_name = "vco_divided_clk_src_mux",
-		.ops = &clk_ops_gen_mux_dp,
-		.flags = CLKFLAG_NO_RATE_CACHE,
-		CLK_INIT(vco_divided_clk_src_mux.c),
-	}
-};
-
-static struct clk_lookup dp_pllcc_8998[] = {
-	CLK_LIST(dp_vco_clk),
-	CLK_LIST(dp_link_2x_clk_divsel_five),
-	CLK_LIST(vco_divsel_four_clk_src),
-	CLK_LIST(vco_divsel_two_clk_src),
-	CLK_LIST(vco_divided_clk_src_mux),
-};
-
-int dp_pll_clock_register_8998(struct platform_device *pdev,
-				 struct mdss_pll_resources *pll_res)
-{
-	int rc = -ENOTSUPP;
-
-	if (!pll_res || !pll_res->pll_base || !pll_res->phy_base) {
-		DEV_ERR("%s: Invalid input parameters\n", __func__);
-		return -EINVAL;
-	}
-
-	/* Set client data for vco, mux and div clocks */
-	dp_vco_clk.priv = pll_res;
-	vco_divided_clk_src_mux.priv = pll_res;
-	vco_divsel_two_clk_src.priv = pll_res;
-	vco_divsel_four_clk_src.priv = pll_res;
-	dp_link_2x_clk_divsel_five.priv = pll_res;
-
-	clk_ops_link_2x_clk_div_c = clk_ops_div;
-	clk_ops_link_2x_clk_div_c.prepare = mdss_pll_div_prepare;
-
-	/*
-	 * Set the ops for the divider in the pixel clock tree to the
-	 * slave_div to ensure that a set rate on this divider clock will not
-	 * be propagated to it's parent. This is needed ensure that when we set
-	 * the rate for pixel clock, the vco is not reconfigured
-	 */
-	clk_ops_vco_divided_clk_src_c = clk_ops_slave_div;
-	clk_ops_vco_divided_clk_src_c.prepare = mdss_pll_div_prepare;
-	clk_ops_vco_divided_clk_src_c.handoff = vco_divided_clk_handoff;
-
-	clk_ops_gen_mux_dp = clk_ops_gen_mux;
-	clk_ops_gen_mux_dp.get_rate = parent_get_rate;
-
-	/* We can select different clock ops for future versions */
-	dp_vco_clk.c.ops = &dp_8998_vco_clk_ops;
-
-	rc = of_msm_clock_register(pdev->dev.of_node, dp_pllcc_8998,
-					ARRAY_SIZE(dp_pllcc_8998));
-	if (rc) {
-		DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc);
-		rc = -EPROBE_DEFER;
-	} else {
-		DEV_DBG("%s SUCCESS\n", __func__);
-	}
-
-	return rc;
-}
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h b/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h
deleted file mode 100644
index 11d5ddc..0000000
--- a/drivers/clk/qcom/mdss/mdss-dp-pll-8998.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/* 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 __MDSS_DP_PLL_8998_H
-#define __MDSS_DP_PLL_8998_H
-
-#define DP_PHY_REVISION_ID0			0x0000
-#define DP_PHY_REVISION_ID1			0x0004
-#define DP_PHY_REVISION_ID2			0x0008
-#define DP_PHY_REVISION_ID3			0x000C
-
-#define DP_PHY_CFG				0x0010
-#define DP_PHY_PD_CTL				0x0014
-#define DP_PHY_MODE				0x0018
-
-#define DP_PHY_AUX_CFG0				0x001C
-#define DP_PHY_AUX_CFG1				0x0020
-#define DP_PHY_AUX_CFG2				0x0024
-#define DP_PHY_AUX_CFG3				0x0028
-#define DP_PHY_AUX_CFG4				0x002C
-#define DP_PHY_AUX_CFG5				0x0030
-#define DP_PHY_AUX_CFG6				0x0034
-#define DP_PHY_AUX_CFG7				0x0038
-#define DP_PHY_AUX_CFG8				0x003C
-#define DP_PHY_AUX_CFG9				0x0040
-#define DP_PHY_AUX_INTERRUPT_MASK		0x0044
-#define DP_PHY_AUX_INTERRUPT_CLEAR		0x0048
-#define DP_PHY_AUX_BIST_CFG			0x004C
-
-#define DP_PHY_VCO_DIV				0x0064
-#define DP_PHY_TX0_TX1_LANE_CTL			0x0068
-
-#define DP_PHY_TX2_TX3_LANE_CTL			0x0084
-#define DP_PHY_STATUS				0x00BC
-
-/* Tx registers */
-#define QSERDES_TX0_OFFSET			0x0400
-#define QSERDES_TX1_OFFSET			0x0800
-
-#define TXn_BIST_MODE_LANENO			0x0000
-#define TXn_CLKBUF_ENABLE			0x0008
-#define TXn_TX_EMP_POST1_LVL			0x000C
-
-#define TXn_TX_DRV_LVL				0x001C
-
-#define TXn_RESET_TSYNC_EN			0x0024
-#define TXn_PRE_STALL_LDO_BOOST_EN		0x0028
-#define TXn_TX_BAND				0x002C
-#define TXn_SLEW_CNTL				0x0030
-#define TXn_INTERFACE_SELECT			0x0034
-
-#define TXn_RES_CODE_LANE_TX			0x003C
-#define TXn_RES_CODE_LANE_RX			0x0040
-#define TXn_RES_CODE_LANE_OFFSET_TX		0x0044
-#define TXn_RES_CODE_LANE_OFFSET_RX		0x0048
-
-#define TXn_DEBUG_BUS_SEL			0x0058
-#define TXn_TRANSCEIVER_BIAS_EN			0x005C
-#define TXn_HIGHZ_DRVR_EN			0x0060
-#define TXn_TX_POL_INV				0x0064
-#define TXn_PARRATE_REC_DETECT_IDLE_EN		0x0068
-
-#define TXn_LANE_MODE_1				0x008C
-
-#define TXn_TRAN_DRVR_EMP_EN			0x00C0
-#define TXn_TX_INTERFACE_MODE			0x00C4
-
-#define TXn_VMODE_CTRL1				0x00F0
-
-
-/* PLL register offset */
-#define QSERDES_COM_ATB_SEL1			0x0000
-#define QSERDES_COM_ATB_SEL2			0x0004
-#define QSERDES_COM_FREQ_UPDATE			0x0008
-#define QSERDES_COM_BG_TIMER			0x000C
-#define QSERDES_COM_SSC_EN_CENTER		0x0010
-#define QSERDES_COM_SSC_ADJ_PER1		0x0014
-#define QSERDES_COM_SSC_ADJ_PER2		0x0018
-#define QSERDES_COM_SSC_PER1			0x001C
-#define QSERDES_COM_SSC_PER2			0x0020
-#define QSERDES_COM_SSC_STEP_SIZE1		0x0024
-#define QSERDES_COM_SSC_STEP_SIZE2		0x0028
-#define QSERDES_COM_POST_DIV			0x002C
-#define QSERDES_COM_POST_DIV_MUX		0x0030
-#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN		0x0034
-#define QSERDES_COM_CLK_ENABLE1			0x0038
-#define QSERDES_COM_SYS_CLK_CTRL		0x003C
-#define QSERDES_COM_SYSCLK_BUF_ENABLE		0x0040
-#define QSERDES_COM_PLL_EN			0x0044
-#define QSERDES_COM_PLL_IVCO			0x0048
-#define QSERDES_COM_CMN_IETRIM			0x004C
-#define QSERDES_COM_CMN_IPTRIM			0x0050
-
-#define QSERDES_COM_CP_CTRL_MODE0		0x0060
-#define QSERDES_COM_CP_CTRL_MODE1		0x0064
-#define QSERDES_COM_PLL_RCTRL_MODE0		0x0068
-#define QSERDES_COM_PLL_RCTRL_MODE1		0x006C
-#define QSERDES_COM_PLL_CCTRL_MODE0		0x0070
-#define QSERDES_COM_PLL_CCTRL_MODE1		0x0074
-#define QSERDES_COM_PLL_CNTRL			0x0078
-#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM		0x007C
-#define QSERDES_COM_SYSCLK_EN_SEL		0x0080
-#define QSERDES_COM_CML_SYSCLK_SEL		0x0084
-#define QSERDES_COM_RESETSM_CNTRL		0x0088
-#define QSERDES_COM_RESETSM_CNTRL2		0x008C
-#define QSERDES_COM_LOCK_CMP_EN			0x0090
-#define QSERDES_COM_LOCK_CMP_CFG		0x0094
-#define QSERDES_COM_LOCK_CMP1_MODE0		0x0098
-#define QSERDES_COM_LOCK_CMP2_MODE0		0x009C
-#define QSERDES_COM_LOCK_CMP3_MODE0		0x00A0
-
-#define QSERDES_COM_DEC_START_MODE0		0x00B0
-#define QSERDES_COM_DEC_START_MODE1		0x00B4
-#define QSERDES_COM_DIV_FRAC_START1_MODE0	0x00B8
-#define QSERDES_COM_DIV_FRAC_START2_MODE0	0x00BC
-#define QSERDES_COM_DIV_FRAC_START3_MODE0	0x00C0
-#define QSERDES_COM_DIV_FRAC_START1_MODE1	0x00C4
-#define QSERDES_COM_DIV_FRAC_START2_MODE1	0x00C8
-#define QSERDES_COM_DIV_FRAC_START3_MODE1	0x00CC
-#define QSERDES_COM_INTEGLOOP_INITVAL		0x00D0
-#define QSERDES_COM_INTEGLOOP_EN		0x00D4
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0	0x00D8
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0	0x00DC
-#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1	0x00E0
-#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1	0x00E4
-#define QSERDES_COM_VCOCAL_DEADMAN_CTRL		0x00E8
-#define QSERDES_COM_VCO_TUNE_CTRL		0x00EC
-#define QSERDES_COM_VCO_TUNE_MAP		0x00F0
-
-#define QSERDES_COM_CMN_STATUS			0x0124
-#define QSERDES_COM_RESET_SM_STATUS		0x0128
-
-#define QSERDES_COM_CLK_SEL			0x0138
-#define QSERDES_COM_HSCLK_SEL			0x013C
-
-#define QSERDES_COM_CORECLK_DIV_MODE0		0x0148
-
-#define QSERDES_COM_SW_RESET			0x0150
-#define QSERDES_COM_CORE_CLK_EN			0x0154
-#define QSERDES_COM_C_READY_STATUS		0x0158
-#define QSERDES_COM_CMN_CONFIG			0x015C
-
-#define QSERDES_COM_SVS_MODE_CLK_SEL		0x0164
-
-#define DP_PLL_POLL_SLEEP_US			500
-#define DP_PLL_POLL_TIMEOUT_US			10000
-
-#define DP_VCO_RATE_8100MHZDIV1000		8100000UL
-#define DP_VCO_RATE_10800MHZDIV1000		10800000UL
-
-#define DP_VCO_HSCLK_RATE_1620MHZDIV1000	1620000UL
-#define DP_VCO_HSCLK_RATE_2700MHZDIV1000	2700000UL
-#define DP_VCO_HSCLK_RATE_5400MHZDIV1000	5400000UL
-
-int dp_vco_set_rate(struct clk *c, unsigned long rate);
-unsigned long dp_vco_get_rate(struct clk *c);
-long dp_vco_round_rate(struct clk *c, unsigned long rate);
-enum handoff dp_vco_handoff(struct clk *c);
-enum handoff vco_divided_clk_handoff(struct clk *c);
-int dp_vco_prepare(struct clk *c);
-void dp_vco_unprepare(struct clk *c);
-int hsclk_divsel_set_div(struct div_clk *clk, int div);
-int hsclk_divsel_get_div(struct div_clk *clk);
-int link2xclk_divsel_set_div(struct div_clk *clk, int div);
-int link2xclk_divsel_get_div(struct div_clk *clk);
-int vco_divided_clk_set_div(struct div_clk *clk, int div);
-int vco_divided_clk_get_div(struct div_clk *clk);
-
-#endif /* __MDSS_DP_PLL_8998_H */
diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll.h b/drivers/clk/qcom/mdss/mdss-dp-pll.h
index 2805ff9..2b1d70e 100644
--- a/drivers/clk/qcom/mdss/mdss-dp-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-dp-pll.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* 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
@@ -15,21 +15,19 @@
 #define __MDSS_DP_PLL_H
 
 struct dp_pll_vco_clk {
+	struct clk_hw hw;
 	unsigned long	rate;		/* current vco rate */
 	u64		min_rate;	/* min vco rate */
 	u64		max_rate;	/* max vco rate */
 	void		*priv;
-
-	struct clk	c;
 };
 
-static inline struct dp_pll_vco_clk *mdss_dp_to_vco_clk(struct clk *clk)
+static inline struct dp_pll_vco_clk *to_dp_vco_hw(struct clk_hw *hw)
 {
-	return container_of(clk, struct dp_pll_vco_clk, c);
+	return container_of(hw, struct dp_pll_vco_clk, hw);
 }
 
-int dp_pll_clock_register_8998(struct platform_device *pdev,
+int dp_pll_clock_register_10nm(struct platform_device *pdev,
 				struct mdss_pll_resources *pll_res);
 
-
 #endif /* __MDSS_DP_PLL_H */
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 7f82fda..e292ef8 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -21,6 +21,7 @@
 #include <linux/iopoll.h>
 #include "mdss-pll.h"
 #include "mdss-dsi-pll.h"
+#include "mdss-dp-pll.h"
 
 int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable)
 {
@@ -126,6 +127,8 @@
 
 	if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_10nm"))
 		pll_res->pll_interface_type = MDSS_DSI_PLL_10NM;
+	if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_10nm"))
+		pll_res->pll_interface_type = MDSS_DP_PLL_10NM;
 	else
 		goto err;
 
@@ -151,6 +154,9 @@
 	case MDSS_DSI_PLL_10NM:
 		rc = dsi_pll_clock_register_10nm(pdev, pll_res);
 		break;
+	case MDSS_DP_PLL_10NM:
+		rc = dp_pll_clock_register_10nm(pdev, pll_res);
+		break;
 	case MDSS_UNKNOWN_PLL:
 	default:
 		rc = -EINVAL;
@@ -171,6 +177,7 @@
 	const char *label;
 	struct resource *pll_base_reg;
 	struct resource *phy_base_reg;
+	struct resource *tx0_base_reg, *tx1_base_reg;
 	struct resource *dynamic_pll_base_reg;
 	struct resource *gdsc_base_reg;
 	struct mdss_pll_resources *pll_res;
@@ -272,6 +279,30 @@
 		}
 	}
 
+	tx0_base_reg = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "ln_tx0_base");
+	if (tx0_base_reg) {
+		pll_res->ln_tx0_base = ioremap(tx0_base_reg->start,
+				resource_size(tx0_base_reg));
+		if (!pll_res->ln_tx0_base) {
+			pr_err("Unable to remap Lane TX0 base resources\n");
+			rc = -ENOMEM;
+			goto tx0_io_error;
+		}
+	}
+
+	tx1_base_reg = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "ln_tx1_base");
+	if (tx1_base_reg) {
+		pll_res->ln_tx1_base = ioremap(tx1_base_reg->start,
+				resource_size(tx1_base_reg));
+		if (!pll_res->ln_tx1_base) {
+			pr_err("Unable to remap Lane TX1 base resources\n");
+			rc = -ENOMEM;
+			goto tx1_io_error;
+		}
+	}
+
 	gdsc_base_reg = platform_get_resource_byname(pdev,
 					IORESOURCE_MEM, "gdsc_base");
 	if (!gdsc_base_reg) {
@@ -309,6 +340,12 @@
 	if (pll_res->gdsc_base)
 		iounmap(pll_res->gdsc_base);
 gdsc_io_error:
+	if (pll_res->ln_tx1_base)
+		iounmap(pll_res->ln_tx1_base);
+tx1_io_error:
+	if (pll_res->ln_tx0_base)
+		iounmap(pll_res->ln_tx0_base);
+tx0_io_error:
 	if (pll_res->dyn_pll_base)
 		iounmap(pll_res->dyn_pll_base);
 dyn_pll_io_error:
@@ -347,6 +384,7 @@
 
 static const struct of_device_id mdss_pll_dt_match[] = {
 	{.compatible = "qcom,mdss_dsi_pll_10nm"},
+	{.compatible = "qcom,mdss_dp_pll_10nm"},
 	{}
 };
 
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index ee91e11..033462d 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -37,6 +37,7 @@
 
 enum {
 	MDSS_DSI_PLL_10NM,
+	MDSS_DP_PLL_10NM,
 	MDSS_UNKNOWN_PLL,
 };
 
@@ -81,6 +82,8 @@
 	 */
 	void __iomem	*pll_base;
 	void __iomem	*phy_base;
+	void __iomem	*ln_tx0_base;
+	void __iomem	*ln_tx1_base;
 	void __iomem	*gdsc_base;
 	void __iomem	*dyn_pll_base;
 
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 8af73ac..d9ebe113 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -4877,15 +4877,12 @@
 	if (handle == NULL)
 		return -ENODEV;
 
-	qce_enable_clk(pce_dev);
-
 	sps_pipe_info = pce_dev->ce_bam_info.consumer.pipe;
 	sps_disconnect(sps_pipe_info);
 
 	sps_pipe_info = pce_dev->ce_bam_info.producer.pipe;
 	sps_disconnect(sps_pipe_info);
 
-	qce_disable_clk(pce_dev);
 	return 0;
 }
 
@@ -4899,8 +4896,6 @@
 	if (handle == NULL)
 		return -ENODEV;
 
-	qce_enable_clk(pce_dev);
-
 	sps_pipe_info = pce_dev->ce_bam_info.consumer.pipe;
 	sps_connect_info = &pce_dev->ce_bam_info.consumer.connect;
 	memset(sps_connect_info->desc.base, 0x00, sps_connect_info->desc.size);
@@ -4923,7 +4918,6 @@
 	if (rc)
 		pr_err("Producer callback registration failed rc = %d\n", rc);
 
-	qce_disable_clk(pce_dev);
 	return rc;
 }
 
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index ff64631..56fbb94 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -5371,8 +5371,11 @@
 	spin_unlock_irqrestore(&cp->lock, flags);
 	if (ret)
 		return ret;
-	if (qce_pm_table.suspend)
+	if (qce_pm_table.suspend) {
+		qcrypto_ce_set_bus(pengine, true);
 		qce_pm_table.suspend(pengine->qce);
+		qcrypto_ce_set_bus(pengine, false);
+	}
 	return 0;
 }
 
@@ -5393,9 +5396,11 @@
 	spin_lock_irqsave(&cp->lock, flags);
 	if (pengine->bw_state == BUS_SUSPENDED) {
 		spin_unlock_irqrestore(&cp->lock, flags);
-		if (qce_pm_table.resume)
+		if (qce_pm_table.resume) {
+			qcrypto_ce_set_bus(pengine, true);
 			qce_pm_table.resume(pengine->qce);
-
+			qcrypto_ce_set_bus(pengine, false);
+		}
 		spin_lock_irqsave(&cp->lock, flags);
 		pengine->bw_state = BUS_NO_BANDWIDTH;
 		pengine->active_seq++;
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index a79a9c9..70581e2 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -20,14 +20,8 @@
 
 #define DP_AUX_ENUM_STR(x)		#x
 
-struct aux_buf {
-	u8 *start;      /* buffer start addr */
-	u8 *end;	/* buffer end addr */
-	u8 *data;       /* data pou32er */
-	u32 size;       /* size of buffer */
-	u32 len;	/* dara length */
-	u8 trans_num;   /* transaction number */
-	enum aux_tx_mode tx_mode;
+enum {
+	DP_AUX_DATA_INDEX_WRITE = BIT(31),
 };
 
 struct dp_aux_private {
@@ -38,15 +32,12 @@
 	struct mutex mutex;
 	struct completion comp;
 
-	struct aux_cmd *cmds;
-	struct aux_buf txp;
-	struct aux_buf rxp;
-
 	u32 aux_error_num;
 	bool cmd_busy;
+	bool native;
+	bool read;
 
-	u8 txbuf[256];
-	u8 rxbuf[256];
+	struct drm_dp_aux drm_aux;
 };
 
 static char *dp_aux_get_error(u32 aux_error)
@@ -69,159 +60,104 @@
 	}
 }
 
-static void dp_aux_buf_init(struct aux_buf *buf, u8 *data, u32 size)
+static u32 dp_aux_write(struct dp_aux_private *aux,
+		struct drm_dp_aux_msg *msg)
 {
-	buf->start     = data;
-	buf->size      = size;
-	buf->data      = buf->start;
-	buf->end       = buf->start + buf->size;
-	buf->len       = 0;
-	buf->trans_num = 0;
-	buf->tx_mode   = AUX_NATIVE;
-}
+	u32 data[4], reg, len;
+	u8 *msgdata = msg->buffer;
+	int const aux_cmd_fifo_len = 128;
+	int i = 0;
 
-static void dp_aux_buf_set(struct dp_aux_private *aux)
-{
-	init_completion(&aux->comp);
-	aux->cmd_busy = false;
-	mutex_init(&aux->mutex);
-
-	dp_aux_buf_init(&aux->txp, aux->txbuf, sizeof(aux->txbuf));
-	dp_aux_buf_init(&aux->rxp, aux->rxbuf, sizeof(aux->rxbuf));
-}
-
-static void dp_aux_buf_reset(struct aux_buf *buf)
-{
-	buf->data      = buf->start;
-	buf->len       = 0;
-	buf->trans_num = 0;
-	buf->tx_mode   = AUX_NATIVE;
-
-	memset(buf->start, 0x0, 256);
-}
-
-static void dp_aux_buf_push(struct aux_buf *buf, u32 len)
-{
-	buf->data += len;
-	buf->len  += len;
-}
-
-static u32 dp_aux_buf_trailing(struct aux_buf *buf)
-{
-	return (u32)(buf->end - buf->data);
-}
-
-static u32 dp_aux_add_cmd(struct aux_buf *buf, struct aux_cmd *cmd)
-{
-	u8 data;
-	u8 *bp, *cp;
-	u32 i, len;
-
-	if (cmd->ex_mode == AUX_READ)
+	if (aux->read)
 		len = 4;
 	else
-		len = cmd->len + 4;
-
-	if (dp_aux_buf_trailing(buf) < len) {
-		pr_err("buf trailing error\n");
-		return 0;
-	}
+		len = msg->size + 4;
 
 	/*
 	 * cmd fifo only has depth of 144 bytes
 	 * limit buf length to 128 bytes here
 	 */
-	if ((buf->len + len) > 128) {
+	if (len > aux_cmd_fifo_len) {
 		pr_err("buf len error\n");
 		return 0;
 	}
 
-	bp = buf->data;
-	data = cmd->addr >> 16;
-	data &= 0x0f;  /* 4 addr bits */
+	/* Pack cmd and write to HW */
+	data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */
+	if (aux->read)
+		data[0] |=  BIT(4); /* R/W */
 
-	if (cmd->ex_mode == AUX_READ)
-		data |=  BIT(4);
+	data[1] = (msg->address >> 8) & 0xff;	/* addr[15:8] */
+	data[2] = msg->address & 0xff;		/* addr[7:0] */
+	data[3] = (msg->size - 1) & 0xff;	/* len[7:0] */
 
-	*bp++ = data;
-	*bp++ = cmd->addr >> 8;
-	*bp++ = cmd->addr;
-	*bp++ = cmd->len - 1;
-
-	if (cmd->ex_mode == AUX_WRITE) {
-		cp = cmd->buf;
-
-		for (i = 0; i < cmd->len; i++)
-			*bp++ = *cp++;
-	}
-
-	dp_aux_buf_push(buf, len);
-
-	buf->tx_mode = cmd->tx_mode;
-
-	buf->trans_num++;
-
-	return cmd->len - 1;
-}
-
-static u32 dp_aux_cmd_fifo_tx(struct dp_aux_private *aux)
-{
-	u8 *dp;
-	u32 data, len, cnt;
-	struct aux_buf *tp = &aux->txp;
-
-	len = tp->len;
-	if (len == 0) {
-		pr_err("invalid len\n");
-		return 0;
-	}
-
-	cnt = 0;
-	dp = tp->start;
-
-	while (cnt < len) {
-		data = *dp;
-		data <<= 8;
-		data &= 0x00ff00;
-		if (cnt == 0)
-			data |= BIT(31);
-
-		aux->catalog->data = data;
+	for (i = 0; i < len; i++) {
+		reg = (i < 4) ? data[i] : msgdata[i - 4];
+		reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */
+		if (i == 0)
+			reg |= DP_AUX_DATA_INDEX_WRITE;
+		aux->catalog->data = reg;
 		aux->catalog->write_data(aux->catalog);
-
-		cnt++;
-		dp++;
 	}
 
-	data = (tp->trans_num - 1);
-	if (tp->tx_mode == AUX_I2C) {
-		data |= BIT(8); /* I2C */
-		data |= BIT(10); /* NO SEND ADDR */
-		data |= BIT(11); /* NO SEND STOP */
-	}
+	reg = 0; /* Transaction number == 1 */
+	if (!aux->native) /* i2c */
+		reg |= (BIT(8) | BIT(10) | BIT(11));
 
-	data |= BIT(9); /* GO */
-	aux->catalog->data = data;
+	reg |= BIT(9);
+	aux->catalog->data = reg;
 	aux->catalog->write_trans(aux->catalog);
 
-	return tp->len;
+	return len;
 }
 
-static u32 dp_cmd_fifo_rx(struct dp_aux_private *aux, u32 len)
+static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
+		struct drm_dp_aux_msg *msg)
+{
+	u32 ret = 0, len = 0, timeout;
+	int const aux_timeout_ms = HZ/4;
+
+	reinit_completion(&aux->comp);
+
+	len = dp_aux_write(aux, msg);
+	if (len == 0) {
+		pr_err("DP AUX write failed\n");
+		return -EINVAL;
+	}
+
+	timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
+	if (!timeout) {
+		pr_err("aux write timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	pr_debug("aux status %s\n",
+		dp_aux_get_error(aux->aux_error_num));
+
+	if (aux->aux_error_num == DP_AUX_ERR_NONE)
+		ret = len;
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux,
+		struct drm_dp_aux_msg *msg)
 {
 	u32 data;
 	u8 *dp;
 	u32 i;
-	struct aux_buf *rp = &aux->rxp;
+	u32 len = msg->size;
 
 	data = 0;
-	data |= BIT(31); /* INDEX_WRITE */
+	data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
 	data |= BIT(0);  /* read */
 
 	aux->catalog->data = data;
 	aux->catalog->write_data(aux->catalog);
 
-	dp = rp->data;
+	dp = msg->buffer;
 
 	/* discard first byte */
 	data = aux->catalog->read_data(aux->catalog);
@@ -230,9 +166,6 @@
 		data = aux->catalog->read_data(aux->catalog);
 		*dp++ = (u8)((data >> 8) & 0xff);
 	}
-
-	rp->len = len;
-	return len;
 }
 
 static void dp_aux_native_handler(struct dp_aux_private *aux)
@@ -292,219 +225,76 @@
 	if (!aux->cmd_busy)
 		return;
 
-	if (aux->cmds->tx_mode == AUX_NATIVE)
+	if (aux->native)
 		dp_aux_native_handler(aux);
 	else
 		dp_aux_i2c_handler(aux);
 }
 
-
-
-static int dp_aux_write(struct dp_aux_private *aux)
+/*
+ * This function does the real job to process an AUX transaction.
+ * It will call aux_reset() function to reset the AUX channel,
+ * if the waiting is timeout.
+ */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
 {
-	struct aux_cmd *cm;
-	struct aux_buf *tp;
-	u32 len, ret, timeout;
+	ssize_t ret;
+	int const aux_cmd_native_max = 16;
+	int const aux_cmd_i2c_max = 128;
+	struct dp_aux_private *aux = container_of(drm_aux,
+		struct dp_aux_private, drm_aux);
 
 	mutex_lock(&aux->mutex);
 
-	tp = &aux->txp;
-	dp_aux_buf_reset(tp);
-
-	cm = aux->cmds;
-	while (cm) {
-		ret = dp_aux_add_cmd(tp, cm);
-		if (ret <= 0)
-			break;
-
-		if (!cm->next)
-			break;
-		cm++;
-	}
-
-	reinit_completion(&aux->comp);
+	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
 	aux->cmd_busy = true;
 
-	len = dp_aux_cmd_fifo_tx(aux);
-
-	timeout = wait_for_completion_timeout(&aux->comp, HZ/4);
-	if (!timeout)
-		pr_err("aux write timeout\n");
-
-	pr_debug("aux status %s\n",
-		dp_aux_get_error(aux->aux_error_num));
-
-	if (aux->aux_error_num == DP_AUX_ERR_NONE)
-		ret = len;
-	else
-		ret = aux->aux_error_num;
-
-	aux->cmd_busy = false;
-	mutex_unlock(&aux->mutex);
-	return  ret;
-}
-
-static int dp_aux_read(struct dp_aux_private *aux)
-{
-	struct aux_cmd *cm;
-	struct aux_buf *tp, *rp;
-	u32 len, ret, timeout;
-
-	mutex_lock(&aux->mutex);
-
-	tp = &aux->txp;
-	rp = &aux->rxp;
-
-	dp_aux_buf_reset(tp);
-	dp_aux_buf_reset(rp);
-
-	cm = aux->cmds;
-	len = 0;
-
-	while (cm) {
-		ret = dp_aux_add_cmd(tp, cm);
-		len += cm->len;
-
-		if (ret <= 0)
-			break;
-
-		if (!cm->next)
-			break;
-		cm++;
+	/* Ignore address only message */
+	if ((msg->size == 0) || (msg->buffer == NULL)) {
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+		ret = msg->size;
+		goto unlock_exit;
 	}
 
-	reinit_completion(&aux->comp);
-	aux->cmd_busy = true;
+	/* msg sanity check */
+	if ((aux->native && (msg->size > aux_cmd_native_max)) ||
+		(msg->size > aux_cmd_i2c_max)) {
+		pr_err("%s: invalid msg: size(%zu), request(%x)\n",
+			__func__, msg->size, msg->request);
+		ret = -EINVAL;
+		goto unlock_exit;
+	}
 
-	dp_aux_cmd_fifo_tx(aux);
+	ret = dp_aux_cmd_fifo_tx(aux, msg);
+	if (ret < 0) {
+		aux->catalog->reset(aux->catalog); /* reset aux */
+		goto unlock_exit;
+	}
 
-	timeout = wait_for_completion_timeout(&aux->comp, HZ/4);
-	if (!timeout)
-		pr_err("aux read timeout\n");
+	if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+		if (aux->read)
+			dp_aux_cmd_fifo_rx(aux, msg);
 
-	pr_debug("aux status %s\n",
-		dp_aux_get_error(aux->aux_error_num));
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+	} else {
+		/* Reply defer to retry */
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+	}
 
-	if (aux->aux_error_num == DP_AUX_ERR_NONE)
-		ret = dp_cmd_fifo_rx(aux, len);
-	else
-		ret = aux->aux_error_num;
+	/* Return requested size for success or retry */
+	ret = msg->size;
 
-	aux->cmds->buf = rp->data;
+unlock_exit:
 	aux->cmd_busy = false;
-
 	mutex_unlock(&aux->mutex);
-
 	return ret;
 }
 
-static int dp_aux_write_ex(struct dp_aux *dp_aux, u32 addr, u32 len,
-				enum aux_tx_mode mode, u8 *buf)
-{
-	struct aux_cmd cmd = {0};
-	struct dp_aux_private *aux;
-
-	if (!dp_aux || !len) {
-		pr_err("invalid input\n");
-		return -EINVAL;
-	}
-
-	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
-	cmd.ex_mode = AUX_WRITE;
-	cmd.tx_mode = mode;
-	cmd.addr    = addr;
-	cmd.len     = len;
-	cmd.buf     = buf;
-
-	aux->cmds = &cmd;
-
-	return dp_aux_write(aux);
-}
-
-static int dp_aux_read_ex(struct dp_aux *dp_aux, u32 addr, u32 len,
-				enum aux_tx_mode mode, u8 **buf)
-{
-	int rc = 0;
-	struct aux_cmd cmd = {0};
-	struct dp_aux_private *aux;
-
-	if (!dp_aux || !len) {
-		pr_err("invalid input\n");
-		rc = -EINVAL;
-		goto end;
-	}
-
-	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
-	cmd.ex_mode = AUX_READ;
-	cmd.tx_mode = mode;
-	cmd.addr    = addr;
-	cmd.len     = len;
-
-	aux->cmds = &cmd;
-
-	rc = dp_aux_read(aux);
-	if (rc <= 0) {
-		rc = -EINVAL;
-		goto end;
-	}
-
-	*buf = cmd.buf;
-end:
-	return rc;
-}
-
-static int dp_aux_process(struct dp_aux *dp_aux, struct aux_cmd *cmds)
-{
-	struct dp_aux_private *aux;
-
-	if (!dp_aux || !cmds) {
-		pr_err("invalid input\n");
-		return -EINVAL;
-	}
-
-	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
-	aux->cmds = cmds;
-
-	if (cmds->ex_mode == AUX_READ)
-		return dp_aux_read(aux);
-	else
-		return dp_aux_write(aux);
-}
-
-static bool dp_aux_ready(struct dp_aux *dp_aux)
-{
-	u8 data = 0;
-	int count, ret;
-	struct dp_aux_private *aux;
-
-	if (!dp_aux) {
-		pr_err("invalid input\n");
-		goto error;
-	}
-
-	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
-
-	for (count = 5; count; count--) {
-		ret = dp_aux_write_ex(dp_aux, 0x50, 1, AUX_I2C, &data);
-		if (ret >= 0)
-			break;
-
-		msleep(100);
-	}
-
-	if (count <= 0) {
-		pr_err("aux chan NOT ready\n");
-		goto error;
-	}
-
-	return true;
-error:
-	return false;
-}
-
 static void dp_aux_init(struct dp_aux *dp_aux, u32 *aux_cfg)
 {
 	struct dp_aux_private *aux;
@@ -535,6 +325,45 @@
 	aux->catalog->enable(aux->catalog, false);
 }
 
+static int dp_aux_register(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+	int ret = 0;
+
+	if (!dp_aux) {
+		pr_err("invalid input\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	aux->drm_aux.name = "sde_dp_aux";
+	aux->drm_aux.dev = aux->dev;
+	aux->drm_aux.transfer = dp_aux_transfer;
+	ret = drm_dp_aux_register(&aux->drm_aux);
+	if (ret) {
+		pr_err("%s: failed to register drm aux: %d\n", __func__, ret);
+		goto exit;
+	}
+	dp_aux->drm_aux = &aux->drm_aux;
+exit:
+	return ret;
+}
+
+static void dp_aux_deregister(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+	drm_dp_aux_unregister(&aux->drm_aux);
+}
+
 struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog)
 {
 	int rc = 0;
@@ -553,21 +382,19 @@
 		goto error;
 	}
 
+	init_completion(&aux->comp);
+	aux->cmd_busy = false;
+	mutex_init(&aux->mutex);
+
 	aux->dev = dev;
-
-	dp_aux_buf_set(aux);
-
 	aux->catalog = catalog;
-
 	dp_aux = &aux->dp_aux;
 
-	dp_aux->process = dp_aux_process;
-	dp_aux->read    = dp_aux_read_ex;
-	dp_aux->write   = dp_aux_write_ex;
-	dp_aux->ready   = dp_aux_ready;
 	dp_aux->isr     = dp_aux_isr;
 	dp_aux->init    = dp_aux_init;
 	dp_aux->deinit  = dp_aux_deinit;
+	dp_aux->drm_aux_register = dp_aux_register;
+	dp_aux->drm_aux_deregister = dp_aux_deregister;
 
 	return dp_aux;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index 0603c15..f08c12b 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -16,6 +16,7 @@
 #define _DP_AUX_H_
 
 #include "dp_catalog.h"
+#include "drm_dp_helper.h"
 
 enum dp_aux_error {
 	DP_AUX_ERR_NONE	= 0,
@@ -26,32 +27,10 @@
 	DP_AUX_ERR_NACK_DEFER	= -5,
 };
 
-enum aux_tx_mode {
-	AUX_NATIVE,
-	AUX_I2C,
-};
-
-enum aux_exe_mode {
-	AUX_WRITE,
-	AUX_READ,
-};
-
-struct aux_cmd {
-	enum aux_exe_mode ex_mode;
-	enum aux_tx_mode tx_mode;
-	u32 addr;
-	u32 len;
-	u8 *buf;
-	bool next;
-};
-
 struct dp_aux {
-	int (*process)(struct dp_aux *aux, struct aux_cmd *cmd);
-	int (*write)(struct dp_aux *aux, u32 addr, u32 len,
-			enum aux_tx_mode mode, u8 *buf);
-	int (*read)(struct dp_aux *aux, u32 addr, u32 len,
-			enum aux_tx_mode mode, u8 **buf);
-	bool (*ready)(struct dp_aux *aux);
+	struct drm_dp_aux *drm_aux;
+	int (*drm_aux_register)(struct dp_aux *aux);
+	void (*drm_aux_deregister)(struct dp_aux *aux);
 	void (*isr)(struct dp_aux *aux);
 	void (*init)(struct dp_aux *aux, u32 *aux_cfg);
 	void (*deinit)(struct dp_aux *aux);
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index ca55d16..9361b52 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -177,8 +177,6 @@
 
 #define QSERDES_COM_BIAS_EN_CLKBUFLR_EN		(0x004)
 
-#define EDID_START_ADDRESS			0x50
-
 /* DP MMSS_CC registers */
 #define MMSS_DP_LINK_CMD_RCGR			(0x0138)
 #define MMSS_DP_LINK_CFG_RCGR			(0x013C)
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 56f6052..888c511 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -20,14 +20,9 @@
 
 #include "dp_ctrl.h"
 
-#define DP_LINK_RATE_MULTIPLIER	27000000
 #define DP_KHZ_TO_HZ 1000
 #define DP_CRYPTO_CLK_RATE_KHZ 180000
 
-/* sink power state  */
-#define SINK_POWER_ON		1
-#define SINK_POWER_OFF		2
-
 #define DP_CTRL_INTR_READY_FOR_VIDEO     BIT(0)
 #define DP_CTRL_INTR_IDLE_PATTERN_SENT  BIT(3)
 
@@ -103,14 +98,6 @@
 	complete(&ctrl->video_comp);
 }
 
-static void dp_ctrl_set_sink_power_state(struct dp_ctrl_private *ctrl,
-		u8 power_state)
-{
-	const int len = 1;
-
-	ctrl->aux->write(ctrl->aux, 0x600, len, AUX_NATIVE, &power_state);
-}
-
 static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state)
 {
 	ctrl->catalog->state_ctrl(ctrl->catalog, state);
@@ -128,7 +115,7 @@
 
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
-	dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_OFF);
+	drm_dp_link_power_down(ctrl->aux->drm_aux, &ctrl->panel->dp_link);
 
 	reinit_completion(&ctrl->idle_comp);
 	dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE);
@@ -143,12 +130,13 @@
 static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
 {
 	u32 config = 0, tbd;
+	u8 *dpcd = ctrl->panel->dpcd;
 
 	config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK  */
 	config |= (0 << 11); /* RGB */
 
 	/* Scrambler reset enable */
-	if (ctrl->panel->dpcd.scrambler_reset)
+	if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
 		config |= (1 << 10);
 
 	tbd = ctrl->link->get_test_bits_depth(ctrl->link,
@@ -158,7 +146,7 @@
 	/* Num of Lanes */
 	config |= ((ctrl->link->lane_count - 1) << 4);
 
-	if (ctrl->panel->dpcd.enhanced_frame)
+	if (drm_dp_enhanced_frame_cap(dpcd))
 		config |= 0x40;
 
 	config |= 0x04; /* progressive video */
@@ -327,7 +315,7 @@
 	even_distribution = 0;
 	min_hblank = 0;
 
-	lclk = link_rate * DP_LINK_RATE_MULTIPLIER;
+	lclk = drm_dp_bw_code_to_link_rate(link_rate) * DP_KHZ_TO_HZ;
 
 	pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
 						pclk, lwidth, h_blank);
@@ -763,7 +751,7 @@
 		buf[i] = voltage_level | pre_emphasis_level | max_level_reached;
 
 	pr_debug("p|v=0x%x\n", voltage_level | pre_emphasis_level);
-	return ctrl->aux->write(ctrl->aux, 0x103, 4, AUX_NATIVE, buf);
+	return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
 }
 
 static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
@@ -778,25 +766,6 @@
 	dp_ctrl_update_sink_vx_px(ctrl, link->v_level, link->p_level);
 }
 
-static void dp_ctrl_cap_lane_rate_set(struct dp_ctrl_private *ctrl)
-{
-	u8 buf[4];
-	struct dp_panel_dpcd *cap;
-
-	cap = &ctrl->panel->dpcd;
-
-	pr_debug("bw=%x lane=%d\n", ctrl->link->link_rate,
-		ctrl->link->lane_count);
-
-	buf[0] = ctrl->link->link_rate;
-	buf[1] = ctrl->link->lane_count;
-
-	if (cap->enhanced_frame)
-		buf[1] |= 0x80;
-
-	ctrl->aux->write(ctrl->aux, 0x100, 2, AUX_NATIVE, buf);
-}
-
 static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
 		u8 pattern)
 {
@@ -805,33 +774,39 @@
 	pr_debug("pattern=%x\n", pattern);
 
 	buf[0] = pattern;
-	ctrl->aux->write(ctrl->aux, 0x102, 1, AUX_NATIVE, buf);
+	drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1);
 }
 
 static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
 {
-	int tries, old_v_level;
-	int ret = 0;
-	int usleep_time;
+	int tries, old_v_level, ret = 0, len = 0;
+	u8 link_status[DP_LINK_STATUS_SIZE];
 	int const maximum_retries = 5;
 
 	dp_ctrl_state_ctrl(ctrl, 0);
-
 	/* Make sure to clear the current pattern before starting a new one */
 	wmb();
 
 	ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
-	dp_ctrl_cap_lane_rate_set(ctrl);
-	dp_ctrl_train_pattern_set(ctrl, 0x21); /* train_1 */
+	dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
+		DP_RECOVERED_CLOCK_OUT_EN); /* train_1 */
 	dp_ctrl_update_vx_px(ctrl);
 
 	tries = 0;
 	old_v_level = ctrl->link->v_level;
 	while (1) {
-		usleep_time = ctrl->panel->dpcd.training_read_interval;
-		usleep_range(usleep_time, usleep_time * 2);
+		drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
 
-		if (ctrl->link->clock_recovery(ctrl->link)) {
+		len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
+			link_status);
+		if (len < DP_LINK_STATUS_SIZE) {
+			pr_err("[%s]: DP link status read failed\n", __func__);
+			ret = -1;
+			break;
+		}
+
+		if (drm_dp_clock_recovery_ok(link_status,
+			ctrl->link->lane_count)) {
 			ret = 0;
 			break;
 		}
@@ -852,8 +827,7 @@
 			old_v_level = ctrl->link->v_level;
 		}
 
-		ctrl->link->adjust_levels(ctrl->link);
-
+		ctrl->link->adjust_levels(ctrl->link, link_status);
 		dp_ctrl_update_vx_px(ctrl);
 	}
 
@@ -869,15 +843,15 @@
 
 	switch (ctrl->link->link_rate) {
 	case DP_LINK_RATE_810:
-		ctrl->link->link_rate = DP_LINK_RATE_540;
+		ctrl->link->link_rate = DP_LINK_BW_5_4;
 		break;
-	case DP_LINK_RATE_540:
-		ctrl->link->link_rate = DP_LINK_RATE_270;
+	case DP_LINK_BW_5_4:
+		ctrl->link->link_rate = DP_LINK_BW_2_7;
 		break;
-	case DP_LINK_RATE_270:
-		ctrl->link->link_rate = DP_LINK_RATE_162;
+	case DP_LINK_BW_2_7:
+		ctrl->link->link_rate = DP_LINK_BW_1_62;
 		break;
-	case DP_LINK_RATE_162:
+	case DP_LINK_BW_1_62:
 	default:
 		ret = -EINVAL;
 		break;
@@ -890,36 +864,38 @@
 
 static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
 {
-	int usleep_time;
-
 	dp_ctrl_train_pattern_set(ctrl, 0);
-
-	usleep_time = ctrl->panel->dpcd.training_read_interval;
-	usleep_range(usleep_time, usleep_time * 2);
+	drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
 }
 
 static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
 {
-	int tries = 0;
-	int ret = 0;
-	int usleep_time;
+	int tries = 0, ret = 0, len = 0;
 	char pattern;
 	int const maximum_retries = 5;
+	u8 link_status[DP_LINK_STATUS_SIZE];
 
-	if (ctrl->panel->dpcd.flags & DPCD_TPS3)
-		pattern = 0x03;
+	if (drm_dp_tps3_supported(ctrl->panel->dpcd))
+		pattern = DP_TRAINING_PATTERN_3;
 	else
-		pattern = 0x02;
+		pattern = DP_TRAINING_PATTERN_2;
 
 	dp_ctrl_update_vx_px(ctrl);
 	ctrl->catalog->set_pattern(ctrl->catalog, pattern);
-	dp_ctrl_train_pattern_set(ctrl, pattern | 0x20);
+	dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN);
 
 	do  {
-		usleep_time = ctrl->panel->dpcd.training_read_interval;
-		usleep_range(usleep_time, usleep_time * 2);
+		drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
 
-		if (ctrl->link->channel_equalization(ctrl->link)) {
+		len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux,
+			link_status);
+		if (len < DP_LINK_STATUS_SIZE) {
+			pr_err("[%s]: DP link status read failed\n", __func__);
+			ret = -1;
+			break;
+		}
+
+		if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count)) {
 			ret = 0;
 			break;
 		}
@@ -930,8 +906,7 @@
 		}
 		tries++;
 
-		ctrl->link->adjust_levels(ctrl->link);
-
+		ctrl->link->adjust_levels(ctrl->link, link_status);
 		dp_ctrl_update_vx_px(ctrl);
 	} while (1);
 
@@ -941,12 +916,7 @@
 static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
 {
 	int ret = 0;
-
-	ret = ctrl->aux->ready(ctrl->aux);
-	if (!ret) {
-		pr_err("aux chan NOT ready\n");
-		return ret;
-	}
+	struct drm_dp_link dp_link;
 
 	ctrl->link->p_level = 0;
 	ctrl->link->v_level = 0;
@@ -954,6 +924,11 @@
 	dp_ctrl_config_ctrl(ctrl);
 	dp_ctrl_state_ctrl(ctrl, 0);
 
+	dp_link.num_lanes = ctrl->link->lane_count;
+	dp_link.rate = ctrl->link->link_rate;
+	dp_link.capabilities = ctrl->panel->dp_link.capabilities;
+	drm_dp_link_configure(ctrl->aux->drm_aux, &dp_link);
+
 	ret = dp_ctrl_link_train_1(ctrl);
 	if (ret < 0) {
 		if (!dp_ctrl_link_rate_down_shift(ctrl)) {
@@ -1007,7 +982,7 @@
 
 	ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
 
-	dp_ctrl_set_sink_power_state(ctrl, SINK_POWER_ON);
+	drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->dp_link);
 
 	if (ctrl->link->phy_pattern_requested(ctrl->link))
 		goto end;
@@ -1065,8 +1040,7 @@
 	ctrl->power->set_pixel_clk_parent(ctrl->power);
 
 	dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
-		(ctrl->link->link_rate * DP_LINK_RATE_MULTIPLIER) /
-			DP_KHZ_TO_HZ);
+		drm_dp_bw_code_to_link_rate(ctrl->link->link_rate));
 
 	dp_ctrl_set_clock_rate(ctrl, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ);
 
@@ -1208,7 +1182,7 @@
 	ctrl->catalog->hpd_config(ctrl->catalog, true);
 
 	ctrl->link->link_rate  = ctrl->panel->get_link_rate(ctrl->panel);
-	ctrl->link->lane_count = ctrl->panel->dpcd.max_lane_count;
+	ctrl->link->lane_count = ctrl->panel->dp_link.num_lanes;
 	ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
 
 	pr_debug("link_rate=%d, lane_count=%d, pixel_rate=%d\n",
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 850acbf..d3f6bca 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -195,6 +195,18 @@
 		goto end;
 	}
 
+	rc = dp->aux->drm_aux_register(dp->aux);
+	if (rc) {
+		pr_err("DRM DP AUX register failed\n");
+		goto end;
+	}
+
+	rc = dp->panel->sde_edid_register(dp->panel);
+	if (rc) {
+		pr_err("DRM DP EDID register failed\n");
+		goto end;
+	}
+
 	rc = dp->power->power_client_init(dp->power, &priv->phandle);
 	if (rc) {
 		pr_err("Power client create failed\n");
@@ -227,6 +239,10 @@
 
 	(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);
 
 	mutex_unlock(&dp->lock);
@@ -245,9 +261,8 @@
 	if (rc)
 		goto end;
 
-	rc = dp->panel->read_edid(dp->panel);
-	if (rc)
-		goto end;
+	sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc,
+		(void **)&dp->panel->edid_ctrl);
 
 	return 0;
 end:
@@ -256,6 +271,7 @@
 
 static int dp_display_process_hpd_low(struct dp_display_private *dp)
 {
+	dp->dp_display.is_connected = false;
 	return 0;
 }
 
@@ -290,6 +306,7 @@
 
 	if (dp->usbpd->hpd_high)
 		dp_display_process_hpd_high(dp);
+	dp->dp_display.is_connected = true;
 
 	mutex_unlock(&dp->lock);
 end:
@@ -315,6 +332,7 @@
 	}
 
 	mutex_lock(&dp->lock);
+	dp->dp_display.is_connected = false;
 	disable_irq(dp->irq);
 	mutex_unlock(&dp->lock);
 
@@ -573,33 +591,17 @@
 	return 0;
 }
 
-static int dp_display_get_modes(struct dp_display *dp,
-	struct dp_display_mode *modes, u32 *count)
+static int dp_display_get_modes(struct dp_display *dp)
 {
-	*count = 1;
+	int ret = 0;
+	struct dp_display_private *dp_display;
 
-	if (modes) {
-		modes->timing.h_active = 1920;
-		modes->timing.v_active = 1080;
-		modes->timing.h_back_porch = 148;
-		modes->timing.h_front_porch = 88;
-		modes->timing.h_sync_width = 44;
-		modes->timing.h_active_low = 0;
-		modes->timing.v_back_porch = 36;
-		modes->timing.v_front_porch = 4;
-		modes->timing.v_sync_width = 5;
-		modes->timing.v_active_low = 0;
-		modes->timing.h_skew = 0;
-		modes->timing.refresh_rate = 60;
-		modes->timing.pixel_clk_khz = 148500;
-	}
+	dp_display = container_of(dp, struct dp_display_private, dp_display);
 
-	return 0;
-}
+	ret = _sde_edid_update_modes(dp->connector,
+		dp_display->panel->edid_ctrl);
 
-static int dp_display_detect(struct dp_display *dp)
-{
-	return 0;
+	return ret;
 }
 
 static int dp_display_probe(struct platform_device *pdev)
@@ -637,7 +639,6 @@
 	g_dp_display->set_mode      = dp_display_set_mode;
 	g_dp_display->validate_mode = dp_display_validate_mode;
 	g_dp_display->get_modes     = dp_display_get_modes;
-	g_dp_display->detect        = dp_display_detect;
 	g_dp_display->prepare       = dp_display_prepare;
 	g_dp_display->unprepare     = dp_display_unprepare;
 	g_dp_display->request_irq   = dp_request_irq;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index e684854..877287a 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -27,6 +27,8 @@
 struct dp_display {
 	struct drm_device *drm_dev;
 	struct dp_bridge *bridge;
+	struct drm_connector *connector;
+	bool is_connected;
 
 	int (*enable)(struct dp_display *dp_display);
 	int (*post_enable)(struct dp_display *dp_display);
@@ -38,11 +40,7 @@
 			struct dp_display_mode *mode);
 	int (*validate_mode)(struct dp_display *dp_display,
 			struct dp_display_mode *mode);
-	int (*get_modes)(struct dp_display *dp_display,
-		struct dp_display_mode *modes, u32 *count);
-
-	int (*detect)(struct dp_display *dp_display);
-
+	int (*get_modes)(struct dp_display *dp_display);
 	int (*prepare)(struct dp_display *dp_display);
 	int (*unprepare)(struct dp_display *dp_display);
 	int (*request_irq)(struct dp_display *dp_display);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 0f6e36f..78c04c4 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -26,8 +26,10 @@
 #define to_dp_bridge(x)     container_of((x), struct dp_bridge, base)
 
 static void convert_to_dp_mode(const struct drm_display_mode *drm_mode,
-				struct dp_display_mode *dp_mode)
+			struct dp_display_mode *dp_mode, struct dp_display *dp)
 {
+	const u32 num_components = 3;
+
 	memset(dp_mode, 0, sizeof(*dp_mode));
 
 	dp_mode->timing.h_active = drm_mode->hdisplay;
@@ -45,6 +47,7 @@
 
 	dp_mode->timing.v_front_porch = drm_mode->vsync_start -
 					 drm_mode->vdisplay;
+	dp_mode->timing.bpp = dp->connector->display_info.bpc * num_components;
 
 	dp_mode->timing.refresh_rate = drm_mode->vrefresh;
 
@@ -235,7 +238,7 @@
 	dp = bridge->display;
 
 	memset(&bridge->dp_mode, 0x0, sizeof(struct dp_display_mode));
-	convert_to_dp_mode(adjusted_mode, &bridge->dp_mode);
+	convert_to_dp_mode(adjusted_mode, &bridge->dp_mode, dp);
 }
 
 static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge,
@@ -257,7 +260,7 @@
 	bridge = to_dp_bridge(drm_bridge);
 	dp = bridge->display;
 
-	convert_to_dp_mode(mode, &dp_mode);
+	convert_to_dp_mode(mode, &dp_mode, dp);
 
 	rc = dp->validate_mode(dp, &dp_mode);
 	if (rc) {
@@ -289,6 +292,7 @@
 	if (!info || !dp_display)
 		return -EINVAL;
 
+	dp_display->connector = connector;
 	return 0;
 }
 
@@ -315,7 +319,7 @@
 
 int dp_connector_get_info(struct msm_display_info *info, void *data)
 {
-	struct dsi_display *display = data;
+	struct dp_display *display = data;
 
 	if (!info || !display) {
 		pr_err("invalid params\n");
@@ -326,17 +330,10 @@
 
 	info->num_of_h_tiles = 1;
 	info->h_tile_instance[0] = 0;
-
-	info->is_connected = true;
-	info->frame_rate = 60;
-	info->width_mm = 160;
-	info->height_mm = 90;
-	info->max_width = 1920;
-	info->max_height = 1080;
-	info->vtotal = 1125;
-	info->is_primary = true;
+	info->is_connected = display->is_connected;
 	info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
-	info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
+	info->capabilities = MSM_DISPLAY_CAP_VID_MODE | MSM_DISPLAY_CAP_EDID |
+		MSM_DISPLAY_CAP_HOT_PLUG;
 
 	return 0;
 }
@@ -375,60 +372,23 @@
 int dp_connector_get_modes(struct drm_connector *connector,
 		void *display)
 {
-	u32 count = 0;
-	u32 size = 0;
-	struct dp_display_mode *modes;
-	struct drm_display_mode drm_mode;
+	int rc = 0;
 	struct dp_display *dp;
-	int rc, i;
 
-	if (!connector || !display || sde_connector_get_panel(connector))
-		goto end;
+	if (!connector || !display)
+		return -EINVAL;
 
 	dp = display;
-
-	rc = dp->get_modes(dp, NULL, &count);
-	if (rc) {
-		pr_err("failed to get num of modes, rc=%d\n", rc);
-		goto end;
+	/* pluggable case assumes EDID is read when HPD */
+	if (dp->is_connected) {
+		rc = dp->get_modes(dp);
+		if (!rc)
+			pr_err("failed to get DP sink modes, rc=%d\n", rc);
+	} else {
+		pr_err("No sink connected\n");
 	}
 
-	size = count * sizeof(*modes);
-	modes = kzalloc(size,  GFP_KERNEL);
-	if (!modes) {
-		count = 0;
-		goto end;
-	}
-
-	rc = dp->get_modes(dp, modes, &count);
-	if (rc) {
-		pr_err("failed to get modes, rc=%d\n", rc);
-		count = 0;
-		goto error;
-	}
-
-	for (i = 0; i < count; i++) {
-		struct drm_display_mode *m;
-
-		memset(&drm_mode, 0x0, sizeof(drm_mode));
-		convert_to_drm_mode(&modes[i], &drm_mode);
-		m = drm_mode_duplicate(connector->dev, &drm_mode);
-		if (!m) {
-			pr_err("failed to add mode %ux%u\n",
-			       drm_mode.hdisplay,
-			       drm_mode.vdisplay);
-			count = -ENOMEM;
-			goto error;
-		}
-		m->width_mm = connector->display_info.width_mm;
-		m->height_mm = connector->display_info.height_mm;
-		drm_mode_probed_add(connector, m);
-	}
-error:
-	kfree(modes);
-end:
-	pr_debug("MODE COUNT =%d\n\n", count);
-	return count;
+	return 0;
 }
 
 int dp_drm_bridge_init(void *data, struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index e9955a9..741acfca 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -114,18 +114,6 @@
 	bool cp_ready;
 };
 
-struct dp_link_status {
-	u8 lane_01_status;
-	u8 lane_23_status;
-	u8 interlane_align_done;
-	u8 downstream_port_status_changed;
-	u8 link_status_updated;
-	u8 port_0_in_sync;
-	u8 port_1_in_sync;
-	u8 req_voltage_swing[4];
-	u8 req_pre_emphasis[4];
-};
-
 struct dp_link_private {
 	struct device *dev;
 	struct dp_aux *aux;
@@ -133,7 +121,7 @@
 
 	struct dp_link_request request;
 	struct dp_link_sink_count sink_count;
-	struct dp_link_status link_status;
+	u8 link_status[DP_LINK_STATUS_SIZE];
 };
 
 /**
@@ -232,13 +220,12 @@
 	int ret = 0;
 	u8 *bp;
 	u8 data;
-	int rlen;
 	u32 const param_len = 0x1;
 	u32 const max_audio_period = 0xA;
 
 	/* TEST_AUDIO_PERIOD_CH_XX */
-	rlen = link->aux->read(link->aux, addr, param_len, AUX_NATIVE, &bp);
-	if (rlen < param_len) {
+	if (drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp,
+		param_len) < param_len) {
 		pr_err("failed to read test_audio_period (0x%x)\n", addr);
 		ret = -EINVAL;
 		goto exit;
@@ -350,8 +337,8 @@
 	int const max_audio_pattern_type = 0x1;
 
 	/* Read the requested audio pattern type (Byte 0x272). */
-	rlen = link->aux->read(link->aux, test_audio_pattern_type_addr,
-			param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux,
+		test_audio_pattern_type_addr, &bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link audio mode data\n");
 		ret = -EINVAL;
@@ -387,8 +374,8 @@
 	int channel_count = 0x0;
 
 	/* Read the requested audio mode (Byte 0x271). */
-	rlen = link->aux->read(link->aux, test_audio_mode_addr,
-			param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_audio_mode_addr,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link audio mode data\n");
 		ret = -EINVAL;
@@ -555,7 +542,7 @@
 		return -EINVAL;
 
 	/* Read the requested video link pattern (Byte 0x221). */
-	rlen = link->aux->read(link->aux, addr, len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
 	if (rlen < len) {
 		pr_err("failed to read 0x%x\n", addr);
 		return -EINVAL;
@@ -576,7 +563,7 @@
 		return -EINVAL;
 
 	/* Read the requested video link pattern (Byte 0x221). */
-	rlen = link->aux->read(link->aux, addr, len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
 	if (rlen < len) {
 		pr_err("failed to read 0x%x\n", addr);
 		return -EINVAL;
@@ -596,7 +583,7 @@
 	int rlen;
 
 	/* Read the requested video link pattern (Byte 0x221). */
-	rlen = link->aux->read(link->aux, addr, len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
 	if (rlen < 1) {
 		pr_err("failed to read 0x%x\n", addr);
 		return -EINVAL;
@@ -625,8 +612,8 @@
 	int const test_misc_addr = 0x232;
 
 	/* Read the requested video link pattern (Byte 0x221). */
-	rlen = link->aux->read(link->aux, test_video_pattern_addr,
-			param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_video_pattern_addr,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link video pattern\n");
 		ret = -EINVAL;
@@ -647,8 +634,8 @@
 			link->request.test_video_pattern));
 
 	/* Read the requested color bit depth and dynamic range (Byte 0x232) */
-	rlen = link->aux->read(link->aux, test_misc_addr,
-			param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_misc_addr,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link bit depth\n");
 		ret = -EINVAL;
@@ -780,9 +767,9 @@
  */
 static bool dp_link_is_link_rate_valid(u32 link_rate)
 {
-	return ((link_rate == DP_LINK_RATE_162) ||
-		(link_rate == DP_LINK_RATE_270) ||
-		(link_rate == DP_LINK_RATE_540) ||
+	return ((link_rate == DP_LINK_BW_1_62) ||
+		(link_rate == DP_LINK_BW_2_7) ||
+		(link_rate == DP_LINK_BW_5_4) ||
 		(link_rate == DP_LINK_RATE_810));
 }
 
@@ -814,12 +801,10 @@
 	int ret = 0;
 	int rlen;
 	int const param_len = 0x1;
-	int const test_link_rate_addr = 0x219;
-	int const test_lane_count_addr = 0x220;
 
 	/* Read the requested link rate (Byte 0x219). */
-	rlen = link->aux->read(link->aux, test_link_rate_addr,
-			param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LINK_RATE,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link rate\n");
 		ret = -EINVAL;
@@ -837,8 +822,8 @@
 	pr_debug("link rate = 0x%x\n", link->request.test_link_rate);
 
 	/* Read the requested lane count (Byte 0x220). */
-	rlen = link->aux->read(link->aux, test_lane_count_addr,
-			param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LANE_COUNT,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read lane count\n");
 		ret = -EINVAL;
@@ -890,8 +875,8 @@
 	int const phy_test_pattern_addr = 0x248;
 	int ret = 0;
 
-	rlen = link->aux->read(link->aux, phy_test_pattern_addr,
-				param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, phy_test_pattern_addr,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read phy link pattern\n");
 		ret = -EINVAL;
@@ -965,16 +950,14 @@
 	u8 data;
 	int rlen;
 	u32 const param_len = 0x1;
-	u32 const device_service_irq_addr = 0x201;
-	u32 const test_request_addr = 0x218;
 	u8 buf[4];
 
 	/**
 	 * Read the device service IRQ vector (Byte 0x201) to determine
 	 * whether an automated link has been requested by the sink.
 	 */
-	rlen = link->aux->read(link->aux, device_service_irq_addr,
-				param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux,
+		DP_DEVICE_SERVICE_IRQ_VECTOR, &bp, param_len);
 	if (rlen < param_len) {
 		pr_err("aux read failed\n");
 		ret = -EINVAL;
@@ -994,8 +977,8 @@
 	 * Read the link request byte (Byte 0x218) to determine what type
 	 * of automated link has been requested by the sink.
 	 */
-	rlen = link->aux->read(link->aux, test_request_addr,
-				param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_REQUEST,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("aux read failed\n");
 		ret = -EINVAL;
@@ -1033,7 +1016,7 @@
 end:
 	/* clear the link request IRQ */
 	buf[0] = 1;
-	link->aux->write(link->aux, test_request_addr, 1, AUX_NATIVE, buf);
+	drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_REQUEST, buf, 1);
 
 	/**
 	 * Send a TEST_ACK if all link parameters are valid, otherwise send
@@ -1060,10 +1043,9 @@
 	u8 data;
 	int rlen;
 	int const param_len = 0x1;
-	int const sink_count_addr = 0x200;
 
-	rlen = link->aux->read(link->aux, sink_count_addr,
-				param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_SINK_COUNT,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read sink count\n");
 		return;
@@ -1080,67 +1062,16 @@
 		link->sink_count.count, link->sink_count.cp_ready);
 }
 
-static int dp_link_link_status_read(struct dp_link_private *link)
-{
-	u8 *bp;
-	u8 data;
-	int rlen, ret = 0;
-	int const addr = 0x202;
-	int const len = 6;
-	struct dp_link_status *sp;
-
-	rlen = link->aux->read(link->aux, addr, len, AUX_NATIVE, &bp);
-	if (rlen < len) {
-		pr_err("edp aux read failed\n");
-		ret = -EINVAL;
-		goto error;
-	}
-
-	sp = &link->link_status;
-
-	data = *bp++; /* byte 0x202 */
-	sp->lane_01_status = data; /* lane 0, 1 */
-
-	data = *bp++; /* byte 0x203 */
-	sp->lane_23_status = data; /* lane 2, 3 */
-
-	data = *bp++; /* byte 0x204 */
-	sp->interlane_align_done = (data & BIT(0));
-	sp->downstream_port_status_changed = (data & BIT(6));
-	sp->link_status_updated = (data & BIT(7));
-
-	data = *bp++; /* byte 0x205 */
-	sp->port_0_in_sync = (data & BIT(0));
-	sp->port_1_in_sync = (data & BIT(1));
-
-	data = *bp++; /* byte 0x206 */
-	sp->req_voltage_swing[0] = data & 0x03;
-	data >>= 2;
-	sp->req_pre_emphasis[0] = data & 0x03;
-	data >>= 2;
-	sp->req_voltage_swing[1] = data & 0x03;
-	data >>= 2;
-	sp->req_pre_emphasis[1] = data & 0x03;
-
-	data = *bp++; /* byte 0x207 */
-	sp->req_voltage_swing[2] = data & 0x03;
-	data >>= 2;
-	sp->req_pre_emphasis[2] = data & 0x03;
-	data >>= 2;
-	sp->req_voltage_swing[3] = data & 0x03;
-	data >>= 2;
-	sp->req_pre_emphasis[3] = data & 0x03;
-
-	return 0;
-error:
-	return ret;
-}
-
 static void dp_link_parse_sink_status_field(struct dp_link_private *link)
 {
+	int len = 0;
+
 	dp_link_parse_sink_count(link);
 	dp_link_parse_request(link);
-	dp_link_link_status_read(link);
+	len = drm_dp_dpcd_read_link_status(link->aux->drm_aux,
+		link->link_status);
+	if (len < DP_LINK_STATUS_SIZE)
+		pr_err("DP link status read failed\n");
 }
 
 static bool dp_link_is_link_training_requested(struct dp_link_private *link)
@@ -1196,7 +1127,7 @@
 
 	pr_debug("\n");
 
-	rlen = link->aux->read(link->aux, addr1, param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr1, &bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed reading lanes 0/1\n");
 		ret = -EINVAL;
@@ -1217,7 +1148,7 @@
 	p1 = data & 0x3;
 	data = data >> 2;
 
-	rlen = link->aux->read(link->aux, addr2, param_len, AUX_NATIVE, &bp);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr2, &bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed reading lanes 2/3\n");
 		ret = -EINVAL;
@@ -1294,76 +1225,6 @@
 	return 0;
 }
 
-static bool dp_link_is_link_status_updated(struct dp_link_private *link)
-{
-	return link->link_status.link_status_updated;
-}
-
-static bool dp_link_channel_eq_done(struct dp_link_private *link)
-{
-	u32 mask, data;
-	struct dp_link *dp_link = &link->dp_link;
-
-	pr_debug("\n");
-
-	dp_link_link_status_read(link);
-
-	if (!link->link_status.interlane_align_done) { /* not align */
-		pr_err("interlane align failed\n");
-		return 0;
-	}
-
-	if (dp_link->lane_count == 1) {
-		mask = 0x7;
-		data = link->link_status.lane_01_status;
-	} else if (dp_link->lane_count == 2) {
-		mask = 0x77;
-		data = link->link_status.lane_01_status;
-	} else {
-		mask = 0x7777;
-		data = link->link_status.lane_23_status;
-		data <<= 8;
-		data |= link->link_status.lane_01_status;
-	}
-
-	data &= mask;
-	pr_debug("data=%x mask=%x\n", data, mask);
-
-	if (data == mask)/* all done */
-		return true;
-
-	return false;
-}
-
-static bool dp_link_clock_recovery_done(struct dp_link_private *link)
-{
-	u32 mask, data;
-	struct dp_link *dp_link = &link->dp_link;
-
-	dp_link_link_status_read(link);
-
-	if (dp_link->lane_count == 1) {
-		mask = 0x01;	/* lane 0 */
-		data = link->link_status.lane_01_status;
-	} else if (dp_link->lane_count == 2) {
-		mask = 0x011; /*B lane 0, 1 */
-		data = link->link_status.lane_01_status;
-	} else {
-		mask = 0x01111; /*B lane 0, 1 */
-		data = link->link_status.lane_23_status;
-		data <<= 8;
-		data |= link->link_status.lane_01_status;
-	}
-
-	data &= mask;
-	pr_debug("data=%x mask=%x\n", data, mask);
-
-	if (data == mask) /* all done */
-		return true;
-
-	return false;
-}
-
 /**
  * dp_link_process_link_status_update() - processes link status updates
  * @link: Display Port link module data
@@ -1377,21 +1238,25 @@
  */
 static int dp_link_process_link_status_update(struct dp_link_private *link)
 {
-	if (!dp_link_is_link_status_updated(link) ||
-	    (dp_link_channel_eq_done(link) &&
-	     dp_link_clock_recovery_done(link)))
+	if (!(link->link_status[2] & BIT(7)) || /* link status updated */
+		(drm_dp_clock_recovery_ok(link->link_status,
+			link->dp_link.lane_count) &&
+	     drm_dp_channel_eq_ok(link->link_status,
+			link->dp_link.lane_count)))
 		return -EINVAL;
 
 	pr_debug("channel_eq_done = %d, clock_recovery_done = %d\n",
-			dp_link_channel_eq_done(link),
-			dp_link_clock_recovery_done(link));
+			drm_dp_clock_recovery_ok(link->link_status,
+			link->dp_link.lane_count),
+			drm_dp_clock_recovery_ok(link->link_status,
+			link->dp_link.lane_count));
 
 	return 0;
 }
 
 static bool dp_link_is_ds_port_status_changed(struct dp_link_private *link)
 {
-	return link->link_status.downstream_port_status_changed;
+	return (link->link_status[2] & BIT(6)); /* port status changed */
 }
 
 /**
@@ -1562,37 +1427,6 @@
 	return ret;
 }
 
-static u8 *dp_link_get_voltage_swing(struct dp_link *dp_link)
-
-{
-	struct dp_link_private *link;
-
-	if (!dp_link) {
-		pr_err("invalid input\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	link = container_of(dp_link, struct dp_link_private, dp_link);
-
-	return link->link_status.req_voltage_swing;
-}
-
-static u8 *dp_link_get_pre_emphasis(struct dp_link *dp_link)
-
-{
-	struct dp_link_private *link;
-
-
-	if (!dp_link) {
-		pr_err("invalid input\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	link = container_of(dp_link, struct dp_link_private, dp_link);
-
-	return link->link_status.req_pre_emphasis;
-}
-
 static int dp_link_get_colorimetry_config(struct dp_link *dp_link)
 {
 	u32 cc;
@@ -1625,38 +1459,11 @@
 	return cc;
 }
 
-static bool dp_link_clock_recovery(struct dp_link *dp_link)
-{
-	struct dp_link_private *link;
-
-	if (!dp_link) {
-		pr_err("invalid input\n");
-		return -EINVAL;
-	}
-
-	link = container_of(dp_link, struct dp_link_private, dp_link);
-
-	return dp_link_clock_recovery_done(link);
-}
-
-static bool dp_link_channel_equalization(struct dp_link *dp_link)
-{
-	struct dp_link_private *link;
-
-	if (!dp_link) {
-		pr_err("invalid input\n");
-		return -EINVAL;
-	}
-
-	link = container_of(dp_link, struct dp_link_private, dp_link);
-
-	return dp_link_channel_eq_done(link);
-}
-
-static int dp_link_adjust_levels(struct dp_link *dp_link)
+static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
 {
 	int i;
 	int max = 0;
+	u8 data;
 	struct dp_link_private *link;
 
 	if (!dp_link) {
@@ -1668,24 +1475,24 @@
 
 	/* use the max level across lanes */
 	for (i = 0; i < dp_link->lane_count; i++) {
-		pr_debug("lane=%d req_voltage_swing=%d\n",
-			i, link->link_status.req_voltage_swing[i]);
-		if (max < link->link_status.req_voltage_swing[i])
-			max = link->link_status.req_voltage_swing[i];
+		data = drm_dp_get_adjust_request_voltage(link_status, i);
+		pr_debug("lane=%d req_voltage_swing=%d\n", i, data);
+		if (max < data)
+			max = data;
 	}
 
-	dp_link->v_level = max;
+	dp_link->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
 
 	/* use the max level across lanes */
 	max = 0;
 	for (i = 0; i < dp_link->lane_count; i++) {
-		pr_debug("lane=%d req_pre_emphasis=%d\n",
-			i, link->link_status.req_pre_emphasis[i]);
-		if (max < link->link_status.req_pre_emphasis[i])
-			max = link->link_status.req_pre_emphasis[i];
+		data = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
+		pr_debug("lane=%d req_pre_emphasis=%d\n", i, data);
+		if (max < data)
+			max = data;
 	}
 
-	dp_link->p_level = max;
+	dp_link->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
 
 	/**
 	 * Adjust the voltage swing and pre-emphasis level combination to within
@@ -1781,12 +1588,8 @@
 	dp_link = &link->dp_link;
 
 	dp_link->process_request        = dp_link_process_request;
-	dp_link->get_voltage_swing      = dp_link_get_voltage_swing;
 	dp_link->get_test_bits_depth    = dp_link_get_test_bits_depth;
-	dp_link->get_pre_emphasis       = dp_link_get_pre_emphasis;
 	dp_link->get_colorimetry_config = dp_link_get_colorimetry_config;
-	dp_link->clock_recovery         = dp_link_clock_recovery;
-	dp_link->channel_equalization   = dp_link_channel_equalization;
 	dp_link->adjust_levels          = dp_link_adjust_levels;
 	dp_link->send_psm_request       = dp_link_send_psm_request;
 	dp_link->phy_pattern_requested  = dp_link_phy_pattern_requested;
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index de10e9a..26249d6 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -54,15 +54,11 @@
 	u32 v_level;
 	u32 p_level;
 
-	u8 *(*get_voltage_swing)(struct dp_link *dp_link);
-	u8 *(*get_pre_emphasis)(struct dp_link *dp_link);
 	u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp);
 	int (*process_request)(struct dp_link *dp_link);
 	int (*get_colorimetry_config)(struct dp_link *dp_link);
-	int (*adjust_levels)(struct dp_link *dp_link);
+	int (*adjust_levels)(struct dp_link *dp_link, u8 *link_status);
 	int (*send_psm_request)(struct dp_link *dp_link, bool req);
-	bool (*clock_recovery)(struct dp_link *dp_link);
-	bool (*channel_equalization)(struct dp_link *dp_link);
 	bool (*phy_pattern_requested)(struct dp_link *dp_link);
 };
 
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index f9616c4..fed1dbb 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -16,7 +16,9 @@
 
 #include "dp_panel.h"
 
-#define DP_LINK_RATE_MULTIPLIER	27000000
+enum {
+	DP_LINK_RATE_MULTIPLIER = 27000000,
+};
 
 struct dp_panel_private {
 	struct device *dev;
@@ -27,13 +29,10 @@
 
 static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
 {
-	u8 *bp;
-	u8 data;
-	u32 const addr = 0x0;
-	u32 const len = 16;
 	int rlen, rc = 0;
 	struct dp_panel_private *panel;
-	struct dp_panel_dpcd *cap;
+	struct drm_dp_link *dp_link;
+	u8 major = 0, minor = 0;
 
 	if (!dp_panel) {
 		pr_err("invalid input\n");
@@ -41,236 +40,38 @@
 		goto end;
 	}
 
-	cap = &dp_panel->dpcd;
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+	dp_link = &dp_panel->dp_link;
 
-	rlen = panel->aux->read(panel->aux, addr, len, AUX_NATIVE, &bp);
-	if (rlen != len) {
+	rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV,
+		dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1));
+	if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) {
 		pr_err("dpcd read failed, rlen=%d\n", rlen);
 		rc = -EINVAL;
 		goto end;
 	}
 
-	memset(cap, 0, sizeof(*cap));
+	dp_link->revision = dp_panel->dpcd[DP_DPCD_REV];
 
-	data = *bp++; /* byte 0 */
-	cap->major = (data >> 4) & 0x0f;
-	cap->minor = data & 0x0f;
-	pr_debug("version: %d.%d\n", cap->major, cap->minor);
+	major = (dp_link->revision >> 4) & 0x0f;
+	minor = dp_link->revision & 0x0f;
+	pr_debug("version: %d.%d\n", major, minor);
 
-	data = *bp++; /* byte 1 */
-	/* 162, 270, 540, 810 MB, symbol rate, NOT bit rate */
-	cap->max_link_rate = data;
-	pr_debug("link_rate=%d\n", cap->max_link_rate);
+	dp_link->rate =
+		drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]);
+	pr_debug("link_rate=%d\n", dp_link->rate);
 
-	data = *bp++; /* byte 2 */
-	if (data & BIT(7))
-		cap->enhanced_frame++;
+	dp_link->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
+			DP_MAX_LANE_COUNT_MASK;
+	pr_debug("lane_count=%d\n", dp_link->num_lanes);
 
-	if (data & 0x40) {
-		cap->flags |=  DPCD_TPS3;
-		pr_debug("pattern 3 supported\n");
-	} else {
-		pr_debug("pattern 3 not supported\n");
-	}
+	if (dp_panel->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)
+		dp_link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
 
-	data &= 0x0f;
-	cap->max_lane_count = data;
-	pr_debug("lane_count=%d\n", cap->max_lane_count);
-
-	data = *bp++; /* byte 3 */
-	if (data & BIT(0)) {
-		cap->flags |= DPCD_MAX_DOWNSPREAD_0_5;
-		pr_debug("max_downspread\n");
-	}
-
-	if (data & BIT(6)) {
-		cap->flags |= DPCD_NO_AUX_HANDSHAKE;
-		pr_debug("NO Link Training\n");
-	}
-
-	data = *bp++; /* byte 4 */
-	cap->num_rx_port = (data & BIT(0)) + 1;
-	pr_debug("rx_ports=%d", cap->num_rx_port);
-
-	data = *bp++; /* Byte 5: DOWN_STREAM_PORT_PRESENT */
-	cap->downstream_port.dfp_present = data & BIT(0);
-	cap->downstream_port.dfp_type = data & 0x6;
-	cap->downstream_port.format_conversion = data & BIT(3);
-	cap->downstream_port.detailed_cap_info_available = data & BIT(4);
-	pr_debug("dfp_present = %d, dfp_type = %d\n",
-			cap->downstream_port.dfp_present,
-			cap->downstream_port.dfp_type);
-	pr_debug("format_conversion = %d, detailed_cap_info_available = %d\n",
-			cap->downstream_port.format_conversion,
-			cap->downstream_port.detailed_cap_info_available);
-
-	bp += 1;	/* Skip Byte 6 */
-	rlen -= 1;
-
-	data = *bp++; /* Byte 7: DOWN_STREAM_PORT_COUNT */
-	cap->downstream_port.dfp_count = data & 0x7;
-	cap->downstream_port.msa_timing_par_ignored = data & BIT(6);
-	cap->downstream_port.oui_support = data & BIT(7);
-	pr_debug("dfp_count = %d, msa_timing_par_ignored = %d\n",
-			cap->downstream_port.dfp_count,
-			cap->downstream_port.msa_timing_par_ignored);
-	pr_debug("oui_support = %d\n", cap->downstream_port.oui_support);
-
-	data = *bp++; /* byte 8 */
-	if (data & BIT(1)) {
-		cap->flags |= DPCD_PORT_0_EDID_PRESENTED;
-		pr_debug("edid presented\n");
-	}
-
-	data = *bp++; /* byte 9 */
-	cap->rx_port0_buf_size = (data + 1) * 32;
-	pr_debug("lane_buf_size=%d\n", cap->rx_port0_buf_size);
-
-	bp += 2; /* skip 10, 11 port1 capability */
-	rlen -= 2;
-
-	data = *bp++;	/* byte 12 */
-	cap->i2c_speed_ctrl = data;
-	if (cap->i2c_speed_ctrl > 0)
-		pr_debug("i2c_rate=%d", cap->i2c_speed_ctrl);
-
-	data = *bp++;	/* byte 13 */
-	cap->scrambler_reset = data & BIT(0);
-	pr_debug("scrambler_reset=%d\n", cap->scrambler_reset);
-
-	if (data & BIT(1))
-		cap->enhanced_frame++;
-
-	pr_debug("enhanced_framing=%d\n", cap->enhanced_frame);
-
-	data = *bp++; /* byte 14 */
-	if (data == 0)
-		cap->training_read_interval = 4000; /* us */
-	else
-		cap->training_read_interval = 4000 * data; /* us */
-	pr_debug("training_interval=%d\n", cap->training_read_interval);
 end:
 	return rc;
 }
 
-/*
- * edid standard header bytes
- */
-static u8 edid_hdr[8] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
-
-static bool dp_panel_is_edid_header_valid(u8 *buf)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(edid_hdr); i++) {
-		if (buf[i] != edid_hdr[i])
-			return false;
-	}
-
-	return true;
-}
-
-static int dp_panel_validate_edid(u8 *bp, int len)
-{
-	int i;
-	u8 csum = 0;
-	u32 const size = 128;
-
-	if (len < size) {
-		pr_err("Error: len=%x\n", len);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < size; i++)
-		csum += *bp++;
-
-	if (csum != 0) {
-		pr_err("error: csum=0x%x\n", csum);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int dp_panel_read_edid(struct dp_panel *dp_panel)
-{
-	u8 *edid_buf;
-	u32 checksum = 0;
-	int rlen, ret = 0;
-	int edid_blk = 0, blk_num = 0, retries = 10;
-	u32 const segment_addr = 0x30;
-	bool edid_parsing_done = false;
-	struct dp_panel_private *panel;
-
-	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
-
-	ret = panel->aux->ready(panel->aux);
-	if (!ret) {
-		pr_err("aux chan NOT ready\n");
-		goto end;
-	}
-
-	do {
-		u8 segment;
-
-
-		/*
-		 * Write the segment first.
-		 * Segment = 0, for blocks 0 and 1
-		 * Segment = 1, for blocks 2 and 3
-		 * Segment = 2, for blocks 3 and 4
-		 * and so on ...
-		 */
-		segment = blk_num >> 1;
-
-		panel->aux->write(panel->aux, segment_addr, 1, AUX_I2C,
-					&segment);
-
-		rlen = panel->aux->read(panel->aux, EDID_START_ADDRESS +
-				(blk_num * EDID_BLOCK_SIZE),
-				EDID_BLOCK_SIZE, AUX_I2C, &edid_buf);
-		if (rlen != EDID_BLOCK_SIZE) {
-			pr_err("invalid edid len: %d\n", rlen);
-			continue;
-		}
-
-		pr_debug("=== EDID data ===\n");
-		print_hex_dump(KERN_DEBUG, "EDID: ", DUMP_PREFIX_NONE, 16, 1,
-			edid_buf, EDID_BLOCK_SIZE, false);
-
-		pr_debug("blk_num=%d, rlen=%d\n", blk_num, rlen);
-
-		if (dp_panel_is_edid_header_valid(edid_buf)) {
-			ret = dp_panel_validate_edid(edid_buf, rlen);
-			if (ret) {
-				pr_err("corrupt edid block detected\n");
-				goto end;
-			}
-
-			if (edid_parsing_done) {
-				blk_num++;
-				continue;
-			}
-
-			dp_panel->edid.ext_block_cnt = edid_buf[0x7E];
-			edid_parsing_done = true;
-			checksum = edid_buf[rlen - 1];
-		} else {
-			edid_blk++;
-			blk_num++;
-		}
-
-		memcpy(dp_panel->edid.buf + (edid_blk * EDID_BLOCK_SIZE),
-			edid_buf, EDID_BLOCK_SIZE);
-
-		if (edid_blk == dp_panel->edid.ext_block_cnt)
-			goto end;
-	} while (retries--);
-end:
-	return ret;
-}
-
 static int dp_panel_timing_cfg(struct dp_panel *dp_panel)
 {
 	int rc = 0;
@@ -334,6 +135,36 @@
 	return rc;
 }
 
+static int dp_panel_edid_register(struct dp_panel *dp_panel)
+{
+	int rc = 0;
+
+	if (!dp_panel) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	dp_panel->edid_ctrl = sde_edid_init();
+	if (!dp_panel->edid_ctrl) {
+		pr_err("sde edid init for DP failed\n");
+		rc = -ENOMEM;
+		goto end;
+	}
+end:
+	return rc;
+}
+
+static void dp_panel_edid_deregister(struct dp_panel *dp_panel)
+{
+	if (!dp_panel) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	sde_edid_deinit((void **)&dp_panel->edid_ctrl);
+}
+
 static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
 {
 	int rc = 0;
@@ -350,12 +181,12 @@
 	return rc;
 }
 
-static u8 dp_panel_get_link_rate(struct dp_panel *dp_panel)
+static u32 dp_panel_get_link_rate(struct dp_panel *dp_panel)
 {
 	const u32 encoding_factx10 = 8;
 	const u32 ln_to_link_ratio = 10;
 	u32 min_link_rate, reminder = 0;
-	u8 calc_link_rate = 0, lane_cnt;
+	u32 calc_link_rate = 0, lane_cnt, max_rate = 0;
 	struct dp_panel_private *panel;
 	struct dp_panel_info *pinfo;
 
@@ -366,11 +197,10 @@
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
 
-	lane_cnt = dp_panel->dpcd.max_lane_count;
+	lane_cnt = dp_panel->dp_link.num_lanes;
+	max_rate = drm_dp_link_rate_to_bw_code(dp_panel->dp_link.rate);
 	pinfo = &dp_panel->pinfo;
 
-	pinfo->bpp = 24;
-
 	/*
 	 * The max pixel clock supported is 675Mhz. The
 	 * current calculations below will make sure
@@ -393,12 +223,12 @@
 		min_link_rate += 1;
 	pr_debug("min_link_rate = %d\n", min_link_rate);
 
-	if (min_link_rate <= DP_LINK_RATE_162)
-		calc_link_rate = DP_LINK_RATE_162;
-	else if (min_link_rate <= DP_LINK_RATE_270)
-		calc_link_rate = DP_LINK_RATE_270;
-	else if (min_link_rate <= DP_LINK_RATE_540)
-		calc_link_rate = DP_LINK_RATE_540;
+	if (min_link_rate <= DP_LINK_BW_1_62)
+		calc_link_rate = DP_LINK_BW_1_62;
+	else if (min_link_rate <= DP_LINK_BW_2_7)
+		calc_link_rate = DP_LINK_BW_2_7;
+	else if (min_link_rate <= DP_LINK_BW_5_4)
+		calc_link_rate = DP_LINK_BW_5_4;
 	else if (min_link_rate <= DP_LINK_RATE_810)
 		calc_link_rate = DP_LINK_RATE_810;
 	else {
@@ -407,8 +237,8 @@
 		calc_link_rate = DP_LINK_RATE_810;
 	}
 
-	if (calc_link_rate > dp_panel->dpcd.max_link_rate)
-		calc_link_rate = dp_panel->dpcd.max_link_rate;
+	if (calc_link_rate > max_rate)
+		calc_link_rate = max_rate;
 
 	pr_debug("calc_link_rate = 0x%x\n", calc_link_rate);
 end:
@@ -440,12 +270,10 @@
 
 	dp_panel = &panel->dp_panel;
 
-	dp_panel->edid.buf = devm_kzalloc(dev,
-				sizeof(EDID_BLOCK_SIZE) * 4, GFP_KERNEL);
-
+	dp_panel->sde_edid_register = dp_panel_edid_register;
+	dp_panel->sde_edid_deregister = dp_panel_edid_deregister;
 	dp_panel->init_info = dp_panel_init_panel_info;
 	dp_panel->timing_cfg = dp_panel_timing_cfg;
-	dp_panel->read_edid = dp_panel_read_edid;
 	dp_panel->read_dpcd = dp_panel_read_dpcd;
 	dp_panel->get_link_rate = dp_panel_get_link_rate;
 
@@ -463,6 +291,5 @@
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
 
-	devm_kfree(panel->dev, dp_panel->edid.buf);
 	devm_kfree(panel->dev, panel);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 5c145eb..5852c70 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -16,66 +16,9 @@
 #define _DP_PANEL_H_
 
 #include "dp_aux.h"
+#include "sde_edid_parser.h"
 
-#define DPCD_ENHANCED_FRAME     BIT(0)
-#define DPCD_TPS3               BIT(1)
-#define DPCD_MAX_DOWNSPREAD_0_5 BIT(2)
-#define DPCD_NO_AUX_HANDSHAKE   BIT(3)
-#define DPCD_PORT_0_EDID_PRESENTED BIT(4)
-
-#define EDID_START_ADDRESS	0x50
-#define EDID_BLOCK_SIZE		0x80
-
-
-#define DP_LINK_RATE_162	6	/* 1.62G = 270M * 6 */
-#define DP_LINK_RATE_270	10	/* 2.70G = 270M * 10 */
-#define DP_LINK_RATE_540	20	/* 5.40G = 270M * 20 */
 #define DP_LINK_RATE_810	30	/* 8.10G = 270M * 30 */
-#define DP_LINK_RATE_MAX	DP_LINK_RATE_810
-
-struct downstream_port_config {
-	/* Byte 02205h */
-	bool dfp_present;
-	u32 dfp_type;
-	bool format_conversion;
-	bool detailed_cap_info_available;
-	/* Byte 02207h */
-	u32 dfp_count;
-	bool msa_timing_par_ignored;
-	bool oui_support;
-};
-
-struct dp_panel_dpcd {
-	u8 major;
-	u8 minor;
-	u8 max_lane_count;
-	u8 num_rx_port;
-	u8 i2c_speed_ctrl;
-	u8 scrambler_reset;
-	u8 enhanced_frame;
-	u32 max_link_rate;  /* 162, 270 and 540 Mb, divided by 10 */
-	u32 flags;
-	u32 rx_port0_buf_size;
-	u32 training_read_interval;/* us */
-	struct downstream_port_config downstream_port;
-};
-
-struct dp_panel_edid {
-	u8 *buf;
-	u8 id_name[4];
-	u8 id_product;
-	u8 version;
-	u8 revision;
-	u8 video_intf;	/* dp == 0x5 */
-	u8 color_depth;	/* 6, 8, 10, 12 and 14 bits */
-	u8 color_format;	/* RGB 4:4:4, YCrCb 4:4:4, Ycrcb 4:2:2 */
-	u8 dpm;		/* display power management */
-	u8 sync_digital;	/* 1 = digital */
-	u8 sync_separate;	/* 1 = separate */
-	u8 vsync_pol;		/* 0 = negative, 1 = positive */
-	u8 hsync_pol;		/* 0 = negative, 1 = positive */
-	u8 ext_block_cnt;
-};
 
 struct dp_panel_info {
 	u32 h_active;
@@ -95,17 +38,21 @@
 };
 
 struct dp_panel {
-	struct dp_panel_dpcd dpcd;
-	struct dp_panel_edid edid;
+	/* dpcd raw data */
+	u8 dpcd[DP_RECEIVER_CAP_SIZE];
+	struct drm_dp_link dp_link;
+
+	struct sde_edid_ctrl *edid_ctrl;
 	struct dp_panel_info pinfo;
 
 	u32 vic;
 
+	int (*sde_edid_register)(struct dp_panel *dp_panel);
+	void (*sde_edid_deregister)(struct dp_panel *dp_panel);
 	int (*init_info)(struct dp_panel *dp_panel);
 	int (*timing_cfg)(struct dp_panel *dp_panel);
-	int (*read_edid)(struct dp_panel *dp_panel);
 	int (*read_dpcd)(struct dp_panel *dp_panel);
-	u8 (*get_link_rate)(struct dp_panel *dp_panel);
+	u32 (*get_link_rate)(struct dp_panel *dp_panel);
 };
 
 struct dp_panel *dp_panel_get(struct device *dev, struct dp_aux *aux,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index cf0cc56..23f23b0 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -1112,12 +1112,11 @@
 	struct sde_hw_stage_cfg *stage_cfg;
 	struct sde_rect plane_crtc_roi;
 
-	u32 flush_mask = 0;
+	u32 flush_mask, flush_sbuf, flush_tmp;
 	uint32_t lm_idx = LEFT_MIXER, stage_idx;
 	bool bg_alpha_enable[CRTC_DUAL_MIXERS] = {false};
 	int zpos_cnt[CRTC_DUAL_MIXERS][SDE_STAGE_MAX + 1] = { {0} };
 	int i;
-	bool sbuf_mode = false;
 	u32 prefill = 0;
 
 	if (!sde_crtc || !mixer) {
@@ -1129,6 +1128,10 @@
 	lm = mixer->hw_lm;
 	stage_cfg = &sde_crtc->stage_cfg;
 	cstate = to_sde_crtc_state(crtc->state);
+	flush_sbuf = 0x0;
+
+	cstate->sbuf_cfg.rot_op_mode = SDE_CTL_ROT_OP_MODE_OFFLINE;
+	cstate->sbuf_prefill_line = 0;
 
 	drm_atomic_crtc_for_each_plane(plane, crtc) {
 		state = plane->state;
@@ -1144,10 +1147,16 @@
 		fb = state->fb;
 
 		if (sde_plane_is_sbuf_mode(plane, &prefill))
-			sbuf_mode = true;
+			cstate->sbuf_cfg.rot_op_mode =
+					SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
+		if (prefill > cstate->sbuf_prefill_line)
+			cstate->sbuf_prefill_line = prefill;
 
-		sde_plane_get_ctl_flush(plane, ctl, &flush_mask);
+		sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_tmp);
 
+		/* persist rotator flush bit(s) for one more commit */
+		flush_mask |= cstate->sbuf_flush_mask | flush_tmp;
+		flush_sbuf |= flush_tmp;
 
 		SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
 				crtc->base.id,
@@ -1163,7 +1172,8 @@
 				state->src_x >> 16, state->src_y >> 16,
 				state->src_w >> 16, state->src_h >> 16,
 				state->crtc_x, state->crtc_y,
-				state->crtc_w, state->crtc_h);
+				state->crtc_w, state->crtc_h,
+				cstate->sbuf_cfg.rot_op_mode);
 
 		for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
 			struct sde_rect intersect;
@@ -1208,6 +1218,8 @@
 		}
 	}
 
+	cstate->sbuf_flush_mask = flush_sbuf;
+
 	if (lm && lm->ops.setup_dim_layer) {
 		cstate = to_sde_crtc_state(crtc->state);
 		for (i = 0; i < cstate->num_dim_layers; i++)
@@ -1215,20 +1227,8 @@
 					mixer, &cstate->dim_layer[i]);
 	}
 
-	if (ctl->ops.setup_sbuf_cfg) {
-		cstate = to_sde_crtc_state(crtc->state);
-		if (!sbuf_mode) {
-			cstate->sbuf_cfg.rot_op_mode =
-					SDE_CTL_ROT_OP_MODE_OFFLINE;
-			cstate->sbuf_prefill_line = 0;
-		} else {
-			cstate->sbuf_cfg.rot_op_mode =
-					SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
-			cstate->sbuf_prefill_line = prefill;
-		}
-
+	if (ctl->ops.setup_sbuf_cfg)
 		ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
-	}
 
 	_sde_crtc_program_lm_output_roi(crtc);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 4b3c814..2cf30a9 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -272,6 +272,7 @@
  * @new_perf: new performance state
  * @sbuf_cfg: stream buffer configuration
  * @sbuf_prefill_line: number of line for inline rotator prefetch
+ * @sbuf_flush_mask: flush mask for inline rotator
  */
 struct sde_crtc_state {
 	struct drm_crtc_state base;
@@ -298,7 +299,8 @@
 	struct sde_core_perf_params cur_perf;
 	struct sde_core_perf_params new_perf;
 	struct sde_ctl_sbuf_cfg sbuf_cfg;
-	u64 sbuf_prefill_line;
+	u32 sbuf_prefill_line;
+	u32 sbuf_flush_mask;
 
 	struct sde_crtc_respool rp;
 };
@@ -433,10 +435,14 @@
  */
 static inline u32 sde_crtc_get_inline_prefill(struct drm_crtc *crtc)
 {
+	struct sde_crtc_state *cstate;
+
 	if (!crtc || !crtc->state)
 		return 0;
 
-	return to_sde_crtc_state(crtc->state)->sbuf_prefill_line;
+	cstate = to_sde_crtc_state(crtc->state);
+	return cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE ?
+		cstate->sbuf_prefill_line : 0;
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 5cb84b4..488f5c0 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -222,7 +222,7 @@
  * @rot_fetch_lines: number of line to prefill, or 0 to disable
  */
 static void programmable_rot_fetch_config(struct sde_encoder_phys *phys_enc,
-		u64 rot_fetch_lines)
+		u32 rot_fetch_lines)
 {
 	struct sde_encoder_phys_vid *vid_enc =
 		to_sde_encoder_phys_vid(phys_enc);
@@ -232,9 +232,12 @@
 	u32 horiz_total = 0;
 	u32 vert_total = 0;
 	u32 rot_fetch_start_vsync_counter = 0;
+	u32 flush_mask = 0;
 	unsigned long lock_flags;
 
-	if (!phys_enc || !vid_enc->hw_intf ||
+	if (!phys_enc || !vid_enc->hw_intf || !phys_enc->hw_ctl ||
+			!phys_enc->hw_ctl->ops.get_bitmask_intf ||
+			!phys_enc->hw_ctl->ops.update_pending_flush ||
 			!vid_enc->hw_intf->ops.setup_rot_start)
 		return;
 
@@ -253,9 +256,14 @@
 	}
 
 	SDE_DEBUG_VIDENC(vid_enc,
-		"rot_fetch_lines %llu rot_fetch_start_vsync_counter %u\n",
+		"rot_fetch_lines %u rot_fetch_start_vsync_counter %u\n",
 		rot_fetch_lines, rot_fetch_start_vsync_counter);
 
+	phys_enc->hw_ctl->ops.get_bitmask_intf(
+			phys_enc->hw_ctl, &flush_mask, vid_enc->hw_intf->idx);
+	phys_enc->hw_ctl->ops.update_pending_flush(
+			phys_enc->hw_ctl, flush_mask);
+
 	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
 	vid_enc->hw_intf->ops.setup_rot_start(vid_enc->hw_intf, &f);
 	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 8941a54..d63fec1 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1368,33 +1368,31 @@
 static u32 sde_plane_rot_calc_prefill(struct drm_plane *plane)
 {
 	struct drm_plane_state *state;
-	struct drm_crtc_state *cstate;
 	struct sde_plane_state *pstate;
 	struct sde_plane_rot_state *rstate;
 	struct sde_kms *sde_kms;
 	u32 blocksize = 128;
 	u32 prefill_line = 0;
 
-	if (!plane || !plane->state || !plane->state->fb ||
-			!plane->state->crtc || !plane->state->crtc->state) {
+	if (!plane || !plane->state || !plane->state->fb) {
 		SDE_ERROR("invalid parameters\n");
 		return 0;
 	}
 
 	sde_kms = _sde_plane_get_kms(plane);
 	state = plane->state;
-	cstate = state->crtc->state;
 	pstate = to_sde_plane_state(state);
 	rstate = &pstate->rot;
 
-	if (!rstate->rot_hw || !rstate->rot_hw->caps || !rstate->out_src_h ||
-			!sde_kms || !sde_kms->catalog) {
-		SDE_ERROR("invalid parameters\n");
+	if (!sde_kms || !sde_kms->catalog) {
+		SDE_ERROR("invalid kms\n");
 		return 0;
 	}
 
-	sde_format_get_block_size(rstate->out_fb_format, &blocksize,
-			&blocksize);
+	if (rstate->out_fb_format)
+		sde_format_get_block_size(rstate->out_fb_format,
+				&blocksize, &blocksize);
+
 	prefill_line = blocksize + sde_kms->catalog->sbuf_headroom;
 
 	SDE_DEBUG("plane%d prefill:%u\n", plane->base.id, prefill_line);
@@ -1416,7 +1414,7 @@
 	struct sde_plane_rot_state *rstate = pstate ? &pstate->rot : NULL;
 	bool sbuf_mode = rstate ? rstate->out_sbuf : false;
 
-	if (prefill && sbuf_mode)
+	if (prefill)
 		*prefill = sde_plane_rot_calc_prefill(plane);
 
 	return sbuf_mode;
@@ -2447,16 +2445,16 @@
  * sde_plane_get_ctl_flush - get control flush for the given plane
  * @plane: Pointer to drm plane structure
  * @ctl: Pointer to hardware control driver
- * @flush: Pointer to flush control word
+ * @flush_sspp: Pointer to sspp flush control word
+ * @flush_rot: Pointer to rotator flush control word
  */
 void sde_plane_get_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl,
-		u32 *flush)
+		u32 *flush_sspp, u32 *flush_rot)
 {
 	struct sde_plane_state *pstate;
 	struct sde_plane_rot_state *rstate;
-	u32 bitmask;
 
-	if (!plane || !flush) {
+	if (!plane || !flush_sspp) {
 		SDE_ERROR("invalid parameters\n");
 		return;
 	}
@@ -2464,13 +2462,15 @@
 	pstate = to_sde_plane_state(plane->state);
 	rstate = &pstate->rot;
 
-	bitmask = ctl->ops.get_bitmask_sspp(ctl, sde_plane_pipe(plane));
+	*flush_sspp = ctl->ops.get_bitmask_sspp(ctl, sde_plane_pipe(plane));
 
+	if (!flush_rot)
+		return;
+
+	*flush_rot = 0x0;
 	if (sde_plane_is_sbuf_mode(plane, NULL) && rstate->rot_hw &&
 			ctl->ops.get_bitmask_rot)
-		ctl->ops.get_bitmask_rot(ctl, &bitmask, rstate->rot_hw->idx);
-
-	*flush = bitmask;
+		ctl->ops.get_bitmask_rot(ctl, flush_rot, rstate->rot_hw->idx);
 }
 
 static int sde_plane_prepare_fb(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index 92c077e..f83a891 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -172,10 +172,11 @@
  * sde_plane_get_ctl_flush - get control flush mask
  * @plane:   Pointer to DRM plane object
  * @ctl: Pointer to control hardware
- * @flush: Pointer to updated flush mask
+ * @flush_sspp: Pointer to sspp flush control word
+ * @flush_rot: Pointer to rotator flush control word
  */
 void sde_plane_get_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl,
-		u32 *flush);
+		u32 *flush_sspp, u32 *flush_rot);
 
 /**
  * sde_plane_is_sbuf_mode - return status of stream buffer mode
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 6c7f6c4..d2cb1e8 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -60,6 +60,7 @@
 	void *data;
 	int err = -EBUSY;
 
+again:
 	spin_lock_irqsave(&chan->lock, flags);
 
 	if (!chan->msg_count || chan->active_req)
@@ -85,6 +86,16 @@
 exit:
 	spin_unlock_irqrestore(&chan->lock, flags);
 
+	/*
+	 * If the controller returns -EAGAIN, then it means, our spinlock
+	 * here is preventing the controller from receiving its interrupt,
+	 * that would help clear the controller channels that are currently
+	 * blocked waiting on the interrupt response.
+	 * Unlock and retry again.
+	 */
+	if (err == -EAGAIN)
+		goto again;
+
 	if (!err && (chan->txdone_method & TXDONE_BY_POLL))
 		/* kick start the timer immediately to avoid delays */
 		hrtimer_start(&chan->mbox->poll_hrt, ktime_set(0, 0),
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index b328a2a..1f649d6 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -28,7 +28,6 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
-#include <linux/workqueue.h>
 
 #include <asm-generic/io.h>
 
@@ -95,10 +94,10 @@
 	struct mbox_chan *chan;
 	struct tcs_mbox_msg *msg;
 	u32 m; /* m-th TCS */
-	struct tasklet_struct tasklet;
 	int err;
 	int idx;
 	bool in_use;
+	struct list_head list;
 };
 
 struct tcs_response_pool {
@@ -122,16 +121,18 @@
 
 /* One per MBOX controller */
 struct tcs_drv {
+	struct mbox_controller mbox;
 	const char *name;
-	void *base; /* start address of the RSC's registers */
-	void *reg_base; /* start address for DRV specific register */
+	void __iomem *base; /* start address of the RSC's registers */
+	void __iomem *reg_base; /* start address for DRV specific register */
 	int drv_id;
 	struct platform_device *pdev;
-	struct mbox_controller mbox;
 	struct tcs_mbox tcs[TCS_TYPE_NR];
 	int num_assigned;
 	int num_tcs;
-	struct workqueue_struct *wq;
+	struct tasklet_struct tasklet;
+	struct list_head response_pending;
+	spinlock_t drv_lock;
 	struct tcs_response_pool *resp_pool;
 	atomic_t tcs_in_use[MAX_POOL_SIZE];
 	/* Debug info */
@@ -141,8 +142,6 @@
 	atomic_t tcs_irq_count[MAX_POOL_SIZE];
 };
 
-static void tcs_notify_tx_done(unsigned long data);
-
 static int tcs_response_pool_init(struct tcs_drv *drv)
 {
 	struct tcs_response_pool *pool;
@@ -153,11 +152,10 @@
 		return -ENOMEM;
 
 	for (i = 0; i < MAX_POOL_SIZE; i++) {
-		tasklet_init(&pool->resp[i].tasklet, tcs_notify_tx_done,
-						(unsigned long) &pool->resp[i]);
 		pool->resp[i].drv = drv;
 		pool->resp[i].idx = i;
 		pool->resp[i].m = TCS_M_INIT;
+		INIT_LIST_HEAD(&pool->resp[i].list);
 	}
 
 	spin_lock_init(&pool->lock);
@@ -188,6 +186,9 @@
 	}
 	spin_unlock_irqrestore(&pool->lock, flags);
 
+	if (pos == MAX_POOL_SIZE)
+		pr_err("response pool is full\n");
+
 	return resp;
 }
 
@@ -240,11 +241,11 @@
 		return;
 
 	msg = resp->msg;
-	pr_info("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
+	pr_debug("Response object idx=%d:\n\tfor-tcs=%d\tin-use=%d\n",
 			resp->idx, resp->m, resp->in_use);
-	pr_info("Msg: state=%d\n", msg->state);
+	pr_debug("Msg: state=%d\n", msg->state);
 	for (i = 0; i < msg->num_payload; i++)
-		pr_info("addr=0x%x data=0x%x complete=0x%x\n",
+		pr_debug("addr=0x%x data=0x%x complete=0x%x\n",
 				msg->payload[i].addr,
 				msg->payload[i].data,
 				msg->payload[i].complete);
@@ -364,7 +365,15 @@
 
 static inline void send_tcs_response(struct tcs_response *resp)
 {
-	tasklet_schedule(&resp->tasklet);
+	struct tcs_drv *drv = resp->drv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&drv->drv_lock, flags);
+	INIT_LIST_HEAD(&resp->list);
+	list_add_tail(&resp->list, &drv->response_pending);
+	spin_unlock_irqrestore(&drv->drv_lock, flags);
+
+	tasklet_schedule(&drv->tasklet);
 }
 
 static inline void enable_tcs_irq(struct tcs_drv *drv, int m, bool enable)
@@ -455,12 +464,12 @@
 		/* Clear the TCS IRQ status */
 		write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, BIT(m));
 
+		/* Notify the client that this request is completed. */
+		atomic_set(&drv->tcs_in_use[m], 0);
+
 		/* Clean up response object and notify mbox in tasklet */
 		if (resp)
 			send_tcs_response(resp);
-
-		/* Notify the client that this request is completed. */
-		atomic_set(&drv->tcs_in_use[m], 0);
 	}
 
 	return IRQ_HANDLED;
@@ -475,19 +484,38 @@
 	mbox_chan_txdone(chan, err);
 }
 
-/**
- * tcs_notify_tx_done: TX Done for requests that do not trigger TCS
- */
-static void tcs_notify_tx_done(unsigned long data)
+static void respond_tx_done(struct tcs_response *resp)
 {
-	struct tcs_response *resp = (struct tcs_response *) data;
 	struct mbox_chan *chan = resp->chan;
 	struct tcs_mbox_msg *msg = resp->msg;
 	int err = resp->err;
 	int m = resp->m;
 
-	mbox_notify_tx_done(chan, msg, m, err);
 	free_response(resp);
+	mbox_notify_tx_done(chan, msg, m, err);
+}
+
+/**
+ * tcs_notify_tx_done: TX Done for requests that do not trigger TCS
+ */
+static void tcs_notify_tx_done(unsigned long data)
+{
+	struct tcs_drv *drv = (struct tcs_drv *)data;
+	struct tcs_response *resp;
+	unsigned long flags;
+
+	do {
+		spin_lock_irqsave(&drv->drv_lock, flags);
+		if (list_empty(&drv->response_pending)) {
+			spin_unlock_irqrestore(&drv->drv_lock, flags);
+			break;
+		}
+		resp = list_first_entry(&drv->response_pending,
+					struct tcs_response, list);
+		list_del(&resp->list);
+		spin_unlock_irqrestore(&drv->drv_lock, flags);
+		respond_tx_done(resp);
+	} while (1);
 }
 
 static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n,
@@ -673,8 +701,11 @@
 	if (IS_ERR(tcs))
 		return PTR_ERR(tcs);
 
-	if (trigger)
+	if (trigger) {
 		resp = setup_response(drv, msg, chan, TCS_M_INIT, 0);
+		if (IS_ERR_OR_NULL(resp))
+			return -EBUSY;
+	}
 
 	/* Identify the sequential slots that we can write to */
 	spin_lock_irqsave(&tcs->tcs_lock, flags);
@@ -686,28 +717,21 @@
 		return slot;
 	}
 
-	if (trigger) {
-		ret = check_for_req_inflight(drv, tcs, msg);
-		if (ret) {
-			spin_unlock_irqrestore(&tcs->tcs_lock, flags);
-			return ret;
-		}
-	}
-
-	/* Mark the slots as in-use, before we unlock */
-	if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
-		bitmap_set(tcs->slots, slot, msg->num_payload);
-
-	/* Copy the addresses of the resources over to the slots */
-	for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++)
-		tcs->cmd_addr[slot + i] = msg->payload[i].addr;
-
+	/* Figure out the TCS-m and CMD-n to write to */
 	offset = slot / tcs->ncpt;
 	m = offset + tcs->tcs_offset;
 	n = slot % tcs->ncpt;
 
-	/* Block, if we have an address from the msg in flight */
 	if (trigger) {
+		/* Block, if we have an address from the msg in flight */
+		ret = check_for_req_inflight(drv, tcs, msg);
+		if (ret) {
+			spin_unlock_irqrestore(&tcs->tcs_lock, flags);
+			if (resp)
+				free_response(resp);
+			return ret;
+		}
+
 		resp->m = m;
 		/* Mark the TCS as busy */
 		atomic_set(&drv->tcs_in_use[m], 1);
@@ -716,6 +740,14 @@
 		if (tcs->type != ACTIVE_TCS)
 			enable_tcs_irq(drv, m, true);
 		drv->tcs_last_sent_ts[m] = arch_counter_get_cntvct();
+	} else {
+		/* Mark the slots as in-use, before we unlock */
+		if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
+			bitmap_set(tcs->slots, slot, msg->num_payload);
+
+		/* Copy the addresses of the resources over to the slots */
+		for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++)
+			tcs->cmd_addr[slot + i] = msg->payload[i].addr;
 	}
 
 	/* Write to the TCS or AMC */
@@ -758,6 +790,32 @@
 	return 0;
 }
 
+static void print_tcs_regs(struct tcs_drv *drv, int m)
+{
+	int n;
+	struct tcs_mbox *tcs = get_tcs_from_index(drv, m);
+	void __iomem *base = drv->reg_base;
+	u32 enable, addr, data, msgid;
+
+	if (!tcs || tcs_is_free(drv, m))
+		return;
+
+	enable = read_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0);
+	if (!enable)
+		return;
+
+	pr_debug("TCS-%d contents:\n", m);
+	for (n = 0; n < tcs->ncpt; n++) {
+		if (!(enable & BIT(n)))
+			continue;
+		addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, n);
+		data = read_tcs_reg(base, TCS_DRV_CMD_DATA, m, n);
+		msgid = read_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n);
+		pr_debug("\tn=%d addr=0x%x data=0x%x hdr=0x%x\n",
+						n, addr, data, msgid);
+	}
+}
+
 static void dump_tcs_stats(struct tcs_drv *drv)
 {
 	int i;
@@ -766,12 +824,13 @@
 	for (i = 0; i < drv->num_tcs; i++) {
 		if (!atomic_read(&drv->tcs_in_use[i]))
 			continue;
-		pr_info("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
+		pr_debug("Time: %llu: TCS-%d:\n\tReq Sent:%d Last Sent:%llu\n\tResp Recv:%d Last Recvd:%llu\n",
 				curr, i,
 				atomic_read(&drv->tcs_send_count[i]),
 				drv->tcs_last_sent_ts[i],
 				atomic_read(&drv->tcs_irq_count[i]),
 				drv->tcs_last_recv_ts[i]);
+		print_tcs_regs(drv, i);
 		print_response(drv, i);
 	}
 }
@@ -840,7 +899,7 @@
 		if (ret != -EBUSY)
 			break;
 		udelay(100);
-	} while (++count < 10);
+	} while (++count < 100);
 
 tx_fail:
 	/* If there was an error in the request, schedule a response */
@@ -849,7 +908,8 @@
 				drv, msg, chan, TCS_M_INIT, ret);
 
 		dev_err(dev, "Error sending RPMH message %d\n", ret);
-		send_tcs_response(resp);
+		if (resp)
+			send_tcs_response(resp);
 		ret = 0;
 	}
 
@@ -857,6 +917,7 @@
 	if (ret == -EBUSY) {
 		dev_err(dev, "TCS Busy, retrying RPMH message send\n");
 		dump_tcs_stats(drv);
+		ret = -EAGAIN;
 	}
 
 	return ret;
@@ -967,6 +1028,7 @@
 	}
 
 	chan = &mbox->chans[drv->num_assigned++];
+	chan->con_priv = drv;
 
 	return chan;
 }
@@ -1108,6 +1170,9 @@
 	drv->mbox.is_idle = tcs_drv_is_idle;
 	drv->num_tcs = st;
 	drv->pdev = pdev;
+	INIT_LIST_HEAD(&drv->response_pending);
+	spin_lock_init(&drv->drv_lock);
+	tasklet_init(&drv->tasklet, tcs_notify_tx_done, (unsigned long)drv);
 
 	drv->name = of_get_property(pdev->dev.of_node, "label", NULL);
 	if (!drv->name)
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
index fdebdc7..b774625 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c
@@ -51,21 +51,23 @@
 static struct cam_cpas_intf *g_cpas_intf;
 
 int cam_cpas_get_hw_info(uint32_t *camera_family,
-	struct cam_hw_version *camera_version)
+	struct cam_hw_version *camera_version,
+	struct cam_hw_version *cpas_version)
 {
 	if (!CAM_CPAS_INTF_INITIALIZED()) {
 		pr_err("cpas intf not initialized\n");
 		return -ENODEV;
 	}
 
-	if (!camera_family || !camera_version) {
-		pr_err("invalid input %pK %pK\n", camera_family,
-			camera_version);
+	if (!camera_family || !camera_version || !cpas_version) {
+		pr_err("invalid input %pK %pK %pK\n", camera_family,
+			camera_version, cpas_version);
 		return -EINVAL;
 	}
 
 	*camera_family = g_cpas_intf->hw_caps.camera_family;
 	*camera_version = g_cpas_intf->hw_caps.camera_version;
+	*cpas_version = g_cpas_intf->hw_caps.cpas_version;
 
 	return 0;
 }
@@ -344,7 +346,7 @@
 		}
 
 		rc = cam_cpas_get_hw_info(&query.camera_family,
-			&query.camera_version);
+			&query.camera_version, &query.cpas_version);
 		if (rc)
 			break;
 
@@ -428,6 +430,7 @@
 static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd,
 	unsigned int cmd, unsigned long arg)
 {
+	struct cam_control cmd_data;
 	int32_t rc;
 	struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd);
 
@@ -436,9 +439,16 @@
 		return -ENODEV;
 	}
 
+	if (copy_from_user(&cmd_data, (void __user *)arg,
+		sizeof(cmd_data))) {
+		pr_err("Failed to copy from user_ptr=%pK size=%zu\n",
+			(void __user *)arg, sizeof(cmd_data));
+		return -EFAULT;
+	}
+
 	switch (cmd) {
 	case VIDIOC_CAM_CONTROL:
-		rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg);
+		rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data);
 		break;
 	default:
 		pr_err("Invalid command %d for CPAS!\n", cmd);
@@ -446,6 +456,15 @@
 		break;
 	}
 
+	if (!rc) {
+		if (copy_to_user((void __user *)arg, &cmd_data,
+			sizeof(cmd_data))) {
+			pr_err("Failed to copy to user_ptr=%pK size=%zu\n",
+				(void __user *)arg, sizeof(cmd_data));
+			rc = -EFAULT;
+		}
+	}
+
 	return rc;
 }
 #endif
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop100.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop100.h
index 12c8e66..20ed1b6 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop100.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop100.h
@@ -279,17 +279,16 @@
 			.value = 3,
 		},
 		.danger_lut = {
-			.enable = false,
+			.enable = true,
 			.access_type = CAM_REG_TYPE_READ_WRITE,
-			.masked_value = 0,
 			.offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */
-			.value = 0x0,
+			.value = 0xFFFFFF00,
 		},
 		.safe_lut = {
-			.enable = false,
+			.enable = true,
 			.access_type = CAM_REG_TYPE_READ_WRITE,
 			.offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */
-			.value = 0x0,
+			.value = 0x3,
 		},
 		.ubwc_ctl = {
 			.enable = true,
@@ -328,18 +327,16 @@
 			.value = 3,
 		},
 		.danger_lut = {
-			.enable = false,
+			.enable = true,
 			.access_type = CAM_REG_TYPE_READ_WRITE,
-			.masked_value = 0,
 			.offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */
-			.value = 0x0,
+			.value = 0xFFFFFF00,
 		},
 		.safe_lut = {
-			.enable = false,
+			.enable = true,
 			.access_type = CAM_REG_TYPE_READ_WRITE,
-			.masked_value = 0,
 			.offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */
-			.value = 0x0,
+			.value = 0x3,
 		},
 		.ubwc_ctl = {
 			.enable = true,
diff --git a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
index f6b0729..27b8504 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/include/cam_cpas_api.h
@@ -312,13 +312,15 @@
  * @camera_family  : Camera family type. One of
  *                   CAM_FAMILY_CAMERA_SS
  *                   CAM_FAMILY_CPAS_SS
- * @camera_version : Camera version
+ * @camera_version : Camera platform version
+ * @cpas_version   : Camera cpas version
  *
  * @return 0 on success.
  *
  */
 int cam_cpas_get_hw_info(
 	uint32_t                 *camera_family,
-	struct cam_hw_version    *camera_version);
+	struct cam_hw_version    *camera_version,
+	struct cam_hw_version    *cpas_version);
 
 #endif /* _CAM_CPAS_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index c837232..4888e5b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -531,7 +531,8 @@
 	rc = camera_io_dev_read(
 		&(s_ctrl->io_master_info),
 		slave_info->sensor_id_reg_addr,
-		&chipid, CAMERA_SENSOR_I2C_TYPE_WORD);
+		&chipid, CAMERA_SENSOR_I2C_TYPE_WORD,
+		CAMERA_SENSOR_I2C_TYPE_WORD);
 
 	CDBG("%s:%d read id: 0x%x expected id 0x%x:\n",
 			__func__, __LINE__, chipid, slave_info->sensor_id);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index f889abc..13e115a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -38,6 +38,7 @@
 
 int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
 	uint32_t addr, uint32_t *data,
+	enum camera_sensor_i2c_type addr_type,
 	enum camera_sensor_i2c_type data_type)
 {
 	if (!io_master_info) {
@@ -47,7 +48,7 @@
 
 	if (io_master_info->master_type == CCI_MASTER) {
 		return cam_cci_i2c_read(io_master_info->cci_client,
-			addr, data, data_type, data_type);
+			addr, data, addr_type, data_type);
 	} else {
 		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
 			__LINE__, io_master_info->master_type);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
index 757ac17..27bbe6e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
@@ -38,12 +38,14 @@
  * @io_master_info: I2C/SPI master information
  * @addr: I2C address
  * @data: I2C data
+ * @addr_type: I2C addr type
  * @data_type: I2C data type
  *
  * This API abstracts read functionality based on master type
  */
 int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
 	uint32_t addr, uint32_t *data,
+	enum camera_sensor_i2c_type addr_type,
 	enum camera_sensor_i2c_type data_type);
 
 /**
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 901632a..96f40e1 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -82,7 +82,7 @@
 		sync_cb->sync_obj = sync_obj;
 		INIT_WORK(&sync_cb->cb_dispatch_work,
 			cam_sync_util_cb_dispatch);
-
+		list_add_tail(&sync_cb->list, &row->callback_list);
 		sync_cb->status = row->state;
 		queue_work(sync_dev->work_queue,
 			&sync_cb->cb_dispatch_work);
diff --git a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
index 1e42f75..0ffea5b 100644
--- a/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/icp/fw_inc/hfi_intf.h
@@ -44,6 +44,7 @@
 	struct hfi_mem msg_q;
 	struct hfi_mem dbg_q;
 	struct hfi_mem sec_heap;
+	struct hfi_mem shmem;
 	void __iomem *icp_base;
 };
 
diff --git a/drivers/media/platform/msm/camera/icp/hfi.c b/drivers/media/platform/msm/camera/icp/hfi.c
index 4315865..15e0315 100644
--- a/drivers/media/platform/msm/camera/icp/hfi.c
+++ b/drivers/media/platform/msm/camera/icp/hfi.c
@@ -19,6 +19,8 @@
 #include <asm/errno.h>
 #include <linux/timer.h>
 #include <media/cam_icp.h>
+#include <linux/iopoll.h>
+
 #include "cam_io_util.h"
 #include "hfi_reg.h"
 #include "hfi_sys_defs.h"
@@ -336,7 +338,7 @@
 		icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	} else {
 		cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN |
-			ICP_FLAG_CSR_WAKE_UP_EN,
+			ICP_FLAG_CSR_WAKE_UP_EN | ICP_CSR_EN_CLKGATE_WFI,
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	}
 
@@ -460,8 +462,10 @@
 	}
 
 	cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
-	cam_io_w((uint32_t)0x7400000, icp_base + HFI_REG_SHARED_MEM_PTR);
-	cam_io_w((uint32_t)0x6400000, icp_base + HFI_REG_SHARED_MEM_SIZE);
+	cam_io_w((uint32_t)hfi_mem->shmem.iova,
+		icp_base + HFI_REG_SHARED_MEM_PTR);
+	cam_io_w((uint32_t)hfi_mem->shmem.len,
+		icp_base + HFI_REG_SHARED_MEM_SIZE);
 	cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
 		icp_base + HFI_REG_UNCACHED_HEAP_PTR);
 	cam_io_w((uint32_t)hfi_mem->sec_heap.len,
@@ -472,25 +476,17 @@
 	hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
 	pr_debug("hw version : %u[%x]\n", hw_version, hw_version);
 
-	do {
-		msleep(500);
-		status = cam_io_r(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
-	} while (status != ICP_INIT_RESP_SUCCESS);
-
-	if (status == ICP_INIT_RESP_SUCCESS) {
-		g_hfi->hfi_state = FW_RESP_DONE;
-		rc = 0;
-	} else {
-		rc = -ENODEV;
-		pr_err("FW initialization failed");
+	rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
+		status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
+	if (rc) {
+		pr_err("timed out , status = %u\n", status);
 		goto regions_fail;
 	}
 
 	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
 	g_hfi->hfi_state = FW_START_SENT;
 
-	pr_debug("fw version : %u[%x]\n", fw_version, fw_version);
-	pr_debug("hfi init is successful\n");
+	HFI_DBG("fw version : %u[%x]\n", fw_version, fw_version);
 	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
 
 	return rc;
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 140542b..43491a9 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -26,6 +26,8 @@
 #include <linux/debugfs.h>
 #include <media/cam_defs.h>
 #include <media/cam_icp.h>
+#include <linux/debugfs.h>
+
 #include "cam_sync_api.h"
 #include "cam_packet_util.h"
 #include "cam_hw.h"
@@ -55,6 +57,23 @@
 
 static struct cam_icp_hw_mgr icp_hw_mgr;
 
+static int cam_icp_hw_mgr_create_debugfs_entry(void)
+{
+	icp_hw_mgr.dentry = debugfs_create_dir("camera_icp", NULL);
+	if (!icp_hw_mgr.dentry)
+		return -ENOMEM;
+
+	if (!debugfs_create_bool("a5_debug",
+		0644,
+		icp_hw_mgr.dentry,
+		&icp_hw_mgr.a5_debug)) {
+		debugfs_remove_recursive(icp_hw_mgr.dentry);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
 static int cam_icp_stop_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
 {
 	struct cam_hw_intf *a5_dev_intf = NULL;
@@ -568,7 +587,12 @@
 	uint64_t kvaddr;
 	size_t len;
 
-	pr_err("Allocating FW for iommu handle: %x\n", icp_hw_mgr.iommu_hdl);
+	rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl,
+		CAM_MEM_MGR_REGION_SHARED,
+		&icp_hw_mgr.hfi_mem.shmem);
+	if (rc)
+		return -ENOMEM;
+
 	rc = cam_smmu_alloc_firmware(icp_hw_mgr.iommu_hdl,
 		&iova, &kvaddr, &len);
 	if (rc < 0) {
@@ -764,7 +788,7 @@
 			msecs_to_jiffies((timeout)));
 	if (!rem_jiffies) {
 		rc = -ETIMEDOUT;
-		pr_err("timeout/err in iconfig command: %d\n", rc);
+		pr_err("FW response timeout: %d\n", rc);
 	}
 
 	return rc;
@@ -870,6 +894,7 @@
 
 	cam_icp_free_hfi_mem();
 	hw_mgr->fw_download = false;
+	debugfs_remove_recursive(icp_hw_mgr.dentry);
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
 	return 0;
@@ -886,6 +911,8 @@
 	struct cam_icp_a5_set_irq_cb irq_cb;
 	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
 	struct hfi_mem_info hfi_mem;
+	unsigned long rem_jiffies;
+	int timeout = 5000;
 	int rc = 0;
 
 	if (!hw_mgr) {
@@ -1014,9 +1041,12 @@
 	hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova;
 	hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len;
 
+	hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start;
+	hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len;
+
 	rc = cam_hfi_init(0, &hfi_mem,
 		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
-		false);
+		hw_mgr->a5_debug);
 	if (rc < 0) {
 		pr_err("hfi_init is failed\n");
 		goto set_irq_failed;
@@ -1033,7 +1063,13 @@
 		NULL, 0);
 
 	ICP_DBG("Wait for INIT DONE Message\n");
-	wait_for_completion(&hw_mgr->a5_complete);
+	rem_jiffies = wait_for_completion_timeout(&icp_hw_mgr.a5_complete,
+			msecs_to_jiffies((timeout)));
+	if (!rem_jiffies) {
+		rc = -ETIMEDOUT;
+		pr_err("FW response timed out %d\n", rc);
+		goto set_irq_failed;
+	}
 
 	ICP_DBG("Done Waiting for INIT DONE Message\n");
 
@@ -1041,6 +1077,10 @@
 		a5_dev_intf->hw_priv,
 		CAM_ICP_A5_CMD_POWER_COLLAPSE,
 		NULL, 0);
+	if (rc) {
+		pr_err("icp power collapse failed\n");
+		goto set_irq_failed;
+	}
 
 	hw_mgr->fw_download = true;
 
@@ -1428,6 +1468,8 @@
 	int rc = 0;
 	struct hfi_cmd_work_data *task_data;
 	struct hfi_cmd_ipebps_async ioconfig_cmd;
+	unsigned long rem_jiffies;
+	int timeout = 5000;
 
 	ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
 	ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
@@ -1451,7 +1493,13 @@
 	task->process_cb = cam_icp_mgr_process_cmd;
 	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
 	ICP_DBG("fw_hdl = %x ctx_data = %pK\n", ctx_data->fw_handle, ctx_data);
-	wait_for_completion(&ctx_data->wait_complete);
+
+	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+			msecs_to_jiffies((timeout)));
+	if (!rem_jiffies) {
+		rc = -ETIMEDOUT;
+		pr_err("FW response timed out %d\n", rc);
+	}
 
 	return rc;
 }
@@ -1462,6 +1510,8 @@
 {
 	struct hfi_cmd_create_handle create_handle;
 	struct hfi_cmd_work_data *task_data;
+	unsigned long rem_jiffies;
+	int timeout = 5000;
 	int rc = 0;
 
 	create_handle.size = sizeof(struct hfi_cmd_create_handle);
@@ -1479,7 +1529,13 @@
 	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
 	task->process_cb = cam_icp_mgr_process_cmd;
 	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
-	wait_for_completion(&ctx_data->wait_complete);
+
+	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+			msecs_to_jiffies((timeout)));
+	if (!rem_jiffies) {
+		rc = -ETIMEDOUT;
+		pr_err("FW response timed out %d\n", rc);
+	}
 
 	return rc;
 }
@@ -1489,6 +1545,8 @@
 {
 	struct hfi_cmd_ping_pkt ping_pkt;
 	struct hfi_cmd_work_data *task_data;
+	unsigned long rem_jiffies;
+	int timeout = 5000;
 	int rc = 0;
 
 	ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt);
@@ -1505,7 +1563,14 @@
 	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
 	task->process_cb = cam_icp_mgr_process_cmd;
 	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
-	wait_for_completion(&ctx_data->wait_complete);
+
+	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+			msecs_to_jiffies((timeout)));
+	if (!rem_jiffies) {
+		rc = -ETIMEDOUT;
+		pr_err("FW response timed out %d\n", rc);
+	}
+
 
 	return rc;
 }
@@ -1929,6 +1994,9 @@
 	if (!icp_hw_mgr.msg_work_data)
 		goto msg_work_data_failed;
 
+	rc = cam_icp_hw_mgr_create_debugfs_entry();
+	if (rc)
+		goto msg_work_data_failed;
 
 	for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
 		icp_hw_mgr.msg_work->task.pool[i].payload =
@@ -1940,7 +2008,6 @@
 
 	init_completion(&icp_hw_mgr.a5_complete);
 
-	pr_err("Exit\n");
 	return rc;
 
 msg_work_data_failed:
diff --git a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index e5ffa7a..32d796a 100644
--- a/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -23,6 +23,8 @@
 #include "hfi_session_defs.h"
 #include "cam_req_mgr_workq.h"
 #include "cam_mem_mgr.h"
+#include "cam_smmu_api.h"
+
 
 #define CAM_ICP_ROLE_PARENT     1
 #define CAM_ICP_ROLE_CHILD      2
@@ -56,6 +58,7 @@
 	struct cam_mem_mgr_memory_desc dbg_q;
 	struct cam_mem_mgr_memory_desc sec_heap;
 	struct cam_mem_mgr_memory_desc fw_buf;
+	struct cam_smmu_region_info shmem;
 };
 
 /**
@@ -176,6 +179,8 @@
 	struct hfi_cmd_work_data *cmd_work_data;
 	struct hfi_msg_work_data *msg_work_data;
 	uint32_t ctxt_cnt;
+	struct dentry *dentry;
+	bool a5_debug;
 };
 
 #endif /* CAM_ICP_HW_MGR_H */
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 88250e1..8d54e20 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1369,13 +1369,13 @@
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
-	case HAL_CONFIG_VPE_OPERATIONS:
+	case HAL_PARAM_VPE_ROTATION:
 	{
-		struct hfi_operations_type *hfi;
-		struct hal_operations *prop =
-			(struct hal_operations *) pdata;
-		pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VPE_OPERATIONS;
-		hfi = (struct hfi_operations_type *) &pkt->rg_property_data[1];
+		struct hfi_vpe_rotation_type *hfi;
+		struct hal_vpe_rotation *prop =
+			(struct hal_vpe_rotation *) pdata;
+		pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VPE_ROTATION;
+		hfi = (struct hfi_vpe_rotation_type *)&pkt->rg_property_data[1];
 		switch (prop->rotate) {
 		case HAL_ROTATE_NONE:
 			hfi->rotation = HFI_ROTATE_NONE;
@@ -1411,7 +1411,7 @@
 			rc = -EINVAL;
 			break;
 		}
-		pkt->size += sizeof(u32) + sizeof(struct hfi_operations_type);
+		pkt->size += sizeof(u32) + sizeof(struct hfi_vpe_rotation_type);
 		break;
 	}
 	case HAL_PARAM_VENC_INTRA_REFRESH:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 89e8356..f678f56 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -110,6 +110,8 @@
 	struct hfi_profile_level *profile_level;
 	struct hfi_bit_depth *pixel_depth;
 	struct hfi_pic_struct *pic_struct;
+	struct hfi_buffer_requirements *buf_req;
+	struct hfi_index_extradata_input_crop_payload *crop_info;
 	u32 entropy_mode = 0;
 	u8 *data_ptr;
 	int prop_id;
@@ -231,6 +233,41 @@
 				data_ptr +=
 					sizeof(u32);
 				break;
+			case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
+				data_ptr = data_ptr + sizeof(u32);
+				buf_req =
+					(struct hfi_buffer_requirements *)
+						data_ptr;
+				event_notify.capture_buf_count =
+					buf_req->buffer_count_min;
+				dprintk(VIDC_DBG,
+					"Capture Count : 0x%x\n",
+						event_notify.capture_buf_count);
+				data_ptr +=
+					sizeof(struct hfi_buffer_requirements);
+				break;
+			case HFI_INDEX_EXTRADATA_INPUT_CROP:
+				data_ptr = data_ptr + sizeof(u32);
+				crop_info = (struct
+				hfi_index_extradata_input_crop_payload *)
+						data_ptr;
+				event_notify.crop_data.left = crop_info->left;
+				event_notify.crop_data.top = crop_info->top;
+				event_notify.crop_data.width = crop_info->width;
+				event_notify.crop_data.height =
+					crop_info->height;
+				dprintk(VIDC_DBG,
+					"CROP info : Left = %d Top = %d\n",
+						crop_info->left,
+						crop_info->top);
+				dprintk(VIDC_DBG,
+					"CROP info : Width = %d Height = %d\n",
+						crop_info->width,
+						crop_info->height);
+				data_ptr +=
+					sizeof(struct
+					hfi_index_extradata_input_crop_payload);
+				break;
 			default:
 				dprintk(VIDC_ERR,
 					"%s cmd: %#x not supported\n",
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 074ea4fa..b116622 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -74,6 +74,14 @@
 			goto mem_map_failed;
 		}
 
+		/* Check if the dmabuf size matches expected size */
+		if (buf->size < *buffer_size) {
+			rc = -EINVAL;
+			dprintk(VIDC_ERR,
+				"Size mismatch! Dmabuf size: %zu Expected Size: %lu",
+				buf->size, *buffer_size);
+			goto mem_buf_size_mismatch;
+		}
 		/* Prepare a dma buf for dma on the given device */
 		attach = dma_buf_attach(buf, cb->dev);
 		if (IS_ERR_OR_NULL(attach)) {
@@ -151,6 +159,7 @@
 	dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
 mem_map_table_failed:
 	dma_buf_detach(buf, attach);
+mem_buf_size_mismatch:
 mem_buf_attach_failed:
 	dma_buf_put(buf);
 mem_map_failed:
@@ -201,12 +210,12 @@
 	}
 }
 
-static int ion_user_to_kernel(struct smem_client *client, int fd, u32 offset,
+static int ion_user_to_kernel(struct smem_client *client, int fd, u32 size,
 		struct msm_smem *mem, enum hal_buffer buffer_type)
 {
 	struct ion_handle *hndl = NULL;
 	ion_phys_addr_t iova = 0;
-	unsigned long buffer_size = 0;
+	unsigned long buffer_size = size;
 	int rc = 0;
 	unsigned long align = SZ_4K;
 	unsigned long ion_flags = 0;
@@ -217,10 +226,11 @@
 	dprintk(VIDC_DBG, "%s ion handle: %pK\n", __func__, hndl);
 	if (IS_ERR_OR_NULL(hndl)) {
 		dprintk(VIDC_ERR, "Failed to get handle: %pK, %d, %d, %pK\n",
-				client, fd, offset, hndl);
+				client, fd, size, hndl);
 		rc = -ENOMEM;
 		goto fail_import_fd;
 	}
+
 	mem->kvaddr = NULL;
 	rc = ion_handle_get_flags(client->clnt, hndl, &ion_flags);
 	if (rc) {
@@ -441,7 +451,7 @@
 	ion_client_destroy(client->clnt);
 }
 
-struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 size,
 		enum hal_buffer buffer_type)
 {
 	struct smem_client *client = clt;
@@ -459,7 +469,7 @@
 	}
 	switch (client->mem_type) {
 	case SMEM_ION:
-		rc = ion_user_to_kernel(clt, fd, offset, mem, buffer_type);
+		rc = ion_user_to_kernel(clt, fd, size, mem, buffer_type);
 		break;
 	default:
 		dprintk(VIDC_ERR, "Mem type not supported\n");
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 7802d31..5c34f28 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -225,6 +225,14 @@
 	return 0;
 }
 
+static int msm_v4l2_g_crop(struct file *file, void *fh,
+			struct v4l2_crop *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_g_crop(vidc_inst, a);
+}
+
 static int msm_v4l2_enum_framesizes(struct file *file, void *fh,
 				struct v4l2_frmsizeenum *fsize)
 {
@@ -265,6 +273,7 @@
 	.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
 	.vidioc_s_parm = msm_v4l2_s_parm,
 	.vidioc_g_parm = msm_v4l2_g_parm,
+	.vidioc_g_crop = msm_v4l2_g_crop,
 	.vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
 };
 
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index aa5f18d..d44684e 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1117,7 +1117,7 @@
 	struct hal_h264_entropy_control h264_entropy_control;
 	struct hal_intra_period intra_period;
 	struct hal_idr_period idr_period;
-	struct hal_operations operations;
+	struct hal_vpe_rotation vpe_rotation;
 	struct hal_intra_refresh intra_refresh;
 	struct hal_multi_slice_control multi_slice_control;
 	struct hal_h264_db_control h264_db_control;
@@ -1345,19 +1345,12 @@
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
 	{
-		if (!(inst->capability.pixelprocess_capabilities &
-			HAL_VIDEO_ENCODER_ROTATION_CAPABILITY)) {
-			dprintk(VIDC_ERR, "Rotation not supported: %#x\n",
-				ctrl->id);
-			rc = -ENOTSUPP;
-			break;
-		}
-		property_id = HAL_CONFIG_VPE_OPERATIONS;
-		operations.rotate = msm_comm_v4l2_to_hal(
+		property_id = HAL_PARAM_VPE_ROTATION;
+		vpe_rotation.rotate = msm_comm_v4l2_to_hal(
 				V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
 				ctrl->val);
-		operations.flip = HAL_FLIP_NONE;
-		pdata = &operations;
+		vpe_rotation.flip = HAL_FLIP_NONE;
+		pdata = &vpe_rotation;
 		break;
 	}
 	case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 6253632..2e952a3 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -265,6 +265,29 @@
 }
 EXPORT_SYMBOL(msm_vidc_s_ctrl);
 
+int msm_vidc_g_crop(void *instance, struct v4l2_crop *crop)
+{
+	struct msm_vidc_inst *inst = instance;
+
+	if (!inst || !crop)
+		return -EINVAL;
+
+	if (inst->session_type == MSM_VIDC_ENCODER) {
+		dprintk(VIDC_ERR,
+			"Session = %pK : Encoder Crop is not implemented yet\n",
+				inst);
+		return -EPERM;
+	}
+
+	crop->c.left = inst->prop.crop_info.left;
+	crop->c.top = inst->prop.crop_info.top;
+	crop->c.width = inst->prop.crop_info.width;
+	crop->c.height = inst->prop.crop_info.height;
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_vidc_g_crop);
+
 int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
 {
 	struct msm_vidc_inst *inst = instance;
@@ -534,7 +557,7 @@
 
 	handle = msm_comm_smem_user_to_kernel(inst,
 				p->reserved[0],
-				p->reserved[1],
+				p->length,
 				buffer_type);
 	if (!handle) {
 		dprintk(VIDC_ERR,
@@ -605,8 +628,10 @@
 		goto exit;
 	}
 
-	dprintk(VIDC_DBG, "[MAP] Create binfo = %pK fd = %d type = %d\n",
-			binfo, b->m.planes[0].reserved[0], b->type);
+	dprintk(VIDC_DBG,
+		"[MAP] Create binfo = %pK fd = %d size = %d type = %d\n",
+		binfo, b->m.planes[0].reserved[0],
+		b->m.planes[0].length, b->type);
 
 	for (i = 0; i < b->length; ++i) {
 		rc = 0;
@@ -878,6 +903,7 @@
 	struct buffer_info *bi, *dummy;
 	int i, rc = 0;
 	int found_buf = 0;
+	struct vb2_buf_entry *temp, *next;
 
 	if (!inst)
 		return -EINVAL;
@@ -936,6 +962,16 @@
 	default:
 		break;
 	}
+
+	mutex_lock(&inst->pendingq.lock);
+	list_for_each_entry_safe(temp, next, &inst->pendingq.list, list) {
+		if (temp->vb->type == buffer_type) {
+			list_del(&temp->list);
+			kfree(temp);
+		}
+	}
+	mutex_unlock(&inst->pendingq.lock);
+
 	return rc;
 }
 EXPORT_SYMBOL(msm_vidc_release_buffer);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index b1a8e8b..fe61e6f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1166,12 +1166,12 @@
 	if (!rc) {
 		dprintk(VIDC_ERR, "Wait interrupted or timed out: %d\n",
 				SESSION_MSG_INDEX(cmd));
-		msm_comm_kill_session(inst);
 		call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
 		dprintk(VIDC_ERR,
 			"sess resp timeout can potentially crash the system\n");
 		msm_comm_print_debug_info(inst);
 		msm_vidc_handle_hw_error(inst->core);
+		msm_comm_kill_session(inst);
 		rc = -EIO;
 	} else {
 		rc = 0;
@@ -1554,6 +1554,14 @@
 	inst->entropy_mode = event_notify->entropy_mode;
 	inst->profile = event_notify->profile;
 	inst->level = event_notify->level;
+	inst->prop.crop_info.left =
+		event_notify->crop_data.left;
+	inst->prop.crop_info.top =
+		event_notify->crop_data.top;
+	inst->prop.crop_info.height =
+		event_notify->crop_data.height;
+	inst->prop.crop_info.width =
+		event_notify->crop_data.width;
 
 	ptr = (u32 *)seq_changed_event.u.data;
 	ptr[0] = event_notify->height;
@@ -1561,6 +1569,10 @@
 	ptr[2] = event_notify->bit_depth;
 	ptr[3] = event_notify->pic_struct;
 	ptr[4] = event_notify->colour_space;
+	ptr[5] = event_notify->crop_data.top;
+	ptr[6] = event_notify->crop_data.left;
+	ptr[7] = event_notify->crop_data.height;
+	ptr[8] = event_notify->crop_data.width;
 
 	dprintk(VIDC_DBG,
 		"Event payload: height = %d width = %d\n",
@@ -1571,6 +1583,13 @@
 		event_notify->bit_depth, event_notify->pic_struct,
 			event_notify->colour_space);
 
+	dprintk(VIDC_DBG,
+		"Event payload: CROP top = %d left = %d Height = %d Width = %d\n",
+			event_notify->crop_data.top,
+			event_notify->crop_data.left,
+			event_notify->crop_data.height,
+			event_notify->crop_data.width);
+
 	mutex_lock(&inst->lock);
 	inst->in_reconfig = true;
 	inst->reconfig_height = event_notify->height;
@@ -4245,14 +4264,13 @@
 			__func__, inst,
 			SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO));
 		inst->state = MSM_VIDC_CORE_INVALID;
-		msm_comm_kill_session(inst);
 		call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
 		dprintk(VIDC_ERR,
 			"SESS_PROP timeout can potentially crash the system\n");
-		if (inst->core->resources.debug_timeout)
-			msm_comm_print_debug_info(inst);
+		msm_comm_print_debug_info(inst);
 
 		msm_vidc_handle_hw_error(inst->core);
+		msm_comm_kill_session(inst);
 		rc = -ETIMEDOUT;
 		goto exit;
 	} else {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 8ffbf50..c197776 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -12,6 +12,7 @@
  */
 
 #define CREATE_TRACE_POINTS
+#define MAX_SSR_STRING_LEN 10
 #include "msm_vidc_debug.h"
 #include "vidc_hfi_api.h"
 
@@ -134,21 +135,36 @@
 
 static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
 		size_t count, loff_t *ppos) {
-	u32 ssr_trigger_val;
-	int rc;
+	unsigned long ssr_trigger_val = 0;
+	int rc = 0;
 	struct msm_vidc_core *core = filp->private_data;
+	size_t size = MAX_SSR_STRING_LEN;
+	char kbuf[MAX_SSR_STRING_LEN + 1] = {0};
 
 	if (!buf)
 		return -EINVAL;
 
-	rc = kstrtou32(buf, 0, &ssr_trigger_val);
-	if (rc < 0) {
+	if (!count)
+		goto exit;
+
+	if (count < size)
+		size = count;
+
+	if (copy_from_user(kbuf, buf, size)) {
+		dprintk(VIDC_WARN, "%s User memory fault\n", __func__);
+		rc = -EFAULT;
+		goto exit;
+	}
+
+	rc = kstrtoul(kbuf, 0, &ssr_trigger_val);
+	if (rc) {
 		dprintk(VIDC_WARN, "returning error err %d\n", rc);
 		rc = -EINVAL;
 	} else {
 		msm_vidc_trigger_ssr(core, ssr_trigger_val);
 		rc = count;
 	}
+exit:
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 8fd895d..f4c851a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -186,7 +186,7 @@
 {
 	bool enable_fatal;
 
-	enable_fatal = core->resources.debug_timeout;
+	enable_fatal = msm_vidc_debug_timeout;
 
 	/* Video driver can decide FATAL handling of HW errors
 	 * based on multiple factors. This condition check will
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 37bccbd..5edd3d5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -175,9 +175,17 @@
 	struct video_device vdev;
 };
 
+struct session_crop {
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+};
+
 struct session_prop {
 	u32 width[MAX_PORT_NUM];
 	u32 height[MAX_PORT_NUM];
+	struct session_crop crop_info;
 	u32 fps;
 	u32 bitrate;
 };
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index d259072..19ca561 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -969,7 +969,7 @@
 	res->debug_timeout = of_property_read_bool(pdev->dev.of_node,
 			"qcom,debug-timeout");
 
-	res->debug_timeout |= msm_vidc_debug_timeout;
+	msm_vidc_debug_timeout |= res->debug_timeout;
 
 	of_property_read_u32(pdev->dev.of_node,
 			"qcom,pm-qos-latency-us", &res->pm_qos_latency_us);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 8968764..6139e46 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1049,8 +1049,12 @@
 	}
 
 	dprintk(VIDC_DBG, "Suspending Venus\n");
-	rc = flush_delayed_work(&venus_hfi_pm_work);
+	flush_delayed_work(&venus_hfi_pm_work);
 
+	mutex_lock(&device->lock);
+	if (device->power_enabled)
+		rc = -EBUSY;
+	mutex_unlock(&device->lock);
 	return rc;
 }
 
@@ -4168,7 +4172,7 @@
 	struct venus_hfi_device *device = dev;
 	u32 smem_block_size = 0;
 	u8 *smem_table_ptr;
-	char version[VENUS_VERSION_LENGTH];
+	char version[VENUS_VERSION_LENGTH] = "";
 	const u32 smem_image_index_venus = 14 * 128;
 
 	if (!device || !fw_info) {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index a2f076b..86e4f42 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -154,7 +154,7 @@
 	HAL_PARAM_VENC_SESSION_QP_RANGE,
 	HAL_CONFIG_VENC_INTRA_PERIOD,
 	HAL_CONFIG_VENC_IDR_PERIOD,
-	HAL_CONFIG_VPE_OPERATIONS,
+	HAL_PARAM_VPE_ROTATION,
 	HAL_PARAM_VENC_INTRA_REFRESH,
 	HAL_PARAM_VENC_MULTI_SLICE_CONTROL,
 	HAL_SYS_DEBUG_CONFIG,
@@ -634,7 +634,7 @@
 	HAL_UNUSED_FLIP = 0x10000000,
 };
 
-struct hal_operations {
+struct hal_vpe_rotation {
 	enum hal_rotate rotate;
 	enum hal_flip flip;
 };
@@ -1019,7 +1019,7 @@
 	struct hal_quantization_range quantization_range;
 	struct hal_intra_period intra_period;
 	struct hal_idr_period idr_period;
-	struct hal_operations operations;
+	struct hal_vpe_rotation vpe_rotation;
 	struct hal_intra_refresh intra_refresh;
 	struct hal_multi_slice_control multi_slice_control;
 	struct hal_debug_config debug_config;
@@ -1212,6 +1212,16 @@
 	} data;
 };
 
+struct hal_index_extradata_input_crop_payload {
+	u32 size;
+	u32 version;
+	u32 port_index;
+	u32 left;
+	u32 top;
+	u32 width;
+	u32 height;
+};
+
 struct msm_vidc_cb_event {
 	u32 device_id;
 	void *session_id;
@@ -1227,6 +1237,8 @@
 	u32 profile;
 	u32 level;
 	u32 entropy_mode;
+	u32 capture_buf_count;
+	struct hal_index_extradata_input_crop_payload crop_data;
 };
 
 struct msm_vidc_cb_data_done {
@@ -1314,16 +1326,6 @@
 	int num_sessions;
 };
 
-struct hal_index_extradata_input_crop_payload {
-	u32 size;
-	u32 version;
-	u32 port_index;
-	u32 left;
-	u32 top;
-	u32 width;
-	u32 height;
-};
-
 struct hal_cmd_sys_get_property_packet {
 	u32 size;
 	u32 packet_type;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 2d4a573..616fc09 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -327,8 +327,6 @@
 	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004)
 #define  HFI_PROPERTY_CONFIG_VENC_SLICE_SIZE                \
 	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005)
-#define HFI_PROPERTY_PARAM_VPE_COMMON_START				\
-	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
 #define  HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER	\
 	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x008)
 #define  HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME			\
@@ -344,13 +342,15 @@
 #define HFI_PROPERTY_CONFIG_VENC_SESSION_QP			\
 	(HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x012)
 
+#define HFI_PROPERTY_PARAM_VPE_COMMON_START				\
+	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
+#define HFI_PROPERTY_PARAM_VPE_ROTATION				\
+	(HFI_PROPERTY_PARAM_VPE_COMMON_START + 0x001)
 
 #define HFI_PROPERTY_CONFIG_VPE_COMMON_START				\
 	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
 #define  HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE		\
 	(HFI_PROPERTY_CONFIG_COMMON_START + 0x010)
-#define HFI_PROPERTY_CONFIG_VPE_OPERATIONS				\
-	(HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x002)
 
 struct hfi_pic_struct {
 	u32 progressive_only;
@@ -472,7 +472,7 @@
 	u32 idr_period;
 };
 
-struct hfi_operations_type {
+struct hfi_vpe_rotation_type {
 	u32 rotation;
 	u32 flip;
 };
@@ -716,12 +716,7 @@
 
 #define HFI_FLIP_NONE					(HFI_COMMON_BASE + 0x1)
 #define HFI_FLIP_HORIZONTAL				(HFI_COMMON_BASE + 0x2)
-#define HFI_FLIP_VERTICAL				(HFI_COMMON_BASE + 0x3)
-
-struct hfi_operations {
-	u32 rotate;
-	u32 flip;
-};
+#define HFI_FLIP_VERTICAL				(HFI_COMMON_BASE + 0x4)
 
 #define HFI_RESOURCE_SYSCACHE 0x00000002
 
diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c
index fbaf05e..e8ba149 100644
--- a/drivers/mfd/wcd934x-regmap.c
+++ b/drivers/mfd/wcd934x-regmap.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * 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
@@ -1926,6 +1926,19 @@
 	case WCD934X_ANA_MBHC_ELECT:
 	case WCD934X_ANA_MBHC_ZDET:
 	case WCD934X_ANA_MICB2:
+	case WCD934X_CODEC_RPM_CLK_MCLK_CFG:
+	case WCD934X_CLK_SYS_MCLK_PRG:
+	case WCD934X_CHIP_TIER_CTRL_EFUSE_CTL:
+	case WCD934X_ANA_BIAS:
+	case WCD934X_ANA_BUCK_CTL:
+	case WCD934X_ANA_RCO:
+	case WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL:
+	case WCD934X_CODEC_RPM_CLK_GATE:
+	case WCD934X_BIAS_VBG_FINE_ADJ:
+	case WCD934X_CODEC_CPR_SVS_CX_VDD:
+	case WCD934X_CODEC_CPR_SVS2_CX_VDD:
+	case WCD934X_CDC_TOP_TOP_CFG1:
+	case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
 		return true;
 	}
 
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 877c4d1..c1857c7 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1261,7 +1261,7 @@
 				atomic_read(&data->ioctl_count) <= 1)) {
 			pr_err("Interrupted from abort\n");
 			ret = -ERESTARTSYS;
-			break;
+			return ret;
 		}
 	}
 
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 0d0d56f..0c8ff86 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -338,10 +338,15 @@
 {
 	struct mmc_host *host = data;
 
-	if (host && host->ops && host->ops->force_err_irq) {
-		mmc_host_clk_hold(host);
+	if (host && host->card && host->ops &&
+			host->ops->force_err_irq) {
+		/*
+		 * To access the force error irq reg, we need to make
+		 * sure the host is powered up and host clock is ticking.
+		 */
+		mmc_get_card(host->card);
 		host->ops->force_err_irq(host, val);
-		mmc_host_clk_release(host);
+		mmc_put_card(host->card);
 	}
 
 	return 0;
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index 293371b..c5aaac5 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -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
@@ -125,7 +125,6 @@
 	IPA_USB_CONNECTED,
 	IPA_USB_STOPPED,
 	IPA_USB_SUSPEND_REQUESTED,
-	IPA_USB_SUSPEND_IN_PROGRESS,
 	IPA_USB_SUSPENDED,
 	IPA_USB_SUSPENDED_NO_RWAKEUP,
 	IPA_USB_RESUME_IN_PROGRESS
@@ -146,13 +145,6 @@
 #define IPA3_USB_IS_TTYPE_DPL(__ttype) \
 	((__ttype) == IPA_USB_TRANSPORT_DPL)
 
-struct finish_suspend_work_context {
-	struct work_struct work;
-	enum ipa3_usb_transport_type ttype;
-	u32 dl_clnt_hdl;
-	u32 ul_clnt_hdl;
-};
-
 struct ipa3_usb_teth_prot_conn_params {
 	u32 usb_to_ipa_clnt_hdl;
 	u32 ipa_to_usb_clnt_hdl;
@@ -168,7 +160,6 @@
 	int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *user_data);
 	void *user_data;
 	enum ipa3_usb_state state;
-	struct finish_suspend_work_context finish_suspend_work;
 	struct ipa_usb_xdci_chan_params ch_params;
 	struct ipa3_usb_teth_prot_conn_params teth_conn_params;
 };
@@ -221,16 +212,10 @@
 
 static void ipa3_usb_wq_notify_remote_wakeup(struct work_struct *work);
 static void ipa3_usb_wq_dpl_notify_remote_wakeup(struct work_struct *work);
-static void ipa3_usb_wq_notify_suspend_completed(struct work_struct *work);
-static void ipa3_usb_wq_dpl_notify_suspend_completed(struct work_struct *work);
 static DECLARE_WORK(ipa3_usb_notify_remote_wakeup_work,
 	ipa3_usb_wq_notify_remote_wakeup);
 static DECLARE_WORK(ipa3_usb_dpl_notify_remote_wakeup_work,
 	ipa3_usb_wq_dpl_notify_remote_wakeup);
-static DECLARE_WORK(ipa3_usb_notify_suspend_completed_work,
-	ipa3_usb_wq_notify_suspend_completed);
-static DECLARE_WORK(ipa3_usb_dpl_notify_suspend_completed_work,
-	ipa3_usb_wq_dpl_notify_suspend_completed);
 
 struct ipa3_usb_context *ipa3_usb_ctx;
 
@@ -273,8 +258,6 @@
 		return "IPA_USB_STOPPED";
 	case IPA_USB_SUSPEND_REQUESTED:
 		return "IPA_USB_SUSPEND_REQUESTED";
-	case IPA_USB_SUSPEND_IN_PROGRESS:
-		return "IPA_USB_SUSPEND_IN_PROGRESS";
 	case IPA_USB_SUSPENDED:
 		return "IPA_USB_SUSPENDED";
 	case IPA_USB_SUSPENDED_NO_RWAKEUP:
@@ -330,17 +313,11 @@
 			 * In case of failure during suspend request
 			 * handling, state is reverted to connected.
 			 */
-			(err_permit && state == IPA_USB_SUSPEND_REQUESTED) ||
-			/*
-			 * In case of failure during suspend completing
-			 * handling, state is reverted to connected.
-			 */
-			(err_permit && state == IPA_USB_SUSPEND_IN_PROGRESS))
+			(err_permit && state == IPA_USB_SUSPEND_REQUESTED))
 			state_legal = true;
 		break;
 	case IPA_USB_STOPPED:
-		if (state == IPA_USB_SUSPEND_IN_PROGRESS ||
-			state == IPA_USB_CONNECTED ||
+		if (state == IPA_USB_CONNECTED ||
 			state == IPA_USB_SUSPENDED ||
 			state == IPA_USB_SUSPENDED_NO_RWAKEUP)
 			state_legal = true;
@@ -349,19 +326,8 @@
 		if (state == IPA_USB_CONNECTED)
 			state_legal = true;
 		break;
-	case IPA_USB_SUSPEND_IN_PROGRESS:
-		if (state == IPA_USB_SUSPEND_REQUESTED ||
-			/*
-			 * In case of failure during resume, state is reverted
-			 * to original, which could be suspend_in_progress.
-			 * Allow it.
-			 */
-			(err_permit && state == IPA_USB_RESUME_IN_PROGRESS))
-			state_legal = true;
-		break;
 	case IPA_USB_SUSPENDED:
 		if (state == IPA_USB_SUSPEND_REQUESTED ||
-			state == IPA_USB_SUSPEND_IN_PROGRESS ||
 			/*
 			 * In case of failure during resume, state is reverted
 			 * to original, which could be suspended. Allow it
@@ -374,8 +340,7 @@
 			state_legal = true;
 		break;
 	case IPA_USB_RESUME_IN_PROGRESS:
-		if (state == IPA_USB_SUSPEND_IN_PROGRESS ||
-			state == IPA_USB_SUSPENDED)
+		if (state == IPA_USB_SUSPENDED)
 			state_legal = true;
 		break;
 	default:
@@ -452,7 +417,6 @@
 		break;
 	case IPA_USB_OP_DISCONNECT:
 		if  (state == IPA_USB_CONNECTED ||
-			state == IPA_USB_SUSPEND_IN_PROGRESS ||
 			state == IPA_USB_SUSPENDED ||
 			state == IPA_USB_SUSPENDED_NO_RWAKEUP)
 			is_legal = true;
@@ -483,7 +447,6 @@
 		break;
 	case IPA_USB_OP_RESUME:
 		if (state == IPA_USB_SUSPENDED ||
-			state == IPA_USB_SUSPEND_IN_PROGRESS ||
 			state == IPA_USB_SUSPENDED_NO_RWAKEUP)
 			is_legal = true;
 		break;
@@ -582,71 +545,6 @@
 	ipa3_usb_notify_do(IPA_USB_TRANSPORT_DPL, IPA_USB_REMOTE_WAKEUP);
 }
 
-static void ipa3_usb_wq_notify_suspend_completed(struct work_struct *work)
-{
-	ipa3_usb_notify_do(IPA_USB_TRANSPORT_TETH, IPA_USB_SUSPEND_COMPLETED);
-}
-
-static void ipa3_usb_wq_dpl_notify_suspend_completed(struct work_struct *work)
-{
-	ipa3_usb_notify_do(IPA_USB_TRANSPORT_DPL, IPA_USB_SUSPEND_COMPLETED);
-}
-
-static void ipa3_usb_wq_finish_suspend_work(struct work_struct *work)
-{
-	struct finish_suspend_work_context *finish_suspend_work_ctx;
-	unsigned long flags;
-	int result = -EFAULT;
-	struct ipa3_usb_transport_type_ctx *tctx;
-
-	mutex_lock(&ipa3_usb_ctx->general_mutex);
-	IPA_USB_DBG_LOW("entry\n");
-	finish_suspend_work_ctx = container_of(work,
-		struct finish_suspend_work_context, work);
-	tctx = &ipa3_usb_ctx->ttype_ctx[finish_suspend_work_ctx->ttype];
-
-	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
-	if (tctx->state != IPA_USB_SUSPEND_IN_PROGRESS) {
-		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
-		mutex_unlock(&ipa3_usb_ctx->general_mutex);
-		return;
-	}
-	spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
-
-	/* Stop DL/DPL channel */
-	result = ipa3_stop_gsi_channel(finish_suspend_work_ctx->dl_clnt_hdl);
-	if (result) {
-		IPAERR("Error stopping DL/DPL channel: %d, resuming channel\n",
-			result);
-		ipa3_xdci_resume(finish_suspend_work_ctx->ul_clnt_hdl,
-			finish_suspend_work_ctx->dl_clnt_hdl,
-			IPA3_USB_IS_TTYPE_DPL(finish_suspend_work_ctx->ttype));
-		/* Change state back to CONNECTED */
-		if (!ipa3_usb_set_state(IPA_USB_CONNECTED, true,
-			finish_suspend_work_ctx->ttype))
-			IPA_USB_ERR("failed to change state to connected\n");
-		queue_work(ipa3_usb_ctx->wq,
-			IPA3_USB_IS_TTYPE_DPL(finish_suspend_work_ctx->ttype) ?
-			&ipa3_usb_dpl_notify_remote_wakeup_work :
-			&ipa3_usb_notify_remote_wakeup_work);
-		mutex_unlock(&ipa3_usb_ctx->general_mutex);
-		return;
-	}
-
-	/* Change ipa_usb state to SUSPENDED */
-	if (!ipa3_usb_set_state(IPA_USB_SUSPENDED, false,
-		finish_suspend_work_ctx->ttype))
-		IPA_USB_ERR("failed to change state to suspended\n");
-
-	queue_work(ipa3_usb_ctx->wq,
-		IPA3_USB_IS_TTYPE_DPL(finish_suspend_work_ctx->ttype) ?
-		&ipa3_usb_dpl_notify_suspend_completed_work :
-		&ipa3_usb_notify_suspend_completed_work);
-
-	IPA_USB_DBG_LOW("exit\n");
-	mutex_unlock(&ipa3_usb_ctx->general_mutex);
-}
-
 static int ipa3_usb_cons_request_resource_cb_do(
 	enum ipa3_usb_transport_type ttype,
 	struct work_struct *remote_wakeup_work)
@@ -674,17 +572,6 @@
 		else
 			result = -EINPROGRESS;
 		break;
-	case IPA_USB_SUSPEND_IN_PROGRESS:
-		/*
-		 * This case happens due to suspend interrupt.
-		 * CONS is granted
-		 */
-		if (!rm_ctx->cons_requested) {
-			rm_ctx->cons_requested = true;
-			queue_work(ipa3_usb_ctx->wq, remote_wakeup_work);
-		}
-		result = 0;
-		break;
 	case IPA_USB_SUSPENDED:
 		if (!rm_ctx->cons_requested) {
 			rm_ctx->cons_requested = true;
@@ -727,15 +614,10 @@
 			ipa3_usb_state_to_string(
 			ipa3_usb_ctx->ttype_ctx[ttype].state));
 	switch (ipa3_usb_ctx->ttype_ctx[ttype].state) {
-	case IPA_USB_SUSPEND_IN_PROGRESS:
+	case IPA_USB_SUSPENDED:
 		/* Proceed with the suspend if no DL/DPL data */
 		if (rm_ctx->cons_requested)
 			rm_ctx->cons_requested_released = true;
-		else {
-			queue_work(ipa3_usb_ctx->wq,
-				&ipa3_usb_ctx->ttype_ctx[ttype].
-				finish_suspend_work.work);
-		}
 		break;
 	case IPA_USB_SUSPEND_REQUESTED:
 		if (rm_ctx->cons_requested)
@@ -2311,8 +2193,7 @@
 	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
 	orig_state = ipa3_usb_ctx->ttype_ctx[ttype].state;
 	if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
-		if (orig_state != IPA_USB_SUSPEND_IN_PROGRESS &&
-			orig_state != IPA_USB_SUSPENDED) {
+		if (orig_state != IPA_USB_SUSPENDED) {
 			spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock,
 				flags);
 			/* Stop UL channel */
@@ -2340,8 +2221,7 @@
 	if (result)
 		goto bad_params;
 
-	if (orig_state != IPA_USB_SUSPEND_IN_PROGRESS &&
-		orig_state != IPA_USB_SUSPENDED) {
+	if (orig_state != IPA_USB_SUSPENDED) {
 		result = ipa3_usb_release_prod(ttype);
 		if (result) {
 			IPA_USB_ERR("failed to release PROD.\n");
@@ -2547,7 +2427,6 @@
 {
 	int result = 0;
 	unsigned long flags;
-	enum ipa3_usb_cons_state curr_cons_state;
 	enum ipa3_usb_transport_type ttype;
 
 	mutex_lock(&ipa3_usb_ctx->general_mutex);
@@ -2602,49 +2481,20 @@
 		goto release_prod_fail;
 	}
 
+	/* Check if DL/DPL data pending */
 	spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
-	curr_cons_state = ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_state;
+	if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_state ==
+		IPA_USB_CONS_GRANTED &&
+		ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
+
+		IPA_USB_DBG("DL/DPL data pending, invoke remote wakeup\n");
+		queue_work(ipa3_usb_ctx->wq,
+			IPA3_USB_IS_TTYPE_DPL(ttype) ?
+			&ipa3_usb_dpl_notify_remote_wakeup_work :
+			&ipa3_usb_notify_remote_wakeup_work);
+	}
 	spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
-	if (curr_cons_state == IPA_USB_CONS_GRANTED) {
-		/* Change state to SUSPEND_IN_PROGRESS */
-		if (!ipa3_usb_set_state(IPA_USB_SUSPEND_IN_PROGRESS,
-			false, ttype))
-			IPA_USB_ERR("fail set state to suspend_in_progress\n");
 
-		/* Check if DL/DPL data pending */
-		spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
-		if (ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_requested) {
-			IPA_USB_DBG(
-				"DL/DPL data pending, invoke remote wakeup\n");
-			queue_work(ipa3_usb_ctx->wq,
-				IPA3_USB_IS_TTYPE_DPL(ttype) ?
-				&ipa3_usb_dpl_notify_remote_wakeup_work :
-				&ipa3_usb_notify_remote_wakeup_work);
-		}
-		spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
-
-		ipa3_usb_ctx->ttype_ctx[ttype].finish_suspend_work.ttype =
-			ttype;
-		ipa3_usb_ctx->ttype_ctx[ttype].finish_suspend_work.dl_clnt_hdl =
-			dl_clnt_hdl;
-		ipa3_usb_ctx->ttype_ctx[ttype].finish_suspend_work.ul_clnt_hdl =
-			ul_clnt_hdl;
-		INIT_WORK(&ipa3_usb_ctx->ttype_ctx[ttype].
-			finish_suspend_work.work,
-			ipa3_usb_wq_finish_suspend_work);
-
-		result = -EINPROGRESS;
-		IPA_USB_DBG("exit with suspend_in_progress\n");
-		goto bad_params;
-	}
-
-	/* Stop DL channel */
-	result = ipa3_stop_gsi_channel(dl_clnt_hdl);
-	if (result) {
-		IPAERR("Error stopping DL/DPL channel: %d\n", result);
-		result = -EFAULT;
-		goto release_prod_fail;
-	}
 	/* Change state to SUSPENDED */
 	if (!ipa3_usb_set_state(IPA_USB_SUSPENDED, false, ttype))
 		IPA_USB_ERR("failed to change state to suspended\n");
@@ -2803,13 +2653,11 @@
 		}
 	}
 
-	if (prev_state != IPA_USB_SUSPEND_IN_PROGRESS) {
-		/* Start DL/DPL channel */
-		result = ipa3_start_gsi_channel(dl_clnt_hdl);
-		if (result) {
-			IPA_USB_ERR("failed to start DL/DPL channel.\n");
-			goto start_dl_fail;
-		}
+	/* Start DL/DPL channel */
+	result = ipa3_start_gsi_channel(dl_clnt_hdl);
+	if (result) {
+		IPA_USB_ERR("failed to start DL/DPL channel.\n");
+		goto start_dl_fail;
 	}
 
 	/* Change state to CONNECTED */
@@ -2824,12 +2672,10 @@
 	return 0;
 
 state_change_connected_fail:
-	if (prev_state != IPA_USB_SUSPEND_IN_PROGRESS) {
-		result = ipa3_stop_gsi_channel(dl_clnt_hdl);
-		if (result)
-			IPA_USB_ERR("Error stopping DL/DPL channel: %d\n",
-				result);
-	}
+	result = ipa3_stop_gsi_channel(dl_clnt_hdl);
+	if (result)
+		IPA_USB_ERR("Error stopping DL/DPL channel: %d\n",
+			result);
 start_dl_fail:
 	if (!IPA3_USB_IS_TTYPE_DPL(ttype)) {
 		result = ipa3_stop_gsi_channel(ul_clnt_hdl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 31e530e..837bf38 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -232,6 +232,9 @@
 	ipa3_transport_release_resource);
 static void ipa_gsi_notify_cb(struct gsi_per_notify *notify);
 
+static void ipa3_post_init_wq(struct work_struct *work);
+static DECLARE_WORK(ipa3_post_init_work, ipa3_post_init_wq);
+
 static struct ipa3_plat_drv_res ipa3_res = {0, };
 struct msm_bus_scale_pdata *ipa3_bus_scale_table;
 
@@ -495,63 +498,6 @@
 	return 0;
 }
 
-/**
-* ipa3_flow_control() - Enable/Disable flow control on a particular client.
-* Return codes:
-* None
-*/
-void ipa3_flow_control(enum ipa_client_type ipa_client,
-		bool enable, uint32_t qmap_id)
-{
-	struct ipa_ep_cfg_ctrl ep_ctrl = {0};
-	int ep_idx;
-	struct ipa3_ep_context *ep;
-
-	/* Check if tethered flow control is needed or not.*/
-	if (!ipa3_ctx->tethered_flow_control) {
-		IPADBG("Apps flow control is not needed\n");
-		return;
-	}
-
-	/* Check if ep is valid. */
-	ep_idx = ipa3_get_ep_mapping(ipa_client);
-	if (ep_idx == -1) {
-		IPADBG("Invalid IPA client\n");
-		return;
-	}
-
-	ep = &ipa3_ctx->ep[ep_idx];
-	if (!ep->valid || (ep->client != IPA_CLIENT_USB_PROD)) {
-		IPADBG("EP not valid/Not applicable for client.\n");
-		return;
-	}
-
-	spin_lock(&ipa3_ctx->disconnect_lock);
-	/* Check if the QMAP_ID matches. */
-	if (ep->cfg.meta.qmap_id != qmap_id) {
-		IPADBG("Flow control ind not for same flow: %u %u\n",
-			ep->cfg.meta.qmap_id, qmap_id);
-		spin_unlock(&ipa3_ctx->disconnect_lock);
-		return;
-	}
-	if (!ep->disconnect_in_progress) {
-		if (enable) {
-			IPADBG("Enabling Flow\n");
-			ep_ctrl.ipa_ep_delay = false;
-			IPA_STATS_INC_CNT(ipa3_ctx->stats.flow_enable);
-		} else {
-			IPADBG("Disabling Flow\n");
-			ep_ctrl.ipa_ep_delay = true;
-			IPA_STATS_INC_CNT(ipa3_ctx->stats.flow_disable);
-		}
-		ep_ctrl.ipa_ep_suspend = false;
-		ipa3_cfg_ep_ctrl(ep_idx, &ep_ctrl);
-	} else {
-		IPADBG("EP disconnect is in progress\n");
-	}
-	spin_unlock(&ipa3_ctx->disconnect_lock);
-}
-
 static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type)
 {
 	if (!buff) {
@@ -1863,9 +1809,11 @@
 				IPA_ENDP_INIT_HOL_BLOCK_EN_n,
 				ep_idx, &ep_holb);
 
-			ipahal_write_reg_n_fields(
-				IPA_ENDP_INIT_CTRL_n,
-				ep_idx, &ep_suspend);
+			/* from IPA 4.0 pipe suspend is not supported */
+			if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
+				ipahal_write_reg_n_fields(
+					IPA_ENDP_INIT_CTRL_n,
+					ep_idx, &ep_suspend);
 		}
 	}
 }
@@ -3979,6 +3927,15 @@
 	struct ipa3_flt_tbl *flt_tbl;
 	int i;
 
+	if (ipa3_ctx == NULL) {
+		IPADBG("IPA driver haven't initialized\n");
+		return -ENXIO;
+	}
+
+	/* Prevent consequent calls from trying to load the FW again. */
+	if (ipa3_ctx->ipa_initialization_complete)
+		return 0;
+
 	/*
 	 * indication whether working in MHI config or non MHI config is given
 	 * in ipa3_write which is launched before ipa3_post_init. i.e. from
@@ -4113,41 +4070,15 @@
 fail_setup_apps_pipes:
 	gsi_deregister_device(ipa3_ctx->gsi_dev_hdl, false);
 fail_register_device:
-	ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
-	ipa_rm_exit();
-	cdev_del(&ipa3_ctx->cdev);
-	device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
-	unregister_chrdev_region(ipa3_ctx->dev_num, 1);
-	ipa3_free_dma_task_for_gsi();
 	ipa3_destroy_flt_tbl_idrs();
-	idr_destroy(&ipa3_ctx->ipa_idr);
-	kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
-	kmem_cache_destroy(ipa3_ctx->tx_pkt_wrapper_cache);
-	kmem_cache_destroy(ipa3_ctx->rt_tbl_cache);
-	kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_offset_cache);
-	kmem_cache_destroy(ipa3_ctx->hdr_proc_ctx_cache);
-	kmem_cache_destroy(ipa3_ctx->hdr_offset_cache);
-	kmem_cache_destroy(ipa3_ctx->hdr_cache);
-	kmem_cache_destroy(ipa3_ctx->rt_rule_cache);
-	kmem_cache_destroy(ipa3_ctx->flt_rule_cache);
-	destroy_workqueue(ipa3_ctx->transport_power_mgmt_wq);
-	destroy_workqueue(ipa3_ctx->power_mgmt_wq);
-	iounmap(ipa3_ctx->mmio);
-	ipa3_disable_clks();
-	if (ipa3_clk)
-		clk_put(ipa3_clk);
-	ipa3_clk = NULL;
-	msm_bus_scale_unregister_client(ipa3_ctx->ipa_bus_hdl);
-	if (ipa3_bus_scale_table) {
-		msm_bus_cl_clear_pdata(ipa3_bus_scale_table);
-		ipa3_bus_scale_table = NULL;
-	}
-	kfree(ipa3_ctx->ctrl);
-	kfree(ipa3_ctx);
-	ipa3_ctx = NULL;
 	return result;
 }
 
+static void ipa3_post_init_wq(struct work_struct *work)
+{
+	ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
+}
+
 static int ipa3_trigger_fw_loading_mdms(void)
 {
 	int result;
@@ -4249,9 +4180,10 @@
 	if (result) {
 		IPAERR("FW loading process has failed\n");
 			return result;
-	} else
-		ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
-
+	} else {
+			queue_work(ipa3_ctx->transport_power_mgmt_wq,
+				&ipa3_post_init_work);
+	}
 	return count;
 }
 
@@ -4722,20 +4654,6 @@
 		goto fail_device_create;
 	}
 
-	cdev_init(&ipa3_ctx->cdev, &ipa3_drv_fops);
-	ipa3_ctx->cdev.owner = THIS_MODULE;
-	ipa3_ctx->cdev.ops = &ipa3_drv_fops;  /* from LDD3 */
-
-	result = cdev_add(&ipa3_ctx->cdev, ipa3_ctx->dev_num, 1);
-	if (result) {
-		IPAERR(":cdev_add err=%d\n", -result);
-		result = -ENODEV;
-		goto fail_cdev_add;
-	}
-	IPADBG("ipa cdev added successful. major:%d minor:%d\n",
-			MAJOR(ipa3_ctx->dev_num),
-			MINOR(ipa3_ctx->dev_num));
-
 	if (ipa3_create_nat_device()) {
 		IPAERR("unable to create nat device\n");
 		result = -ENODEV;
@@ -4793,16 +4711,28 @@
 		}
 	}
 
+	cdev_init(&ipa3_ctx->cdev, &ipa3_drv_fops);
+	ipa3_ctx->cdev.owner = THIS_MODULE;
+	ipa3_ctx->cdev.ops = &ipa3_drv_fops;  /* from LDD3 */
+
+	result = cdev_add(&ipa3_ctx->cdev, ipa3_ctx->dev_num, 1);
+	if (result) {
+		IPAERR(":cdev_add err=%d\n", -result);
+		result = -ENODEV;
+		goto fail_cdev_add;
+	}
+	IPADBG("ipa cdev added successful. major:%d minor:%d\n",
+			MAJOR(ipa3_ctx->dev_num),
+			MINOR(ipa3_ctx->dev_num));
 	return 0;
 
+fail_cdev_add:
 fail_ipa_init_interrupts:
 	ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
 fail_create_apps_resource:
 	ipa_rm_exit();
 fail_ipa_rm_init:
 fail_nat_dev_add:
-	cdev_del(&ipa3_ctx->cdev);
-fail_cdev_add:
 	device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
 fail_device_create:
 	unregister_chrdev_region(ipa3_ctx->dev_num, 1);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 0b8115f..564397a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -69,13 +69,15 @@
 	}
 
 	/* Enable the pipe */
-	if (IPA_CLIENT_IS_CONS(ep->client) &&
-	    (ep->keep_ipa_awake ||
-	     ipa3_ctx->resume_on_connect[ep->client] ||
-	     !ipa3_should_pipe_be_suspended(ep->client))) {
-		memset(&ep_cfg_ctrl, 0, sizeof(ep_cfg_ctrl));
-		ep_cfg_ctrl.ipa_ep_suspend = false;
-		res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+		if (IPA_CLIENT_IS_CONS(ep->client) &&
+		    (ep->keep_ipa_awake ||
+		    ipa3_ctx->resume_on_connect[ep->client] ||
+		    !ipa3_should_pipe_be_suspended(ep->client))) {
+			memset(&ep_cfg_ctrl, 0, sizeof(ep_cfg_ctrl));
+			ep_cfg_ctrl.ipa_ep_suspend = false;
+			res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+		}
 	}
 
 	return res;
@@ -97,33 +99,41 @@
 		res = ipa3_cfg_ep_holb(clnt_hdl, &holb_cfg);
 	}
 
-	/* Suspend the pipe */
-	if (IPA_CLIENT_IS_CONS(ep->client)) {
-		/*
-		 * for RG10 workaround uC needs to be loaded before pipe can
-		 * be suspended in this case.
-		 */
-		if (ipa3_ctx->apply_rg10_wa && ipa3_uc_state_check()) {
-			IPADBG("uC is not loaded yet, waiting...\n");
-			res = wait_for_completion_timeout(
-				&ipa3_ctx->uc_loaded_completion_obj, 60 * HZ);
-			if (res == 0)
-				IPADBG("timeout waiting for uC to load\n");
+	/*
+	 * for IPA 4.0 and above aggregation frame is closed together with
+	 * channel STOP
+	 */
+	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+		/* Suspend the pipe */
+		if (IPA_CLIENT_IS_CONS(ep->client)) {
+			/*
+			 * for RG10 workaround uC needs to be loaded before
+			 * pipe can be suspended in this case.
+			 */
+			if (ipa3_ctx->apply_rg10_wa && ipa3_uc_state_check()) {
+				IPADBG("uC is not loaded yet, waiting...\n");
+				res = wait_for_completion_timeout(
+					&ipa3_ctx->uc_loaded_completion_obj,
+					60 * HZ);
+				if (res == 0)
+					IPADBG("timeout waiting for uC load\n");
+			}
+
+			memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+			ep_cfg_ctrl.ipa_ep_suspend = true;
+			res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
 		}
 
-		memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
-		ep_cfg_ctrl.ipa_ep_suspend = true;
-		res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
-	}
-
-	udelay(IPA_PKT_FLUSH_TO_US);
-	ipahal_read_reg_n_fields(IPA_ENDP_INIT_AGGR_n, clnt_hdl, &ep_aggr);
-	if (ep_aggr.aggr_en) {
-		res = ipa3_tag_aggr_force_close(clnt_hdl);
-		if (res) {
-			IPAERR("tag process timeout, client:%d err:%d\n",
-				   clnt_hdl, res);
-			BUG();
+		udelay(IPA_PKT_FLUSH_TO_US);
+		ipahal_read_reg_n_fields(IPA_ENDP_INIT_AGGR_n, clnt_hdl,
+			&ep_aggr);
+		if (ep_aggr.aggr_en) {
+			res = ipa3_tag_aggr_force_close(clnt_hdl);
+			if (res) {
+				IPAERR("tag process timeout client:%d err:%d\n",
+					clnt_hdl, res);
+				ipa_assert();
+			}
 		}
 	}
 
@@ -1257,10 +1267,12 @@
 		goto disable_clk_and_exit;
 	}
 
-	/* Suspend the DL/DPL EP */
-	memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
-	ep_cfg_ctrl.ipa_ep_suspend = true;
-	ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+		/* Suspend the DL/DPL EP */
+		memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+		ep_cfg_ctrl.ipa_ep_suspend = true;
+		ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+	}
 
 	/*
 	 * Check if DL/DPL channel is empty again, data could enter the channel
@@ -1275,6 +1287,14 @@
 		goto unsuspend_dl_and_exit;
 	}
 
+	/* Stop DL channel */
+	result = ipa3_stop_gsi_channel(dl_clnt_hdl);
+	if (result) {
+		IPAERR("Error stopping DL/DPL channel: %d\n", result);
+		result = -EFAULT;
+		goto unsuspend_dl_and_exit;
+	}
+
 	/* STOP UL channel */
 	if (!is_dpl) {
 		source_pipe_bitmask = 1 << ipa3_get_ep_mapping(ul_ep->client);
@@ -1283,7 +1303,7 @@
 		if (result) {
 			IPAERR("Error stopping UL channel: result = %d\n",
 				result);
-			goto unsuspend_dl_and_exit;
+			goto start_dl_and_exit;
 		}
 	}
 
@@ -1292,11 +1312,15 @@
 	IPADBG("exit\n");
 	return 0;
 
+start_dl_and_exit:
+	gsi_start_channel(dl_ep->gsi_chan_hdl);
 unsuspend_dl_and_exit:
-	/* Unsuspend the DL EP */
-	memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
-	ep_cfg_ctrl.ipa_ep_suspend = false;
-	ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+		/* Unsuspend the DL EP */
+		memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+		ep_cfg_ctrl.ipa_ep_suspend = false;
+		ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+	}
 disable_clk_and_exit:
 	IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(dl_clnt_hdl));
 	return result;
@@ -1340,7 +1364,8 @@
 
 int ipa3_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, bool is_dpl)
 {
-	struct ipa3_ep_context *ul_ep, *dl_ep;
+	struct ipa3_ep_context *ul_ep = NULL;
+	struct ipa3_ep_context *dl_ep = NULL;
 	enum gsi_status gsi_res;
 	struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
 
@@ -1360,10 +1385,17 @@
 		ul_ep = &ipa3_ctx->ep[ul_clnt_hdl];
 	IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(dl_clnt_hdl));
 
-	/* Unsuspend the DL/DPL EP */
-	memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
-	ep_cfg_ctrl.ipa_ep_suspend = false;
-	ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+		/* Unsuspend the DL/DPL EP */
+		memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+		ep_cfg_ctrl.ipa_ep_suspend = false;
+		ipa3_cfg_ep_ctrl(dl_clnt_hdl, &ep_cfg_ctrl);
+	}
+
+	/* Start DL channel */
+	gsi_res = gsi_start_channel(dl_ep->gsi_chan_hdl);
+	if (gsi_res != GSI_STATUS_SUCCESS)
+		IPAERR("Error starting DL channel: %d\n", gsi_res);
 
 	/* Start UL channel */
 	if (!is_dpl) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 04d807f..915f2b8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -267,7 +267,6 @@
 	int i = 0;
 	int j;
 	int result;
-	int fail_dma_wrap = 0;
 	u32 mem_flag = GFP_ATOMIC;
 	const struct ipa_gsi_ep_config *gsi_ep_cfg;
 
@@ -298,7 +297,6 @@
 	spin_lock_bh(&sys->spinlock);
 
 	for (i = 0; i < num_desc; i++) {
-		fail_dma_wrap = 0;
 		tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache,
 					   mem_flag);
 		if (!tx_pkt) {
@@ -319,7 +317,7 @@
 			if (ipa_populate_tag_field(&desc[i], tx_pkt,
 				&tag_pyld_ret)) {
 				IPAERR("Failed to populate tag field\n");
-				goto failure;
+				goto failure_dma_map;
 			}
 		}
 
@@ -335,11 +333,6 @@
 					tx_pkt->mem.base,
 					tx_pkt->mem.size,
 					DMA_TO_DEVICE);
-				if (!tx_pkt->mem.phys_base) {
-					IPAERR("failed to do dma map.\n");
-					fail_dma_wrap = 1;
-					goto failure;
-				}
 			} else {
 					tx_pkt->mem.phys_base =
 						desc[i].dma_address;
@@ -355,17 +348,17 @@
 					desc[i].frag,
 					0, tx_pkt->mem.size,
 					DMA_TO_DEVICE);
-				if (!tx_pkt->mem.phys_base) {
-					IPAERR("dma map failed\n");
-					fail_dma_wrap = 1;
-					goto failure;
-				}
 			} else {
 				tx_pkt->mem.phys_base =
 					desc[i].dma_address;
 				tx_pkt->no_unmap_dma = true;
 			}
 		}
+		if (dma_mapping_error(ipa3_ctx->pdev, tx_pkt->mem.phys_base)) {
+			IPAERR("failed to do dma map.\n");
+			goto failure_dma_map;
+		}
+
 		tx_pkt->sys = sys;
 		tx_pkt->callback = desc[i].callback;
 		tx_pkt->user1 = desc[i].user1;
@@ -426,28 +419,31 @@
 
 	return 0;
 
+failure_dma_map:
+		kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
+
 failure:
 	ipahal_destroy_imm_cmd(tag_pyld_ret);
 	tx_pkt = tx_pkt_first;
 	for (j = 0; j < i; j++) {
 		next_pkt = list_next_entry(tx_pkt, link);
 		list_del(&tx_pkt->link);
-		if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) {
-			dma_unmap_single(ipa3_ctx->pdev, tx_pkt->mem.phys_base,
-				tx_pkt->mem.size,
-				DMA_TO_DEVICE);
-		} else {
-			dma_unmap_page(ipa3_ctx->pdev, tx_pkt->mem.phys_base,
-				tx_pkt->mem.size,
-				DMA_TO_DEVICE);
+
+		if (!tx_pkt->no_unmap_dma) {
+			if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) {
+				dma_unmap_single(ipa3_ctx->pdev,
+					tx_pkt->mem.phys_base,
+					tx_pkt->mem.size, DMA_TO_DEVICE);
+			} else {
+				dma_unmap_page(ipa3_ctx->pdev,
+					tx_pkt->mem.phys_base,
+					tx_pkt->mem.size,
+					DMA_TO_DEVICE);
+			}
 		}
 		kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
 		tx_pkt = next_pkt;
 	}
-	if (j < num_desc)
-		/* last desc failed */
-		if (fail_dma_wrap)
-			kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
 
 	kfree(gsi_xfer_elem_array);
 
@@ -1444,8 +1440,7 @@
 		rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
 						     sys->rx_buff_sz,
 						     DMA_FROM_DEVICE);
-		if (rx_pkt->data.dma_addr == 0 ||
-				rx_pkt->data.dma_addr == ~0) {
+		if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
 			pr_err_ratelimited("%s dma map fail %p for %p sys=%p\n",
 			       __func__, (void *)rx_pkt->data.dma_addr,
 			       ptr, sys);
@@ -1605,8 +1600,7 @@
 		ptr = skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ);
 		rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
 				IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE);
-		if (rx_pkt->data.dma_addr == 0 ||
-				rx_pkt->data.dma_addr == ~0) {
+		if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
 			IPAERR("dma_map_single failure %p for %p\n",
 			       (void *)rx_pkt->data.dma_addr, ptr);
 			goto fail_dma_mapping;
@@ -1676,8 +1670,7 @@
 		rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
 						     sys->rx_buff_sz,
 						     DMA_FROM_DEVICE);
-		if (rx_pkt->data.dma_addr == 0 ||
-				rx_pkt->data.dma_addr == ~0) {
+		if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
 			IPAERR("dma_map_single failure %p for %p\n",
 			       (void *)rx_pkt->data.dma_addr, ptr);
 			goto fail_dma_mapping;
@@ -1764,8 +1757,8 @@
 			ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
 			rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev,
 				ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
-			if (rx_pkt->data.dma_addr == 0 ||
-				rx_pkt->data.dma_addr == ~0) {
+			if (dma_mapping_error(ipa3_ctx->pdev,
+				rx_pkt->data.dma_addr)) {
 				IPAERR("dma_map_single failure %p for %p\n",
 					(void *)rx_pkt->data.dma_addr, ptr);
 				goto fail_dma_mapping;
@@ -1780,8 +1773,8 @@
 			ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
 			rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev,
 				ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
-			if (rx_pkt->data.dma_addr == 0 ||
-				rx_pkt->data.dma_addr == ~0) {
+			if (dma_mapping_error(ipa3_ctx->pdev,
+				rx_pkt->data.dma_addr)) {
 				IPAERR("dma_map_single failure %p for %p\n",
 					(void *)rx_pkt->data.dma_addr, ptr);
 				goto fail_dma_mapping;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index 410b96a..593d4fc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -490,6 +490,10 @@
 			entry->hdr,
 			entry->hdr_len,
 			DMA_TO_DEVICE);
+		if (dma_mapping_error(ipa3_ctx->pdev, entry->phys_base)) {
+			IPAERR("dma_map_single failure for entry\n");
+			goto fail_dma_mapping;
+		}
 	} else {
 		entry->is_hdr_proc_ctx = false;
 		if (list_empty(&htbl->head_free_offset_list[bin])) {
@@ -565,6 +569,9 @@
 	list_del(&entry->link);
 	dma_unmap_single(ipa3_ctx->pdev, entry->phys_base,
 			entry->hdr_len, DMA_TO_DEVICE);
+fail_dma_mapping:
+	entry->is_hdr_proc_ctx = false;
+
 bad_hdr_len:
 	entry->cookie = 0;
 	kmem_cache_free(ipa3_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 86442b1..9a406d6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1970,8 +1970,6 @@
 int ipa3_set_rt_tuple_mask(int tbl_idx, struct ipahal_reg_hash_tuple *tuple);
 void ipa3_set_resorce_groups_min_max_limits(void);
 void ipa3_suspend_apps_pipes(bool suspend);
-void ipa3_flow_control(enum ipa_client_type ipa_client, bool enable,
-			uint32_t qmap_id);
 int ipa3_flt_read_tbl_from_hw(u32 pipe_idx,
 	enum ipa_ip_type ip_type,
 	bool hashable,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index 799246b..60dc04f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1600,13 +1600,15 @@
 
 	memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
 	if (IPA_CLIENT_IS_CONS(ep->client)) {
-		ep_cfg_ctrl.ipa_ep_suspend = true;
-		result = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
-		if (result)
-			IPAERR("client (ep: %d) failed to suspend result=%d\n",
-					clnt_hdl, result);
-		else
-			IPADBG("client (ep: %d) suspended\n", clnt_hdl);
+		if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+			ep_cfg_ctrl.ipa_ep_suspend = true;
+			result = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+			if (result)
+				IPAERR("(ep: %d) failed to suspend result=%d\n",
+						clnt_hdl, result);
+			else
+				IPADBG("(ep: %d) suspended\n", clnt_hdl);
+		}
 	} else {
 		ep_cfg_ctrl.ipa_ep_delay = true;
 		result = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index ab26893..079481d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -1631,6 +1631,16 @@
 
 	ep = &ipa3_ctx->ep[ipa_ep_idx];
 
+	/*
+	 * starting IPA 4.0 pipe no longer can be suspended. Instead,
+	 * the corresponding GSI channel should be stopped. Usually client
+	 * driver will take care of stopping the channel. For client drivers
+	 * that are not stopping the channel, IPA RM will do that based on
+	 * ipa3_should_pipe_channel_be_stopped().
+	 */
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+		return false;
+
 	if (ep->keep_ipa_awake)
 		return false;
 
@@ -1651,6 +1661,41 @@
 }
 
 /**
+ * ipa3_should_pipe_channel_be_stopped() - returns true when the client's
+ * channel should be stopped during a power save scenario. False otherwise.
+ * Most client already stops the GSI channel on suspend, and are not included
+ * in the list below.
+ *
+ * @client: [IN] IPA client
+ */
+static bool ipa3_should_pipe_channel_be_stopped(enum ipa_client_type client)
+{
+	struct ipa3_ep_context *ep;
+	int ipa_ep_idx;
+
+	if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
+		return false;
+
+	ipa_ep_idx = ipa3_get_ep_mapping(client);
+	if (ipa_ep_idx == -1) {
+		IPAERR("Invalid client.\n");
+		WARN_ON(1);
+		return false;
+	}
+
+	ep = &ipa3_ctx->ep[ipa_ep_idx];
+
+	if (ep->keep_ipa_awake)
+		return false;
+
+	if (client == IPA_CLIENT_ODU_EMB_CONS ||
+	    client == IPA_CLIENT_ODU_TETH_CONS)
+		return true;
+
+	return false;
+}
+
+/**
  * ipa3_suspend_resource_sync() - suspend client endpoints related to the IPA_RM
  * resource and decrement active clients counter, which may result in clock
  * gating of IPA clocks.
@@ -1695,6 +1740,19 @@
 				pipe_suspended = true;
 			}
 		}
+
+		if (ipa3_ctx->ep[ipa_ep_idx].client == client &&
+			ipa3_should_pipe_channel_be_stopped(client)) {
+			if (ipa3_ctx->ep[ipa_ep_idx].valid) {
+				/* Stop GSI channel */
+				res = ipa3_stop_gsi_channel(ipa_ep_idx);
+				if (res) {
+					IPAERR("failed stop gsi ch %lu\n",
+					ipa3_ctx->ep[ipa_ep_idx].gsi_chan_hdl);
+					return res;
+				}
+			}
+		}
 	}
 	/* Sleep ~1 msec */
 	if (pipe_suspended)
@@ -1761,6 +1819,12 @@
 				ipa3_cfg_ep_ctrl(ipa_ep_idx, &suspend);
 			}
 		}
+
+		if (ipa3_ctx->ep[ipa_ep_idx].client == client &&
+			ipa3_should_pipe_channel_be_stopped(client)) {
+			res = -EPERM;
+			goto bail;
+		}
 	}
 
 	if (res == 0) {
@@ -1824,6 +1888,19 @@
 				ipa3_cfg_ep_ctrl(ipa_ep_idx, &suspend);
 			}
 		}
+
+		if (ipa3_ctx->ep[ipa_ep_idx].client == client &&
+			ipa3_should_pipe_channel_be_stopped(client)) {
+			if (ipa3_ctx->ep[ipa_ep_idx].valid) {
+				res = gsi_start_channel(
+					ipa3_ctx->ep[ipa_ep_idx].gsi_chan_hdl);
+				if (res) {
+					IPAERR("failed to start gsi ch %lu\n",
+					ipa3_ctx->ep[ipa_ep_idx].gsi_chan_hdl);
+					return res;
+				}
+			}
+		}
 	}
 
 	return res;
@@ -2714,6 +2791,12 @@
 		return -EINVAL;
 	}
 
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0 && ep_ctrl->ipa_ep_suspend) {
+		IPAERR("pipe suspend is not supported\n");
+		WARN_ON(1);
+		return -EPERM;
+	}
+
 	IPADBG("pipe=%d ep_suspend=%d, ep_delay=%d\n",
 		clnt_hdl,
 		ep_ctrl->ipa_ep_suspend,
@@ -4674,6 +4757,7 @@
 	struct ipa_ep_cfg_ctrl cfg;
 	int ipa_ep_idx;
 	struct ipa3_ep_context *ep;
+	int res;
 
 	memset(&cfg, 0, sizeof(cfg));
 	cfg.ipa_ep_suspend = suspend;
@@ -4688,7 +4772,23 @@
 	if (ep->valid) {
 		IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
 			ipa_ep_idx);
-		ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+		if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+			if (suspend) {
+				res = ipa3_stop_gsi_channel(ipa_ep_idx);
+				if (res) {
+					IPAERR("failed to stop LAN channel\n");
+					ipa_assert();
+				}
+			} else {
+				res = gsi_start_channel(ep->gsi_chan_hdl);
+				if (res) {
+					IPAERR("failed to start LAN channel\n");
+					ipa_assert();
+				}
+			}
+		} else {
+			ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+		}
 		if (suspend)
 			ipa3_gsi_poll_after_suspend(ep);
 		else if (!atomic_read(&ep->sys->curr_polling_state))
@@ -4706,7 +4806,23 @@
 	if (ep->valid) {
 		IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
 			ipa_ep_idx);
-		ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+		if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+			if (suspend) {
+				res = ipa3_stop_gsi_channel(ipa_ep_idx);
+				if (res) {
+					IPAERR("failed to stop WAN channel\n");
+					ipa_assert();
+				}
+			} else {
+				res = gsi_start_channel(ep->gsi_chan_hdl);
+				if (res) {
+					IPAERR("failed to start WAN channel\n");
+					ipa_assert();
+				}
+			}
+		} else {
+			ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+		}
 		if (suspend)
 			ipa3_gsi_poll_after_suspend(ep);
 		else if (!atomic_read(&ep->sys->curr_polling_state))
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
index 1a119b9..3019e4d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_reg.c
@@ -688,6 +688,19 @@
 		IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_SHFT);
 }
 
+static void ipareg_construct_endp_init_ctrl_n_v4_0(enum ipahal_reg_name reg,
+	const void *fields, u32 *val)
+{
+	struct ipa_ep_cfg_ctrl *ep_ctrl =
+		(struct ipa_ep_cfg_ctrl *)fields;
+
+	WARN_ON(ep_ctrl->ipa_ep_suspend);
+
+	IPA_SETFIELD_IN_REG(*val, ep_ctrl->ipa_ep_delay,
+		IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_SHFT,
+		IPA_ENDP_INIT_CTRL_n_ENDP_DELAY_BMSK);
+}
+
 static void ipareg_construct_endp_init_ctrl_scnd_n(enum ipahal_reg_name reg,
 	const void *fields, u32 *val)
 {
@@ -1444,6 +1457,9 @@
 		ipareg_parse_hps_queue_weights, 0x000005a4, 0},
 
 	/* IPAv4.0 */
+	[IPA_HW_v4_0][IPA_ENDP_INIT_CTRL_n] = {
+		ipareg_construct_endp_init_ctrl_n_v4_0, ipareg_parse_dummy,
+		0x00000800, 0x70 },
 	[IPA_HW_v4_0][IPA_TX_CFG] = {
 		ipareg_construct_tx_cfg_v4_0, ipareg_parse_tx_cfg_v4_0,
 		0x000001FC, 0},
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index b198348..f408f23 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1507,25 +1507,13 @@
 		break;
 	/*  Flow enable  */
 	case RMNET_IOCTL_FLOW_ENABLE:
-		IPAWANDBG("Received flow enable\n");
-		if (copy_from_user(&ioctl_data, ifr->ifr_ifru.ifru_data,
-			sizeof(struct rmnet_ioctl_data_s))) {
-			rc = -EFAULT;
-			break;
-		}
-		ipa3_flow_control(IPA_CLIENT_USB_PROD, true,
-			ioctl_data.u.tcm_handle);
+		IPAWANERR("RMNET_IOCTL_FLOW_ENABLE not supported\n");
+		rc = -EFAULT;
 		break;
 	/*  Flow disable  */
 	case RMNET_IOCTL_FLOW_DISABLE:
-		IPAWANDBG("Received flow disable\n");
-		if (copy_from_user(&ioctl_data, ifr->ifr_ifru.ifru_data,
-			sizeof(struct rmnet_ioctl_data_s))) {
-			rc = -EFAULT;
-			break;
-		}
-		ipa3_flow_control(IPA_CLIENT_USB_PROD, false,
-			ioctl_data.u.tcm_handle);
+		IPAWANERR("RMNET_IOCTL_FLOW_DISABLE not supported\n");
+		rc = -EFAULT;
 		break;
 	/*  Set flow handle  */
 	case RMNET_IOCTL_FLOW_SET_HNDL:
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 5ca0fe5..306510f 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -34,17 +34,21 @@
 #define RPMH_MAX_REQ_IN_BATCH		10
 
 #define DEFINE_RPMH_MSG_ONSTACK(rc, s, q, c, name)	\
-	struct rpmh_msg name = {		\
-		.msg = { 0 },			\
-		.msg.state = s,			\
-		.msg.is_complete = true,	\
-		.msg.payload = name.cmd,	\
-		.msg.num_payload = 0,		\
-		.cmd = { { 0 } },		\
-		.waitq = q,			\
-		.wait_count = c,		\
-		.rc = rc,			\
-		.bit = -1,			\
+	struct rpmh_msg name = {			\
+		.msg = {				\
+			.state = s,			\
+			.payload = name.cmd,		\
+			.num_payload = 0,		\
+			.is_read = false,		\
+			.is_control = false,		\
+			.is_complete = true,		\
+			.invalidate = false,		\
+		},					\
+		.cmd = { { 0 } },			\
+		.completion = q,			\
+		.wait_count = c,			\
+		.rc = rc,				\
+		.bit = -1,				\
 	}
 
 struct rpmh_req {
@@ -57,7 +61,7 @@
 struct rpmh_msg {
 	struct tcs_mbox_msg msg;
 	struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
-	wait_queue_head_t *waitq;
+	struct completion *completion;
 	atomic_t *wait_count;
 	struct rpmh_client *rc;
 	int bit;
@@ -106,21 +110,31 @@
 	return msg;
 }
 
+static void free_msg_to_pool(struct rpmh_msg *rpm_msg)
+{
+	struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
+	unsigned long flags;
+
+	/* If we allocated the pool, set it as available */
+	if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
+		spin_lock_irqsave(&rpm->lock, flags);
+		bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
+		spin_unlock_irqrestore(&rpm->lock, flags);
+	}
+}
+
 static void rpmh_rx_cb(struct mbox_client *cl, void *msg)
 {
 	struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg);
 
 	atomic_dec(rpm_msg->wait_count);
-	wake_up(rpm_msg->waitq);
 }
 
 static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r)
 {
 	struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg);
-	struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
 	atomic_t *wc = rpm_msg->wait_count;
-	wait_queue_head_t *waitq = rpm_msg->waitq;
-	unsigned long flags;
+	struct completion *compl = rpm_msg->completion;
 
 	rpm_msg->err = r;
 
@@ -144,18 +158,12 @@
 	 * into an issue that the stack allocated parent object may be
 	 * invalid before we can check the ->bit value.
 	 */
-
-	/* If we allocated the pool, set it as available */
-	if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
-		spin_lock_irqsave(&rpm->lock, flags);
-		bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
-		spin_unlock_irqrestore(&rpm->lock, flags);
-	}
+	free_msg_to_pool(rpm_msg);
 
 	/* Signal the blocking thread we are done */
 	if (wc && atomic_dec_and_test(wc))
-		if (waitq)
-			wake_up(waitq);
+		if (compl)
+			complete(compl);
 }
 
 static struct rpmh_req *__find_req(struct rpmh_client *rc, u32 addr)
@@ -312,9 +320,9 @@
 int rpmh_write_single(struct rpmh_client *rc, enum rpmh_state state,
 			u32 addr, u32 data)
 {
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+	DECLARE_COMPLETION_ONSTACK(compl);
 	atomic_t wait_count = ATOMIC_INIT(1);
-	DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg);
+	DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg);
 	int ret;
 
 	if (IS_ERR_OR_NULL(rc))
@@ -333,7 +341,7 @@
 	if (ret < 0)
 		return ret;
 
-	wait_event(waitq, atomic_read(&wait_count) == 0);
+	wait_for_completion(&compl);
 
 	return rpm_msg.err;
 }
@@ -408,9 +416,9 @@
 int rpmh_write(struct rpmh_client *rc, enum rpmh_state state,
 			struct tcs_cmd *cmd, int n)
 {
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+	DECLARE_COMPLETION_ONSTACK(compl);
 	atomic_t wait_count = ATOMIC_INIT(1);
-	DEFINE_RPMH_MSG_ONSTACK(rc, state, &waitq, &wait_count, rpm_msg);
+	DEFINE_RPMH_MSG_ONSTACK(rc, state, &compl, &wait_count, rpm_msg);
 	int ret;
 
 	if (IS_ERR_OR_NULL(rc) || !cmd || n <= 0 || n > MAX_RPMH_PAYLOAD)
@@ -428,7 +436,7 @@
 	if (ret)
 		return ret;
 
-	wait_event(waitq, atomic_read(&wait_count) == 0);
+	wait_for_completion(&compl);
 
 	return rpm_msg.err;
 }
@@ -454,7 +462,7 @@
 			struct tcs_cmd *cmd, int *n)
 {
 	struct rpmh_msg *rpm_msg[RPMH_MAX_REQ_IN_BATCH];
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+	DECLARE_COMPLETION_ONSTACK(compl);
 	atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */
 	int count = 0;
 	int ret, i, j, k;
@@ -507,9 +515,8 @@
 	for (i = 0; i < count; i++) {
 		rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i]);
 		if (IS_ERR_OR_NULL(rpm_msg[i])) {
-			/* Clean up our call by spoofing tx_done */
 			for (j = 0 ; j < i; j++)
-				rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, 0);
+				free_msg_to_pool(rpm_msg[j]);
 			return PTR_ERR(rpm_msg[i]);
 		}
 		cmd += n[i];
@@ -520,7 +527,7 @@
 		might_sleep();
 		atomic_set(&wait_count, count);
 		for (i = 0; i < count; i++) {
-			rpm_msg[i]->waitq = &waitq;
+			rpm_msg[i]->completion = &compl;
 			rpm_msg[i]->wait_count = &wait_count;
 			/* Bypass caching and write to mailbox directly */
 			ret = mbox_send_message(rc->chan, &rpm_msg[i]->msg);
@@ -530,15 +537,17 @@
 				break;
 			}
 		}
-		wait_event(waitq, atomic_read(&wait_count) == (count - i));
+		/* For those unsent requests, spoof tx_done */
+		for (j = i; j < count; j++)
+			rpmh_tx_done(&rc->client, &rpm_msg[j]->msg, ret);
+		wait_for_completion(&compl);
 	} else {
 		/* Send Sleep requests to the controller, expect no response */
 		for (i = 0; i < count; i++) {
-			rpm_msg[i]->waitq = NULL;
+			rpm_msg[i]->completion = NULL;
 			ret = mbox_send_controller_data(rc->chan,
 						&rpm_msg[i]->msg);
-			/* Clean up our call by spoofing tx_done */
-			rpmh_tx_done(&rc->client, &rpm_msg[i]->msg, ret);
+			free_msg_to_pool(rpm_msg[i]);
 		}
 		return 0;
 	}
@@ -660,10 +669,10 @@
 int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp)
 {
 	int ret;
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+	DECLARE_COMPLETION_ONSTACK(compl);
 	atomic_t wait_count = ATOMIC_INIT(2); /* wait for rx_cb and tx_done */
 	DEFINE_RPMH_MSG_ONSTACK(rc, RPMH_ACTIVE_ONLY_STATE,
-				&waitq, &wait_count, rpm_msg);
+				&compl, &wait_count, rpm_msg);
 
 	if (IS_ERR_OR_NULL(rc) || !resp)
 		return -EINVAL;
@@ -684,7 +693,7 @@
 		return ret;
 
 	/* Wait until the response is received from RPMH */
-	wait_event(waitq, atomic_read(&wait_count) == 0);
+	wait_for_completion(&compl);
 
 	/* Read the data back from the tcs_mbox_msg structrure */
 	*resp = rpm_msg.cmd[0].data;
diff --git a/include/dt-bindings/clock/mdss-10nm-pll-clk.h b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
index c1350ce..75ddcfa 100644
--- a/include/dt-bindings/clock/mdss-10nm-pll-clk.h
+++ b/include/dt-bindings/clock/mdss-10nm-pll-clk.h
@@ -34,4 +34,12 @@
 #define PCLK_SRC_MUX_1_CLK	15
 #define PCLK_SRC_1_CLK		16
 #define PCLK_MUX_1_CLK		17
+
+/* DP PLL clocks */
+#define	DP_VCO_CLK	0
+#define	DP_LINK_CLK_DIVSEL_TEN	1
+#define	DP_VCO_DIVIDED_TWO_CLK_SRC	2
+#define	DP_VCO_DIVIDED_FOUR_CLK_SRC	3
+#define	DP_VCO_DIVIDED_SIX_CLK_SRC	4
+#define	DP_VCO_DIVIDED_CLK_SRC_MUX	5
 #endif
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 0583431..8053c8a 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -121,5 +121,6 @@
 int msm_vidc_unsubscribe_event(void *instance,
 		const struct v4l2_event_subscription *sub);
 int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
+int msm_vidc_g_crop(void *instance, struct v4l2_crop *a);
 int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize);
 #endif
diff --git a/include/uapi/media/cam_cpas.h b/include/uapi/media/cam_cpas.h
index 300bd87..c5cbac8 100644
--- a/include/uapi/media/cam_cpas.h
+++ b/include/uapi/media/cam_cpas.h
@@ -11,13 +11,15 @@
  *
  * @camera_family     : Camera family type
  * @reserved          : Reserved field for alignment
- * @camera_version    : Camera version
+ * @camera_version    : Camera platform version
+ * @cpas_version      : Camera CPAS version within camera platform
  *
  */
 struct cam_cpas_query_cap {
 	uint32_t                 camera_family;
 	uint32_t                 reserved;
 	struct cam_hw_version    camera_version;
+	struct cam_hw_version    cpas_version;
 };
 
 #endif /* __UAPI_CAM_CPAS_H__ */
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index c0a32f3..3c026e64 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -795,11 +795,13 @@
 	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
 	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
 	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
+	/* Add 1msec delay for VOUT to settle */
+	usleep_range(1000, 1100);
 	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
 	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
-	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
 	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
 	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
 
 	return 0;
 }
@@ -8274,6 +8276,9 @@
 
 	WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
 	ret = __tavil_cdc_mclk_enable_locked(tavil, enable);
+	if (enable)
+		wcd_resmgr_set_sido_input_src(tavil->resmgr,
+						     SIDO_SOURCE_RCO_BG);
 	WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
 
 	return ret;
@@ -8411,6 +8416,8 @@
 					__func__, ret);
 				goto done;
 			}
+			wcd_resmgr_set_sido_input_src(tavil->resmgr,
+							SIDO_SOURCE_RCO_BG);
 			ret = wcd_resmgr_enable_clk_block(tavil->resmgr,
 							   WCD_CLK_RCO);
 			ret |= tavil_cdc_req_mclk_enable(tavil, false);
@@ -9814,18 +9821,23 @@
 {
 	int val, rc;
 
-	__tavil_cdc_mclk_enable(tavil, true);
+	WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
+	__tavil_cdc_mclk_enable_locked(tavil, true);
 
 	regmap_update_bits(tavil->wcd9xxx->regmap,
 			WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x10);
 	regmap_update_bits(tavil->wcd9xxx->regmap,
 			WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01);
-
 	/*
 	 * 5ms sleep required after enabling efuse control
 	 * before checking the status.
 	 */
 	usleep_range(5000, 5500);
+	wcd_resmgr_set_sido_input_src(tavil->resmgr,
+					     SIDO_SOURCE_RCO_BG);
+
+	WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
+
 	rc = regmap_read(tavil->wcd9xxx->regmap,
 			 WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
 	if (rc || (!(val & 0x01)))
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index 8780888..825aaee 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -25,8 +25,7 @@
 #define WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41
 #define WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42
 
-static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
-					  int sido_src);
+
 static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type)
 {
 	if (clk_type == WCD_CLK_OFF)
@@ -267,8 +266,6 @@
 					0x01, 0x01);
 			wcd_resmgr_codec_reg_update_bits(resmgr,
 					WCD934X_CODEC_RPM_CLK_GATE, 0x03, 0x00);
-			wcd_resmgr_set_sido_input_src(resmgr,
-						      SIDO_SOURCE_RCO_BG);
 		} else {
 			wcd_resmgr_codec_reg_update_bits(resmgr,
 					WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
@@ -515,7 +512,7 @@
 	return ret;
 }
 
-static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
 					  int sido_src)
 {
 	if (!resmgr)
@@ -553,6 +550,7 @@
 		pr_debug("%s: sido input src to external\n", __func__);
 	}
 }
+EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src);
 
 /*
  * wcd_resmgr_set_sido_input_src_locked:
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.h b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
index f605a24..e831ba6 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -87,4 +87,7 @@
 void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr);
 void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr,
 					  int sido_src);
+void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+					  int sido_src);
+
 #endif