Merge "defconfig: sdm670: Enable regmap debugfs write"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
index b3f3431..0d955ed 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_bus.txt
@@ -139,6 +139,7 @@
 			the command DB driver.
 qcom,drv-id:		The DRV id associated with the RSC, used to differentiate
 			between RSCS owned by different execution environments.
+qcom,defer-init-qos:	Flag to force defer initial QoS configuration at probe time.
 
 
 Example:
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index dd668cb..c8cffb5 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -281,6 +281,18 @@
 				core ib calculation.
 - qcom,sde-core-clk-ff:		A string entry indicating the fudge factor for
 				core clock calculation.
+- qcom,sde-min-core-ib-kbps:	This u32 value indicates the minimum mnoc ib
+				vote in Kbps that can be reduced without hitting underflow.
+				BW calculation logic will choose the IB bandwidth requirement
+				based on usecase if this floor value is not defined.
+- qcom,sde-min-llcc-ib-kbps:	This u32 value indicates the minimum llcc ib
+				vote in Kbps that can be reduced without hitting underflow.
+				BW calculation logic will choose the IB bandwidth requirement
+				based on usecase if this floor value is not defined.
+- qcom,sde-min-dram-ib-kbps:	This u32 value indicates the minimum dram ib
+				vote in Kbps that can be reduced without hitting underflow.
+				BW calculation logic will choose the IB bandwidth requirement
+				based on usecase if this floor value is not defined.
 - qcom,sde-comp-ratio-rt:	A string entry indicating the compression ratio
 				for each supported compressed format on realtime interface.
 				The string is composed of one or more of
@@ -572,6 +584,9 @@
 
     qcom,sde-core-ib-ff = "1.1";
     qcom,sde-core-clk-ff = "1.0";
+    qcom,sde-min-core-ib-kbps = <2400000>;
+    qcom,sde-min-llcc-ib-kbps = <800000>;
+    qcom,sde-min-dram-ib-kbps = <800000>;
     qcom,sde-comp-ratio-rt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3";
     qcom,sde-comp-ratio-nrt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3";
     qcom,sde-undersized-prefill-lines = <4>;
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
index e46fd5c..ada2eab 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dp.txt
@@ -10,6 +10,7 @@
 			"dp_mmss_cc" - Display Clock Control memory region.
 			"qfprom_physical" - QFPROM Phys memory region.
 			"dp_pll" - USB3 DP combo PLL memory region.
+			"usb3_dp_com" - USB3 DP PHY combo memory region.
 			"hdcp_physical" - DP HDCP memory region.
 - cell-index:           Specifies the controller instance.
 - clocks:               Clocks required for Display Port operation.
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 0f8dc27..8fcdd82 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -96,6 +96,10 @@
 		  retention. No cache invalidation operations involving asid
 		  may be used.
 
+- qcom,disable-atos:
+		  Some hardware may not have full support for atos debugging
+		  in tandem with other features like power collapse.
+
 - qcom,deferred-regulator-disable-delay : The time delay for deferred regulator
                   disable in ms. In case of unmap call, regulator is
                   enabled/disabled. This may introduce additional delay. For
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 271703f..85b0fe9 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -67,6 +67,9 @@
 			  service.
 - qcom,sysmon-id:	platform device id that sysmon is probed with for the subsystem.
 - qcom,override-acc: Boolean- Present if we need to override the default ACC settings
+- qcom,mss_pdc_offset: Integer- Mandatory if PDC register is specified. It is
+				used to specify which bit in the PDC register
+				corresponds to the modem.
 - qcom,ahb-clk-vote: Boolean- Present if we need to remove the vote for the mss_cfg_ahb
 		     clock after the modem boots up
 - qcom,pnoc-clk-vote: Boolean- Present if the modem needs the PNOC bus to be
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index d0d878b..a3fd951 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -271,6 +271,14 @@
 	Definition: A boolean property that when defined holds SOC at 100% when
 		    the battery is full.
 
+- qcom,linearize-soc
+	Usage:      optional
+	Value type: <empty>
+	Definition: A boolean property that when defined linearizes SOC when
+		    the SOC drops after charge termination monotonically to
+		    improve the user experience. This is applicable only if
+		    "qcom,hold-soc-while-full" is specified.
+
 - qcom,ki-coeff-soc-dischg
 	Usage:      optional
 	Value type: <prop-encoded-array>
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 4901fa0..c3e2cab 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -23,6 +23,8 @@
                           with "phys" attribute, provides phandle to UFS PHY node
 - vdd-hba-supply        : phandle to UFS host controller supply regulator node
 - vcc-supply            : phandle to VCC supply regulator node
+- vcc-voltage-level     : specifies voltage levels for VCC supply.
+                          Should be specified in pairs (min, max), units uV.
 - vccq-supply           : phandle to VCCQ supply regulator node
 - vccq2-supply          : phandle to VCCQ2 supply regulator node
 - vcc-supply-1p8        : For embedded UFS devices, valid VCC range is 1.7-1.95V
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index ff8a523..bde40e0 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -276,6 +276,7 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_USB_BAM=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
 CONFIG_QCOM_SCM=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_MSM_SMEM=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 6965607..c239ca8 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -271,6 +271,7 @@
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_HWSPINLOCK_QCOM=y
+CONFIG_MAILBOX=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
 CONFIG_QCOM_SCM=y
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index f2cf941..bc0c962 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -8,45 +8,54 @@
 		sdm845-mtp-overlay.dtbo \
 		sdm845-qrd-overlay.dtbo \
 		sdm845-qvr-overlay.dtbo \
-		sdm845-v2-cdp-overlay.dtbo \
-		sdm845-v2-mtp-overlay.dtbo \
-		sdm845-v2-qrd-overlay.dtbo \
 		sdm845-4k-panel-mtp-overlay.dtbo \
 		sdm845-4k-panel-cdp-overlay.dtbo \
 		sdm845-4k-panel-qrd-overlay.dtbo \
+		sdm845-v2-cdp-overlay.dtbo \
+		sdm845-v2-mtp-overlay.dtbo \
+		sdm845-v2-qrd-overlay.dtbo \
+		sdm845-v2-4k-panel-mtp-overlay.dtbo \
+		sdm845-v2-4k-panel-cdp-overlay.dtbo \
+		sdm845-v2-4k-panel-qrd-overlay.dtbo \
 		sda845-cdp-overlay.dtbo \
 		sda845-mtp-overlay.dtbo \
 		sda845-qrd-overlay.dtbo \
-		sda845-v2-cdp-overlay.dtbo \
-		sda845-v2-mtp-overlay.dtbo \
-		sda845-v2-qrd-overlay.dtbo \
 		sda845-4k-panel-mtp-overlay.dtbo \
 		sda845-4k-panel-cdp-overlay.dtbo \
 		sda845-4k-panel-qrd-overlay.dtbo \
-		sdm845-interposer-sdm670-cdp-overlay.dtbo \
-		sdm845-interposer-sdm670-mtp-overlay.dtbo
+		sda845-v2-cdp-overlay.dtbo \
+		sda845-v2-mtp-overlay.dtbo \
+		sda845-v2-qrd-overlay.dtbo \
+		sda845-v2-4k-panel-mtp-overlay.dtbo \
+		sda845-v2-4k-panel-cdp-overlay.dtbo \
+		sda845-v2-4k-panel-qrd-overlay.dtbo
 
 sdm845-cdp-overlay.dtbo-base := sdm845.dtb
 sdm845-mtp-overlay.dtbo-base := sdm845.dtb
 sdm845-qrd-overlay.dtbo-base := sdm845.dtb
 sdm845-qvr-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-cdp-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb
-sdm845-v2-qrd-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-qvr-overlay.dtbo-base := sdm845.dtb
 sdm845-4k-panel-mtp-overlay.dtbo-base := sdm845.dtb
 sdm845-4k-panel-cdp-overlay.dtbo-base := sdm845.dtb
 sdm845-4k-panel-qrd-overlay.dtbo-base := sdm845.dtb
+sdm845-v2-cdp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-qrd-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-mtp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-cdp-overlay.dtbo-base := sdm845-v2.dtb
+sdm845-v2-4k-panel-qrd-overlay.dtbo-base := sdm845-v2.dtb
 sda845-cdp-overlay.dtbo-base := sda845.dtb
 sda845-mtp-overlay.dtbo-base := sda845.dtb
 sda845-qrd-overlay.dtbo-base := sda845.dtb
-sda845-v2-cdp-overlay.dtbo-base := sda845-v2.dtb
-sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
-sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
 sda845-4k-panel-mtp-overlay.dtbo-base := sda845.dtb
 sda845-4k-panel-cdp-overlay.dtbo-base := sda845.dtb
 sda845-4k-panel-qrd-overlay.dtbo-base := sda845.dtb
-sdm845-interposer-sdm670-cdp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
-sdm845-interposer-sdm670-mtp-overlay.dtbo-base := sdm845-interposer-sdm670.dtb
+sda845-v2-cdp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-mtp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-qrd-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-4k-panel-mtp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-4k-panel-cdp-overlay.dtbo-base := sda845-v2.dtb
+sda845-v2-4k-panel-qrd-overlay.dtbo-base := sda845-v2.dtb
 else
 dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \
 	sdm845-rumi.dtb \
@@ -71,19 +80,31 @@
 		sdm670-mtp-overlay.dtbo \
 		sdm670-rumi-overlay.dtbo \
 		sdm670-pm660a-cdp-overlay.dtbo \
-		sdm670-pm660a-mtp-overlay.dtbo
+		sdm670-pm660a-mtp-overlay.dtbo \
+		sdm670-external-codec-cdp-overlay.dtbo \
+		sdm670-external-codec-mtp-overlay.dtbo \
+		sdm670-external-codec-pm660a-cdp-overlay.dtbo \
+		sdm670-external-codec-pm660a-mtp-overlay.dtbo
 
 sdm670-cdp-overlay.dtbo-base := sdm670.dtb
 sdm670-mtp-overlay.dtbo-base := sdm670.dtb
 sdm670-rumi-overlay.dtbo-base := sdm670.dtb
 sdm670-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
 sdm670-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
 else
 dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
 	sdm670-mtp.dtb \
 	sdm670-cdp.dtb \
 	sdm670-pm660a-mtp.dtb \
-	sdm670-pm660a-cdp.dtb
+	sdm670-pm660a-cdp.dtb \
+	sdm670-external-codec-cdp.dtb \
+	sdm670-external-codec-mtp.dtb \
+	sdm670-external-codec-pm660a-cdp.dtb \
+	sdm670-external-codec-pm660a-mtp.dtb
 endif
 
 always		:= $(dtb-y)
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 5de0e44..2156a5d 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -21,6 +21,7 @@
 		#iommu-cells = <1>;
 		qcom,dynamic;
 		qcom,use-3-lvl-tables;
+		qcom,disable-atos;
 		#global-interrupts = <2>;
 		qcom,regulator-names = "vdd";
 		vdd-supply = <&gpu_cx_gdsc>;
@@ -62,6 +63,7 @@
 		qcom,skip-init;
 		qcom,use-3-lvl-tables;
 		qcom,no-asid-retention;
+		qcom,disable-atos;
 		#global-interrupts = <1>;
 		#size-cells = <1>;
 		#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 48d68a7..54a05df 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -12,6 +12,7 @@
 
 #include <dt-bindings/spmi/spmi.h>
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/thermal/thermal.h>
 
 &spmi_bus {
 	pm660_0: qcom,pm660@0 {
@@ -58,13 +59,14 @@
 			};
 		};
 
-		qcom,temp-alarm@2400 {
+		pm660_tz: qcom,temp-alarm@2400 {
 			compatible = "qcom,qpnp-temp-alarm";
 			reg = <0x2400 0x100>;
 			interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
 			label = "pm660_tz";
 			qcom,channel-num = <6>;
 			qcom,temp_alarm-vadc = <&pm660_vadc>;
+			#thermal-sensor-cells = <0>;
 		};
 
 		pm660_gpios: pinctrl@c000 {
@@ -358,18 +360,23 @@
 			qcom,pmic-revid = <&pm660_revid>;
 		};
 
-		bcl@4200 {
+		bcl_sensor: bcl@4200 {
 			compatible = "qcom,msm-bcl-lmh";
 			reg = <0x4200 0xff>,
 				<0x4300 0xff>;
 			reg-names = "fg_user_adc",
 					"fg_lmh";
 			interrupts = <0x0 0x42 0x0 IRQ_TYPE_NONE>,
-					<0x0 0x42 0x2 IRQ_TYPE_NONE>;
-			interrupt-names = "bcl-high-ibat-int",
-					"bcl-low-vbat-int";
-			qcom,vbat-polling-delay-ms = <100>;
-			qcom,ibat-polling-delay-ms = <100>;
+					<0x0 0x42 0x1 IRQ_TYPE_NONE>,
+					<0x0 0x42 0x2 IRQ_TYPE_NONE>,
+					<0x0 0x42 0x3 IRQ_TYPE_NONE>,
+					<0x0 0x42 0x4 IRQ_TYPE_NONE>;
+			interrupt-names = "bcl-high-ibat",
+						"bcl-very-high-ibat",
+						"bcl-low-vbat",
+						"bcl-very-low-vbat",
+						"bcl-crit-low-vbat";
+			#thermal-sensor-cells = <1>;
 		};
 	};
 
@@ -456,4 +463,243 @@
 			};
 		};
 	};
+
+	ibat-high {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&bcl_sensor 0>;
+
+		trips {
+			ibat-high {
+				temperature = <4200>;
+				hysteresis = <200>;
+				type = "passive";
+			};
+		};
+	};
+
+	ibat-vhigh {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&bcl_sensor 1>;
+
+		trips {
+			ibat-vhigh {
+				temperature = <4300>;
+				hysteresis = <100>;
+				type = "passive";
+			};
+		};
+	};
+
+	vbat_adc {
+		polling-delay-passive = <100>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_cap";
+		thermal-sensors = <&bcl_sensor 2>;
+		tracks-low;
+
+		trips {
+			pm660_vbat_adc: vbat-adc {
+				temperature = <3300>;
+				hysteresis = <100>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			vbat_map6 {
+				trip = <&pm660_vbat_adc>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			vbat_map7 {
+				trip = <&pm660_vbat_adc>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
+
+	vbat_low {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_cap";
+		thermal-sensors = <&bcl_sensor 3>;
+		tracks-low;
+
+		trips {
+			vbat-low {
+				temperature = <3100>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+	};
+
+	vbat_too_low {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_cap";
+		thermal-sensors = <&bcl_sensor 4>;
+		tracks-low;
+
+		trips {
+			vbat-too-low {
+				temperature = <2900>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+	};
+
+	soc {
+		polling-delay-passive = <100>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_cap";
+		thermal-sensors = <&bcl_sensor 5>;
+		tracks-low;
+
+		trips {
+			pm660_low_soc: low-soc {
+				temperature = <10>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			soc_map6 {
+				trip = <&pm660_low_soc>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			soc_map7 {
+				trip = <&pm660_low_soc>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
+
+	pm660_temp_alarm: pm660_tz {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&pm660_tz>;
+
+		trips {
+			pm660_trip0: pm660-trip0 {
+				temperature = <105000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm660_trip1: pm660-trip1 {
+				temperature = <125000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm660_trip2: pm660-trip2 {
+				temperature = <145000>;
+				hysteresis = <0>;
+				type = "critical";
+			};
+		};
+		cooling-maps {
+			trip0_cpu0 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU0 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu1 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU1 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu2 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU2 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu3 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU3 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu4 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU4 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu5 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU5 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu6 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU6 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip0_cpu7 {
+				trip = <&pm660_trip0>;
+				cooling-device =
+					<&CPU7 (THERMAL_MAX_LIMIT-1)
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			trip1_cpu1 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU1 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu2 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU2 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu3 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU3 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu4 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU4 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu5 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU5 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu6 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU6 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+			trip1_cpu7 {
+				trip = <&pm660_trip1>;
+				cooling-device =
+					<&CPU7 THERMAL_MAX_LIMIT
+						THERMAL_MAX_LIMIT>;
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi
index 771154a..aaf5d05 100644
--- a/arch/arm64/boot/dts/qcom/pm660l.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi
@@ -39,11 +39,12 @@
 				<PON_POWER_OFF_SHUTDOWN>;
 		};
 
-		qcom,temp-alarm@2400 {
+		pm660l_tz: qcom,temp-alarm@2400 {
 			compatible = "qcom,qpnp-temp-alarm";
 			reg = <0x2400 0x100>;
 			interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
 			label = "pm660l_tz";
+			#thermal-sensor-cells = <0>;
 		};
 
 		pm660l_gpios: pinctrl@c000 {
@@ -295,3 +296,29 @@
 		};
 	};
 };
+
+&thermal_zones {
+	pm660l_tz {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm660l_tz>;
+
+		trips {
+			pm660l_trip0: pm660l-trip0 {
+				temperature = <105000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			 pm660l_trip1: pm660l-trip1 {
+				temperature = <125000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			 pm660l_trip2: pm660l-trip2 {
+				temperature = <145000>;
+				hysteresis = <0>;
+				type = "critical";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts
new file mode 100644
index 0000000..9b7449e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-cdp-overlay.dts
@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel CDP";
+	compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <1 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+	connectors = <&sde_rscc &sde_wb>;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+	qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts
new file mode 100644
index 0000000..bb310d3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-mtp-overlay.dts
@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel MTP";
+	compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <8 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+	connectors = <&sde_rscc &sde_wb &sde_dp>;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+	qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts
new file mode 100644
index 0000000..ab61f2e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-4k-panel-qrd-overlay.dts
@@ -0,0 +1,64 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sda845 v2 4K Display Panel QRD";
+	compatible = "qcom,sda845-qrd", "qcom,sda845", "qcom,qrd";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <11 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+	qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+	qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+	qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index 4f40678..d5d4847 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -12,6 +12,31 @@
 
 #include "sdm670-pmic-overlay.dtsi"
 
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm660l_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm660_l1>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm660l_l4>;
+	vccq2-supply = <&pm660_l8>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm660_l1>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
 &qupv3_se9_2uart {
 	status = "disabled";
 };
@@ -35,3 +60,41 @@
 &qupv3_se6_4uart {
 	status = "disabled";
 };
+
+&sdhc_1 {
+	vdd-supply = <&pm660l_l4>;
+	qcom,vdd-voltage-level = <2960000 2960000>;
+	qcom,vdd-current-level = <200 570000>;
+
+	vdd-io-supply = <&pm660_l8>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on  &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm660l_l5>;
+	qcom,vdd-voltage-level = <2960000 2960000>;
+	qcom,vdd-current-level = <200 800000>;
+
+	vdd-io-supply = <&pm660l_l2>;
+	qcom,vdd-io-voltage-level = <1800000 2960000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on &sdc2_data_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+	status = "ok";
+};
+
+&pm660_charger {
+	qcom,batteryless-platform;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts
new file mode 100644
index 0000000..32a8580
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Ext. Audio Codec CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <1 1>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts
new file mode 100644
index 0000000..6a87d3a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-cdp.dts
@@ -0,0 +1,27 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660L Ext. Audio Codec CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,board-id = <1 1>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts
new file mode 100644
index 0000000..970209ca
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Ext. Audio Codec MTP";
+	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <8 1>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts
new file mode 100644
index 0000000..87ac190
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-mtp.dts
@@ -0,0 +1,27 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660L Ext. Audio Codec MTP";
+	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+	qcom,board-id = <8 1>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..48a6066
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp-overlay.dts
@@ -0,0 +1,35 @@
+/* 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Ext. Audio Codec CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <1 1>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts
new file mode 100644
index 0000000..e64d13b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-cdp.dts
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660A Ext. Audio Codec CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,board-id = <1 1>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..8715ddc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp-overlay.dts
@@ -0,0 +1,34 @@
+/* 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Ext. Audio Codec MTP";
+	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <8 1>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts
new file mode 100644
index 0000000..0beaddb3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec-pm660a-mtp.dts
@@ -0,0 +1,28 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-external-codec.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM 670 PM660 + PM660A Ext. Audio Codec MTP";
+	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+	qcom,board-id = <8 1>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
new file mode 100644
index 0000000..6ea92ee
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
@@ -0,0 +1,11 @@
+/* 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.
+ */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index d13aa15..7718bca 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -73,6 +73,7 @@
 
 		/* base addr, size */
 		qcom,gpu-qdss-stm = <0x161c0000 0x40000>;
+		#cooling-cells = <2>;
 
 		clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
 			<&clock_gpucc GPU_CC_CXO_CLK>,
@@ -170,7 +171,7 @@
 				reg = <0>;
 				qcom,gpu-freq = <430000000>;
 				qcom,bus-freq = <11>;
-				qcom,bus-min = <10>;
+				qcom,bus-min = <8>;
 				qcom,bus-max = <11>;
 			};
 
@@ -178,9 +179,9 @@
 			qcom,gpu-pwrlevel@1 {
 				reg = <1>;
 				qcom,gpu-freq = <355000000>;
-				qcom,bus-freq = <9>;
-				qcom,bus-min = <8>;
-				qcom,bus-max = <10>;
+				qcom,bus-freq = <8>;
+				qcom,bus-min = <5>;
+				qcom,bus-max = <9>;
 			};
 
 			/* LOW SVS */
@@ -198,7 +199,7 @@
 				qcom,gpu-freq = <180000000>;
 				qcom,bus-freq = <4>;
 				qcom,bus-min = <3>;
-				qcom,bus-max = <5>;
+				qcom,bus-max = <4>;
 			};
 
 			/* XO */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index 4f40678..0f3a61f 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -12,6 +12,31 @@
 
 #include "sdm670-pmic-overlay.dtsi"
 
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm660l_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm660_l1>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm660l_l4>;
+	vccq2-supply = <&pm660_l8>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm660_l1>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
+
 &qupv3_se9_2uart {
 	status = "disabled";
 };
@@ -35,3 +60,50 @@
 &qupv3_se6_4uart {
 	status = "disabled";
 };
+
+&sdhc_1 {
+	vdd-supply = <&pm660l_l4>;
+	qcom,vdd-voltage-level = <2960000 2960000>;
+	qcom,vdd-current-level = <200 570000>;
+
+	vdd-io-supply = <&pm660_l8>;
+	qcom,vdd-io-always-on;
+	qcom,vdd-io-lpm-sup;
+	qcom,vdd-io-voltage-level = <1800000 1800000>;
+	qcom,vdd-io-current-level = <200 325000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc1_clk_on  &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+	pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+	status = "ok";
+};
+
+&sdhc_2 {
+	vdd-supply = <&pm660l_l5>;
+	qcom,vdd-voltage-level = <2960000 2960000>;
+	qcom,vdd-current-level = <200 800000>;
+
+	vdd-io-supply = <&pm660l_l2>;
+	qcom,vdd-io-voltage-level = <1800000 2960000>;
+	qcom,vdd-io-current-level = <200 22000>;
+
+	pinctrl-names = "active", "sleep";
+	pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on &sdc2_data_on>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+	status = "ok";
+};
+
+&vendor {
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "fg-gen3-batterydata-itech-3000mah.dtsi"
+		#include "fg-gen3-batterydata-ascent-3450mah.dtsi"
+		#include "fg-gen3-batterydata-demo-6000mah.dtsi"
+	};
+};
+
+&pm660_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
index 73df253..a080db4 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
@@ -1196,6 +1196,20 @@
 			};
 		};
 
+		sdc1_rclk_on: sdc1_rclk_on {
+			config {
+				pins = "sdc1_rclk";
+				bias-pull-down; /* pull down */
+			};
+		};
+
+		sdc1_rclk_off: sdc1_rclk_off {
+			config {
+				pins = "sdc1_rclk";
+				bias-pull-down; /* pull down */
+			};
+		};
+
 		sdc2_clk_on: sdc2_clk_on {
 			config {
 				pins = "sdc2_clk";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
index cd8bfba..24d92eb 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -15,6 +15,7 @@
 		compatible = "qcom,qpnp-smb2";
 		#address-cells = <1>;
 		#size-cells = <1>;
+		#cooling-cells = <2>;
 
 		qcom,pmic-revid = <&pm660_revid>;
 
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 1f76288..23792b1 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -96,6 +96,14 @@
 			regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
 			regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
 		};
+
+		mx_cdev: mx-cdev-lvl {
+			compatible = "qcom,regulator-cooling-device";
+			regulator-cdev-supply = <&pm660l_s1_level>;
+			regulator-levels = <RPMH_REGULATOR_LEVEL_NOM
+					RPMH_REGULATOR_LEVEL_OFF>;
+			#cooling-cells = <2>;
+		};
 	};
 
 	/* pm660l S2 - VDD_GFX supply */
@@ -137,6 +145,13 @@
 			regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
 			qcom,min-dropout-voltage-level = <(-1)>;
 		};
+
+		cx_cdev: regulator-cdev {
+			compatible = "qcom,rpmh-reg-cdev";
+			mboxes = <&qmp_aop 0>;
+			qcom,reg-resource-name = "cx";
+			#cooling-cells = <2>;
+		};
 	};
 
 	rpmh-regulator-ldoa1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
index ca9d8c7..4ba16e4 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
@@ -49,6 +49,7 @@
 	/delete-node/ rpmh-regulator-ldoa28;
 	/delete-node/ rpmh-regulator-bobb1;
 	/delete-node/ rpmh-regulator-gfxlvl;
+	/delete-node/ thermal-zones;
 };
 
 #include "sdm670-stub-regulator.dtsi"
@@ -127,6 +128,8 @@
 	qcom,clk-rates = <400000 20000000 25000000 50000000>;
 	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
 
+	/delete-property/qcom,devfreq,freq-table;
+
 	status = "ok";
 };
 
@@ -146,6 +149,8 @@
 	qcom,clk-rates = <400000 20000000 25000000 50000000>;
 	qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50";
 
+	/delete-property/qcom,devfreq,freq-table;
+
 	status = "ok";
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
new file mode 100644
index 0000000..e4993d6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
@@ -0,0 +1,1507 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/thermal/thermal.h>
+
+&clock_cpucc {
+	lmh_dcvs0: qcom,limits-dcvs@0 {
+		compatible = "qcom,msm-hw-limits";
+		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+		qcom,affinity = <0>;
+		#thermal-sensor-cells = <0>;
+	};
+
+	lmh_dcvs1: qcom,limits-dcvs@1 {
+		compatible = "qcom,msm-hw-limits";
+		interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+		qcom,affinity = <1>;
+		#thermal-sensor-cells = <0>;
+	};
+};
+
+&soc {
+	qmi-tmd-devices {
+		compatible = "qcom,qmi_cooling_devices";
+
+		modem {
+			qcom,instance-id = <0x0>;
+
+			modem_pa: modem_pa {
+				qcom,qmi-dev-name = "pa";
+				#cooling-cells = <2>;
+			};
+
+			modem_proc: modem_proc {
+				qcom,qmi-dev-name = "modem";
+				#cooling-cells = <2>;
+			};
+
+			modem_current: modem_current {
+				qcom,qmi-dev-name = "modem_current";
+				#cooling-cells = <2>;
+			};
+
+			modem_vdd: modem_vdd {
+				qcom,qmi-dev-name = "cpuv_restriction_cold";
+				#cooling-cells = <2>;
+			};
+		};
+
+		adsp {
+			qcom,instance-id = <0x1>;
+
+			adsp_vdd: adsp_vdd {
+				qcom,qmi-dev-name = "cpuv_restriction_cold";
+				#cooling-cells = <2>;
+			};
+		};
+
+		cdsp {
+			qcom,instance-id = <0x43>;
+
+			cdsp_vdd: cdsp_vdd {
+				qcom,qmi-dev-name = "cpuv_restriction_cold";
+				#cooling-cells = <2>;
+			};
+		};
+	};
+};
+
+&thermal_zones {
+	aoss0-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "user_space";
+		thermal-sensors = <&tsens0 0>;
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpu0-silver-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "user_space";
+		thermal-sensors = <&tsens0 1>;
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpu1-silver-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "user_space";
+		thermal-sensors = <&tsens0 2>;
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpu2-silver-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "user_space";
+		thermal-sensors = <&tsens0 3>;
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpu3-silver-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 4>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpu4-silver-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 5>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpu5-silver-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 6>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	kryo-l3-0-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 7>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	kryo-l3-1-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 8>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpu0-gold-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 9>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	cpu1-gold-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 10>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	gpu0-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens0 11>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	gpu1-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "user_space";
+		thermal-sensors = <&tsens0 12>;
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	aoss1-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 0>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	mdm-dsp-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 1>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	ddr-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 2>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	wlan-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 3>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	compute-hvx-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 4>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	camera-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 5>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	mmss-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 6>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	mdm-core-usr {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 7>;
+		thermal-governor = "user_space";
+		trips {
+			active-config0 {
+				temperature = <125000>;
+				hysteresis = <1000>;
+				type = "passive";
+			};
+		};
+	};
+
+	gpu-virt-max-step {
+		polling-delay-passive = <10>;
+		polling-delay = <100>;
+		thermal-governor = "step_wise";
+		trips {
+			gpu_trip0: gpu-trip0 {
+				temperature = <95000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			gpu_cdev0 {
+				trip = <&gpu_trip0>;
+				cooling-device =
+					<&msm_gpu THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+			};
+		};
+	};
+
+	hexa-silv-max-step {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		trips {
+			silver-trip {
+				temperature = <120000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+	};
+
+	dual-gold-max-step {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		trips {
+			gold-trip {
+				temperature = <120000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+	};
+
+	pop-mem-step {
+		polling-delay-passive = <10>;
+		polling-delay = <0>;
+		thermal-sensors = <&tsens1 2>;
+		thermal-governor = "step_wise";
+		trips {
+			pop_trip: pop-trip {
+				temperature = <95000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			pop_cdev6 {
+				trip = <&pop_trip>;
+				cooling-device =
+					<&CPU6 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+			pop_cdev7 {
+				trip = <&pop_trip>;
+				cooling-device =
+					<&CPU7 THERMAL_NO_LIMIT
+						(THERMAL_MAX_LIMIT-1)>;
+			};
+		};
+	};
+
+	aoss0-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 0>;
+		tracks-low;
+		trips {
+			aoss0_trip: aoss0-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	cpu0-silver-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 1>;
+		tracks-low;
+		trips {
+			cpu0_trip: cpu0-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	cpu1-silver-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 2>;
+		tracks-low;
+		trips {
+			cpu1_trip: cpu1-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	cpu2-silver-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 3>;
+		tracks-low;
+		trips {
+			cpu2_trip: cpu2-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	cpu3-silver-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 4>;
+		tracks-low;
+		trips {
+			cpu3_trip: cpu3-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	cpu4-silver-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 5>;
+		tracks-low;
+		trips {
+			cpu4_trip: cpu4-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu4_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&cpu4_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&cpu4_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&cpu4_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&cpu4_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&cpu4_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&cpu4_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	cpu5-silver-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 6>;
+		tracks-low;
+		trips {
+			cpu5_trip: cpu5-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpu5_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&cpu5_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&cpu5_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&cpu5_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&cpu5_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&cpu5_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&cpu5_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	kryo-l3-0-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 7>;
+		tracks-low;
+		trips {
+			l3_0_trip: l3-0-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&l3_0_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&l3_0_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&l3_0_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&l3_0_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&l3_0_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&l3_0_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&l3_0_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	kryo-l3-1-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 8>;
+		tracks-low;
+		trips {
+			l3_1_trip: l3-1-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&l3_1_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&l3_1_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&l3_1_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&l3_1_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&l3_1_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&l3_1_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&l3_1_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	cpu0-gold-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 9>;
+		tracks-low;
+		trips {
+			cpug0_trip: cpug0-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpug0_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&cpug0_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&cpug0_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&cpug0_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&cpug0_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&cpug0_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&cpug0_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	cpu1-gold-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 10>;
+		tracks-low;
+		trips {
+			cpug1_trip: cpug1-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&cpug1_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&cpug1_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&cpug1_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&cpug1_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&cpug1_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&cpug1_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&cpug1_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	gpu0-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 11>;
+		tracks-low;
+		trips {
+			gpu0_trip_l: gpu0-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&gpu0_trip_l>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&gpu0_trip_l>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&gpu0_trip_l>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&gpu0_trip_l>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&gpu0_trip_l>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&gpu0_trip_l>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&gpu0_trip_l>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	gpu1-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens0 12>;
+		tracks-low;
+		trips {
+			gpu1_trip_l: gpu1-trip_l {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&gpu1_trip_l>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&gpu1_trip_l>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&gpu1_trip_l>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&gpu1_trip_l>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&gpu1_trip_l>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&gpu1_trip_l>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&gpu1_trip_l>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	aoss1-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens1 0>;
+		tracks-low;
+		trips {
+			aoss1_trip: aoss1-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&aoss1_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&aoss1_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&aoss1_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&aoss1_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&aoss1_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&aoss1_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&aoss1_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	mdm-dsp-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens1 1>;
+		tracks-low;
+		trips {
+			dsp_trip: dsp-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&dsp_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&dsp_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&dsp_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&dsp_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&dsp_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&dsp_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&dsp_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	ddr-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens1 2>;
+		tracks-low;
+		trips {
+			ddr_trip: ddr-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&ddr_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&ddr_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&ddr_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&ddr_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&ddr_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&ddr_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&ddr_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	wlan-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens1 3>;
+		tracks-low;
+		trips {
+			wlan_trip: wlan-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&wlan_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&wlan_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&wlan_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&wlan_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&wlan_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&wlan_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&wlan_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	compute-hvx-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens1 4>;
+		tracks-low;
+		trips {
+			hvx_trip: hvx-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&hvx_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&hvx_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&hvx_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&hvx_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&hvx_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&hvx_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&hvx_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	camera-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens1 5>;
+		tracks-low;
+		trips {
+			camera_trip: camera-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	mmss-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens1 6>;
+		tracks-low;
+		trips {
+			mmss_trip: mmss-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&mmss_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&mmss_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&mmss_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&mmss_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&mmss_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&mmss_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&mmss_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	mdm-core-lowf {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "low_limits_floor";
+		thermal-sensors = <&tsens1 7>;
+		tracks-low;
+		trips {
+			mdm_trip: mdm-trip {
+				temperature = <5000>;
+				hysteresis = <5000>;
+				type = "passive";
+			};
+		};
+		cooling-maps {
+			cpu0_vdd_cdev {
+				trip = <&mdm_trip>;
+				cooling-device = <&CPU0 4 4>;
+			};
+			cpu6_vdd_cdev {
+				trip = <&mdm_trip>;
+				cooling-device = <&CPU6 9 9>;
+			};
+			gpu_vdd_cdev {
+				trip = <&aoss0_trip>;
+				cooling-device = <&msm_gpu 1 1>;
+			};
+			cx_vdd_cdev {
+				trip = <&mdm_trip>;
+				cooling-device = <&cx_cdev 0 0>;
+			};
+			mx_vdd_cdev {
+				trip = <&mdm_trip>;
+				cooling-device = <&mx_cdev 0 0>;
+			};
+			modem_vdd_cdev {
+				trip = <&mdm_trip>;
+				cooling-device = <&modem_vdd 0 0>;
+			};
+			adsp_vdd_cdev {
+				trip = <&mdm_trip>;
+				cooling-device = <&adsp_vdd 0 0>;
+			};
+			cdsp_vdd_cdev {
+				trip = <&mdm_trip>;
+				cooling-device = <&cdsp_vdd 0 0>;
+			};
+		};
+	};
+
+	lmh-dcvs-01 {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "user_space";
+		thermal-sensors = <&lmh_dcvs1>;
+
+		trips {
+			active-config {
+				temperature = <95000>;
+				hysteresis = <30000>;
+				type = "passive";
+			};
+		};
+	};
+
+	lmh-dcvs-00 {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "user_space";
+		thermal-sensors = <&lmh_dcvs0>;
+
+		trips {
+			active-config {
+				temperature = <95000>;
+				hysteresis = <30000>;
+				type = "passive";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
index bd35cf2..1064a16 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
@@ -17,9 +17,18 @@
 	/delete-node/ ssusb@a800000;
 	/delete-node/ qusb@88e3000;
 	/delete-node/ ssphy@88eb000;
+	/delete-node/ usb_audio_qmi_dev;
+	usb_audio_qmi_dev {
+		compatible = "qcom,usb-audio-qmi-dev";
+		iommus = <&apps_smmu 0x180f 0x0>;
+		qcom,usb-audio-stream-id = <0xf>;
+		qcom,usb-audio-intr-num = <2>;
+	};
 };
 
 &usb0 {
+	/delete-property/ iommus;
+	/delete-property/ qcom,smmu-s1-bypass;
 	extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
 };
 
@@ -30,6 +39,6 @@
 };
 
 &usb_qmp_dp_phy {
-	vdd-supply = <&pm660_l1>;
-	core-supply = <&pm660l_l1>;
+	vdd-supply = <&pm660l_l1>; /* 0.88v */
+	core-supply = <&pm660_l1>; /* 1.2v */
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 692d75f..3ada991 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -53,6 +53,8 @@
 			cache-size = <0x8000>;
 			cpu-release-addr = <0x0 0x90000000>;
 			next-level-cache = <&L2_0>;
+			qcom,lmh-dcvs = <&lmh_dcvs0>;
+			#cooling-cells = <2>;
 			L2_0: l2-cache {
 				compatible = "arm,arch-cache";
 				cache-size = <0x20000>;
@@ -86,6 +88,8 @@
 			cache-size = <0x8000>;
 			cpu-release-addr = <0x0 0x90000000>;
 			next-level-cache = <&L2_100>;
+			qcom,lmh-dcvs = <&lmh_dcvs0>;
+			#cooling-cells = <2>;
 			L2_100: l2-cache {
 				compatible = "arm,arch-cache";
 				cache-size = <0x20000>;
@@ -114,6 +118,8 @@
 			cache-size = <0x8000>;
 			cpu-release-addr = <0x0 0x90000000>;
 			next-level-cache = <&L2_200>;
+			qcom,lmh-dcvs = <&lmh_dcvs0>;
+			#cooling-cells = <2>;
 			L2_200: l2-cache {
 				compatible = "arm,arch-cache";
 				cache-size = <0x20000>;
@@ -142,6 +148,8 @@
 			cache-size = <0x8000>;
 			cpu-release-addr = <0x0 0x90000000>;
 			next-level-cache = <&L2_300>;
+			qcom,lmh-dcvs = <&lmh_dcvs0>;
+			#cooling-cells = <2>;
 			L2_300: l2-cache {
 				compatible = "arm,arch-cache";
 				cache-size = <0x20000>;
@@ -170,6 +178,8 @@
 			cache-size = <0x8000>;
 			cpu-release-addr = <0x0 0x90000000>;
 			next-level-cache = <&L2_400>;
+			qcom,lmh-dcvs = <&lmh_dcvs0>;
+			#cooling-cells = <2>;
 			L2_400: l2-cache {
 				compatible = "arm,arch-cache";
 				cache-size = <0x20000>;
@@ -198,6 +208,8 @@
 			cache-size = <0x8000>;
 			cpu-release-addr = <0x0 0x90000000>;
 			next-level-cache = <&L2_500>;
+			qcom,lmh-dcvs = <&lmh_dcvs0>;
+			#cooling-cells = <2>;
 			L2_500: l2-cache {
 				compatible = "arm,arch-cache";
 				cache-size = <0x20000>;
@@ -226,6 +238,8 @@
 			cache-size = <0x10000>;
 			cpu-release-addr = <0x0 0x90000000>;
 			next-level-cache = <&L2_600>;
+			qcom,lmh-dcvs = <&lmh_dcvs1>;
+			#cooling-cells = <2>;
 			L2_600: l2-cache {
 				compatible = "arm,arch-cache";
 				cache-size = <0x40000>;
@@ -254,6 +268,8 @@
 			cache-size = <0x10000>;
 			cpu-release-addr = <0x0 0x90000000>;
 			next-level-cache = <&L2_700>;
+			qcom,lmh-dcvs = <&lmh_dcvs1>;
+			#cooling-cells = <2>;
 			L2_700: l2-cache {
 				compatible = "arm,arch-cache";
 				cache-size = <0x40000>;
@@ -439,6 +455,12 @@
 			size = <0 0x5c00000>;
 		};
 
+		dump_mem: mem_dump_region {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0 0x2400000>;
+		};
+
 		/* global autoconfigured region for contiguous allocations */
 		linux,cma {
 			compatible = "shared-dma-pool";
@@ -490,301 +512,7 @@
 		qcom,pipe-attr-ee;
 	};
 
-	thermal_zones: thermal-zones {
-		aoss0-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-governor = "user_space";
-			thermal-sensors = <&tsens0 0>;
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		cpu0-silver-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-governor = "user_space";
-			thermal-sensors = <&tsens0 1>;
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		cpu1-silver-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-governor = "user_space";
-			thermal-sensors = <&tsens0 2>;
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		cpu2-silver-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-governor = "user_space";
-			thermal-sensors = <&tsens0 3>;
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		cpu3-silver-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens0 4>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		cpu4-silver-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens0 5>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		cpu5-silver-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens0 6>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		kryo-l3-0-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens0 7>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		kryo-l3-1-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens0 8>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		cpu0-gold-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens0 9>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		cpu1-gold-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens0 10>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		gpu0-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens0 11>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		gpu1-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-governor = "user_space";
-			thermal-sensors = <&tsens0 12>;
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		aoss1-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens1 0>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		mdm-dsp-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens1 1>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		ddr-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens1 2>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		wlan-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens1 3>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		compute-hvx-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens1 4>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		camera-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens1 5>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		mmss-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens1 6>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-
-		mdm-core-usr {
-			polling-delay-passive = <0>;
-			polling-delay = <0>;
-			thermal-sensors = <&tsens1 7>;
-			thermal-governor = "user_space";
-			trips {
-				active-config0 {
-					temperature = <125000>;
-					hysteresis = <1000>;
-					type = "passive";
-				};
-			};
-		};
-	};
+	thermal_zones: thermal-zones {};
 
 	tsens0: tsens@c222000 {
 		compatible = "qcom,tsens24xx";
@@ -881,53 +609,88 @@
 	};
 
 	clock_rpmh: qcom,rpmhclk {
-		compatible = "qcom,dummycc";
-		clock-output-names = "rpmh_clocks";
+		compatible = "qcom,rpmh-clk-sdm670";
 		#clock-cells = <1>;
+		mboxes = <&apps_rsc 0>;
+		mbox-names = "apps";
 	};
 
 	clock_gcc: qcom,gcc@100000 {
-		compatible = "qcom,dummycc";
-		clock-output-names = "gcc_clocks";
+		compatible = "qcom,gcc-sdm670", "syscon";
+		reg = <0x100000 0x1f0000>;
+		reg-names = "cc_base";
+		vdd_cx-supply = <&pm660l_s3_level>;
+		vdd_cx_ao-supply = <&pm660l_s3_level_ao>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
 
 	clock_videocc: qcom,videocc@ab00000 {
-		compatible = "qcom,dummycc";
-		clock-output-names = "videocc_clocks";
+		compatible = "qcom,video_cc-sdm670", "syscon";
+		reg = <0xab00000 0x10000>;
+		reg-names = "cc_base";
+		vdd_cx-supply = <&pm660l_s3_level>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
 
 	clock_camcc: qcom,camcc@ad00000 {
-		compatible = "qcom,dummycc";
-		clock-output-names = "camcc_clocks";
+		compatible = "qcom,cam_cc-sdm670", "syscon";
+		reg = <0xad00000 0x10000>;
+		reg-names = "cc_base";
+		vdd_cx-supply = <&pm660l_s3_level>;
+		vdd_mx-supply = <&pm660l_s1_level>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
 
 	clock_dispcc: qcom,dispcc@af00000 {
-		compatible = "qcom,dummycc";
-		clock-output-names = "dispcc_clocks";
+		compatible = "qcom,dispcc-sdm670", "syscon";
+		reg = <0xaf00000 0x10000>;
+		reg-names = "cc_base";
+		vdd_cx-supply = <&pm660l_s3_level>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
 
 	clock_gpucc: qcom,gpucc@5090000 {
-		compatible = "qcom,dummycc";
-		clock-output-names = "gpucc_clocks";
+		compatible = "qcom,gpucc-sdm670", "syscon";
+		reg = <0x5090000 0x9000>;
+		reg-names = "cc_base";
+		vdd_cx-supply = <&pm660l_s3_level>;
+		vdd_mx-supply = <&pm660l_s1_level>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
 
 	clock_gfx: qcom,gfxcc@5090000  {
-		compatible = "qcom,dummycc";
-		clock-output-names = "gfxcc_clocks";
+		compatible = "qcom,gfxcc-sdm670";
+		reg = <0x5090000 0x9000>;
+		reg-names = "cc_base";
+		vdd_gfx-supply = <&pm660l_s2_level>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
 	};
 
+	cpucc_debug: syscon@17970018 {
+		compatible = "syscon";
+		reg = <0x17970018 0x4>;
+	};
+
+	clock_debug: qcom,cc-debug {
+		compatible = "qcom,debugcc-sdm845";
+		qcom,cc-count = <5>;
+		qcom,gcc = <&clock_gcc>;
+		qcom,videocc = <&clock_videocc>;
+		qcom,camcc = <&clock_camcc>;
+		qcom,dispcc = <&clock_dispcc>;
+		qcom,gpucc = <&clock_gpucc>;
+		qcom,cpucc = <&cpucc_debug>;
+		clock-names = "xo_clk_src";
+		clocks = <&clock_rpmh RPMH_CXO_CLK>;
+		#clock-cells = <1>;
+	};
+
 	clock_cpucc: qcom,cpucc {
 		compatible = "qcom,dummycc";
 		clock-output-names = "cpucc_clocks";
@@ -953,6 +716,16 @@
 		qcom,apps-ch-pipes = <0x780000>;
 		qcom,ea-pc = <0x290>;
 		status = "disabled";
+		qcom,iommu-s1-bypass;
+
+		iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb {
+			compatible = "qcom,iommu-slim-ctrl-cb";
+			iommus = <&apps_smmu 0x1826 0x0>,
+				 <&apps_smmu 0x182d 0x0>,
+				 <&apps_smmu 0x182e 0x1>,
+				 <&apps_smmu 0x1830 0x1>;
+		};
+
 	};
 
 	slim_qca: slim@62e40000 {
@@ -964,6 +737,13 @@
 		interrupts = <0 291 0>, <0 292 0>;
 		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
 		status = "disabled";
+		qcom,iommu-s1-bypass;
+
+		iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb {
+			compatible = "qcom,iommu-slim-ctrl-cb";
+			iommus = <&apps_smmu 0x1833 0x0>;
+		};
+
 	};
 
 	wdog: qcom,wdt@17980000{
@@ -1160,6 +940,61 @@
 		};
 	};
 
+	mem_dump {
+		compatible = "qcom,mem-dump";
+		memory-region = <&dump_mem>;
+
+		rpmh_dump {
+			qcom,dump-size = <0x2000000>;
+			qcom,dump-id = <0xec>;
+		};
+
+		rpm_sw_dump {
+			qcom,dump-size = <0x28000>;
+			qcom,dump-id = <0xea>;
+		};
+
+		pmic_dump {
+			qcom,dump-size = <0x10000>;
+			qcom,dump-id = <0xe4>;
+		};
+
+		tmc_etf_dump {
+			qcom,dump-size = <0x10000>;
+			qcom,dump-id = <0xf0>;
+		};
+
+		tmc_etf_swao_dump {
+			qcom,dump-size = <0x8400>;
+			qcom,dump-id = <0xf1>;
+		};
+
+		tmc_etr_reg_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0x100>;
+		};
+
+		tmc_etf_reg_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0x101>;
+		};
+
+		tmc_etf_swao_reg_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0x102>;
+		};
+
+		misc_data_dump {
+			qcom,dump-size = <0x1000>;
+			qcom,dump-id = <0xe8>;
+		};
+
+		power_regs_data_dump {
+			qcom,dump-size = <0x100000>;
+			qcom,dump-id = <0xed>;
+		};
+	};
+
 	kryo3xx-erp {
 		compatible = "arm,arm64-kryo3xx-cpu-erp";
 		interrupts = <1 6 4>,
@@ -1574,6 +1409,44 @@
 			<0 0>,
 			<0 0>;
 
+		qcom,msm-bus,name = "ufshc_mem";
+		qcom,msm-bus,num-cases = <12>;
+		qcom,msm-bus,num-paths = <2>;
+		qcom,msm-bus,vectors-KBps =
+		/*
+		 * During HS G3 UFS runs at nominal voltage corner, vote
+		 * higher bandwidth to push other buses in the data path
+		 * to run at nominal to achieve max throughput.
+		 * 4GBps pushes BIMC to run at nominal.
+		 * 200MBps pushes CNOC to run at nominal.
+		 * Vote for half of this bandwidth for HS G3 1-lane.
+		 * For max bandwidth, vote high enough to push the buses
+		 * to run in turbo voltage corner.
+		 */
+		<123 512 0 0>, <1 757 0 0>,          /* No vote */
+		<123 512 922 0>, <1 757 1000 0>,     /* PWM G1 */
+		<123 512 1844 0>, <1 757 1000 0>,    /* PWM G2 */
+		<123 512 3688 0>, <1 757 1000 0>,    /* PWM G3 */
+		<123 512 7376 0>, <1 757 1000 0>,    /* PWM G4 */
+		<123 512 127796 0>, <1 757 1000 0>,  /* HS G1 RA */
+		<123 512 255591 0>, <1 757 1000 0>,  /* HS G2 RA */
+		<123 512 2097152 0>, <1 757 102400 0>,  /* HS G3 RA */
+		<123 512 149422 0>, <1 757 1000 0>,  /* HS G1 RB */
+		<123 512 298189 0>, <1 757 1000 0>,  /* HS G2 RB */
+		<123 512 2097152 0>, <1 757 102400 0>,  /* HS G3 RB */
+		<123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */
+
+		qcom,bus-vector-names = "MIN",
+		"PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1",
+		"HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1",
+		"HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1",
+		"MAX";
+
+		/* PM QoS */
+		qcom,pm-qos-cpu-groups = <0x3f 0xC0>;
+		qcom,pm-qos-cpu-group-latency-us = <70 70>;
+		qcom,pm-qos-default-cpu = <0>;
+
 		resets = <&clock_gcc GCC_UFS_PHY_BCR>;
 		reset-names = "core_reset";
 
@@ -1817,6 +1690,7 @@
 		qcom,ssctl-instance-id = <0x12>;
 		qcom,override-acc;
 		qcom,qdsp6v65-1-0;
+		qcom,mss_pdc_offset = <8>;
 		status = "ok";
 		memory-region = <&pil_modem_mem>;
 		qcom,mem-protect-id = <0xF>;
@@ -1905,6 +1779,12 @@
 		qcom,bus-width = <8>;
 		qcom,large-address-bus;
 
+		qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+						192000000 384000000>;
+		qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+		qcom,devfreq,freq-table = <50000000 200000000>;
+
 		clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>,
 			<&clock_gcc GCC_SDCC1_APPS_CLK>;
 		clock-names = "iface_clk", "core_clk";
@@ -1926,6 +1806,12 @@
 		qcom,bus-width = <4>;
 		qcom,large-address-bus;
 
+		qcom,clk-rates = <400000 20000000 25000000
+					50000000 100000000 201500000>;
+		qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50",
+				      "SDR104";
+
+		qcom,devfreq,freq-table = <50000000 201500000>;
 		clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>,
 			<&clock_gcc GCC_SDCC2_APPS_CLK>;
 		clock-names = "iface_clk", "core_clk";
@@ -2015,6 +1901,26 @@
 			dma-coherent;
 		};
 	};
+
+	qcom,icnss@18800000 {
+		status = "disabled";
+		compatible = "qcom,icnss";
+		reg = <0x18800000 0x800000>;
+		interrupts = <0 414 0 /* CE0 */ >,
+			     <0 415 0 /* CE1 */ >,
+			     <0 416 0 /* CE2 */ >,
+			     <0 417 0 /* CE3 */ >,
+			     <0 418 0 /* CE4 */ >,
+			     <0 419 0 /* CE5 */ >,
+			     <0 420 0 /* CE6 */ >,
+			     <0 421 0 /* CE7 */ >,
+			     <0 422 0 /* CE8 */ >,
+			     <0 423 0 /* CE9 */ >,
+			     <0 424 0 /* CE10 */ >,
+			     <0 425 0 /* CE11 */ >;
+		qcom,wlan-msa-memory = <0x100000>;
+		qcom,smmu-s1-bypass;
+	};
 };
 
 #include "sdm670-pinctrl.dtsi"
@@ -2114,3 +2020,4 @@
 #include "sdm670-audio.dtsi"
 #include "sdm670-usb.dtsi"
 #include "sdm670-gpu.dtsi"
+#include "sdm670-thermal.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index 5fbb1db..646dbad 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -645,7 +645,10 @@
 			qcom,qport = <2>;
 			qcom,connections = <&slv_qns_a2noc_snoc>;
 			qcom,bus-dev = <&fab_aggre2_noc>;
+			qcom,ap-owned;
 			qcom,prio = <2>;
+			qcom,defer-init-qos;
+			qcom,node-qos-bcms = <7035 0 1>;
 		};
 
 		mas_xm_pcie3_1: mas-xm-pcie3-1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index dddf1fb..fe19658 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -110,6 +110,7 @@
 	vdd-hba-supply = <&ufs_phy_gdsc>;
 	vdd-hba-fixed-regulator;
 	vcc-supply = <&pm8998_l20>;
+	vcc-voltage-level = <2950000 2960000>;
 	vccq2-supply = <&pm8998_s4>;
 	vcc-max-microamp = <600000>;
 	vccq2-max-microamp = <600000>;
@@ -146,6 +147,7 @@
 	vdd-hba-supply = <&ufs_card_gdsc>;
 	vdd-hba-fixed-regulator;
 	vcc-supply = <&pm8998_l21>;
+	vcc-voltage-level = <2950000 2960000>;
 	vccq2-supply = <&pm8998_s4>;
 	vcc-max-microamp = <300000>;
 	vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
index ad15615..e435cdd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
@@ -13,3 +13,28 @@
 #include "sdm845-cdp.dtsi"
 #include "sdm845-interposer-pm660.dtsi"
 #include "sdm845-interposer-sdm670-audio.dtsi"
+
+&soc {
+	/delete-node/ ssusb@a800000;
+	/delete-node/ qusb@88e3000;
+	/delete-node/ ssphy@88eb000;
+};
+
+&usb0 {
+	extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+};
+
+&qusb_phy0 {
+	vdd-supply = <&pm660l_l1>;
+	vdda18-supply = <&pm660_l10>;
+	vdda33-supply = <&pm660l_l7>;
+};
+
+&usb_qmp_dp_phy {
+	vdd-supply = <&pm660l_l1>; /* 0.88v */
+	core-supply = <&pm660_l1>; /* 1.2v */
+};
+
+&pcie0 {
+	status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
index c709770..4b24b0d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
@@ -16,4 +16,30 @@
 
 &qupv3_se10_i2c {
 	/delete-node/ qcom,smb1355@8;
+	/delete-node/ qcom,smb1355@c;
+};
+
+&soc {
+	/delete-node/ ssusb@a800000;
+	/delete-node/ qusb@88e3000;
+	/delete-node/ ssphy@88eb000;
+};
+
+&usb0 {
+	extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+};
+
+&qusb_phy0 {
+	vdd-supply = <&pm660l_l1>;
+	vdda18-supply = <&pm660_l10>;
+	vdda33-supply = <&pm660l_l7>;
+};
+
+&usb_qmp_dp_phy {
+	vdd-supply = <&pm660l_l1>; /* 0.88v */
+	core-supply = <&pm660_l1>; /* 1.2v */
+};
+
+&pcie0 {
+	status = "disabled";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index 3d58dc1..3756197 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -198,6 +198,7 @@
 	vdd-hba-supply = <&ufs_phy_gdsc>;
 	vdd-hba-fixed-regulator;
 	vcc-supply = <&pm8998_l20>;
+	vcc-voltage-level = <2950000 2960000>;
 	vccq2-supply = <&pm8998_s4>;
 	vcc-max-microamp = <600000>;
 	vccq2-max-microamp = <600000>;
@@ -234,6 +235,7 @@
 	vdd-hba-supply = <&ufs_card_gdsc>;
 	vdd-hba-fixed-regulator;
 	vcc-supply = <&pm8998_l21>;
+	vcc-voltage-level = <2950000 2960000>;
 	vccq2-supply = <&pm8998_s4>;
 	vcc-max-microamp = <300000>;
 	vccq2-max-microamp = <300000>;
@@ -291,7 +293,11 @@
 	qcom,battery-data = <&mtp_batterydata>;
 };
 
-&smb1355_charger {
+&smb1355_charger_0 {
+	status = "ok";
+};
+
+&smb1355_charger_1 {
 	status = "ok";
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 6122eee..02f30fd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -88,7 +88,11 @@
 	qcom,fg-bmd-en-delay-ms = <300>;
 };
 
-&smb1355_charger {
+&smb1355_charger_0 {
+	status = "ok";
+};
+
+&smb1355_charger_1 {
 	status = "ok";
 };
 
@@ -111,6 +115,7 @@
 	vdd-hba-supply = <&ufs_phy_gdsc>;
 	vdd-hba-fixed-regulator;
 	vcc-supply = <&pm8998_l20>;
+	vcc-voltage-level = <2950000 2960000>;
 	vccq2-supply = <&pm8998_s4>;
 	vcc-max-microamp = <600000>;
 	vccq2-max-microamp = <600000>;
@@ -147,6 +152,7 @@
 	vdd-hba-supply = <&ufs_card_gdsc>;
 	vdd-hba-fixed-regulator;
 	vcc-supply = <&pm8998_l21>;
+	vcc-voltage-level = <2950000 2960000>;
 	vccq2-supply = <&pm8998_s4>;
 	vcc-max-microamp = <300000>;
 	vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
index 6ea92ee..0da0e67 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
@@ -9,3 +9,28 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
+&ufsphy_mem {
+	compatible = "qcom,ufs-phy-qmp-v3";
+
+	vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+	vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+	vdda-phy-max-microamp = <62900>;
+	vdda-pll-max-microamp = <18300>;
+
+	status = "ok";
+};
+
+&ufshc_mem {
+	vdd-hba-supply = <&ufs_phy_gdsc>;
+	vdd-hba-fixed-regulator;
+	vcc-supply = <&pm8998_l20>;
+	vccq2-supply = <&pm8998_s4>;
+	vcc-max-microamp = <600000>;
+	vccq2-max-microamp = <600000>;
+
+	qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+	qcom,vddp-ref-clk-max-microamp = <100>;
+
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index f50df47..d22c28a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -1389,12 +1389,24 @@
 		compatible = "qcom,rpmh-vrm-regulator";
 		mboxes = <&apps_rsc 0>;
 		qcom,resource-name = "bobb1";
+		qcom,send-defaults;
+
 		pmi8998_bob: regulator-bob {
 			regulator-name = "pmi8998_bob";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
 			regulator-min-microvolt = <3312000>;
 			regulator-max-microvolt = <3600000>;
 			qcom,init-voltage = <3312000>;
+			qcom,init-mode = <RPMH_REGULATOR_MODE_BOB_PASS>;
+		};
+
+		pmi8998_bob_ao: regulator-bob-ao {
+			regulator-name = "pmi8998_bob_ao";
+			qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+			regulator-min-microvolt = <3312000>;
+			regulator-max-microvolt = <3600000>;
+			qcom,init-voltage = <3312000>;
+			qcom,init-mode = <RPMH_REGULATOR_MODE_BOB_AUTO>;
 		};
 	};
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
index e7fd8a0..99004bf 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
@@ -33,6 +33,7 @@
 	vdd-hba-supply = <&ufs_phy_gdsc>;
 	vdd-hba-fixed-regulator;
 	vcc-supply = <&pm8998_l20>;
+	vcc-voltage-level = <2950000 2960000>;
 	vccq2-supply = <&pm8998_s4>;
 	vcc-max-microamp = <600000>;
 	vccq2-max-microamp = <600000>;
@@ -157,6 +158,7 @@
 	vdd-hba-supply = <&ufs_card_gdsc>;
 	vdd-hba-fixed-regulator;
 	vcc-supply = <&pm8998_l21>;
+	vcc-voltage-level = <2950000 2960000>;
 	vccq2-supply = <&pm8998_s4>;
 	vcc-max-microamp = <300000>;
 	vccq2-max-microamp = <300000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index db3d23c..03b40b3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -430,10 +430,11 @@
 			<0xaf02000 0x1a0>,
 			<0x780000 0x621c>,
 			<0x88ea030 0x10>,
+			<0x88e8000 0x20>,
 			<0x0aee1000 0x034>;
 		reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
 			"dp_mmss_cc", "qfprom_physical", "dp_pll",
-			"hdcp_physical";
+			"usb3_dp_com", "hdcp_physical";
 
 		interrupt-parent = <&mdss_mdp>;
 		interrupts = <12 0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 0618f92..6051106 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -130,6 +130,9 @@
 		qcom,sde-has-idle-pc;
 		qcom,sde-max-bw-low-kbps = <9600000>;
 		qcom,sde-max-bw-high-kbps = <9600000>;
+		qcom,sde-min-core-ib-kbps = <2400000>;
+		qcom,sde-min-llcc-ib-kbps = <800000>;
+		qcom,sde-min-dram-ib-kbps = <800000>;
 		qcom,sde-dram-channels = <2>;
 		qcom,sde-num-nrt-paths = <0>;
 		qcom,sde-dspp-ad-version = <0x00040000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts
new file mode 100644
index 0000000..5b3e964
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-cdp-overlay.dts
@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-cdp-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel CDP";
+	compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
+	qcom,msm-id = <321 0x20000>;
+	qcom,board-id = <1 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+	connectors = <&sde_rscc &sde_wb>;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+	qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts
new file mode 100644
index 0000000..0d6c5e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-mtp-overlay.dts
@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel MTP";
+	compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
+	qcom,msm-id = <321 0x20000>;
+	qcom,board-id = <8 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+	connectors = <&sde_rscc &sde_wb &sde_dp>;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+	qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts
new file mode 100644
index 0000000..764c145
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-4k-panel-qrd-overlay.dts
@@ -0,0 +1,64 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-qrd.dtsi"
+#include "sdm845-qrd-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sdm845 v2 4K Display Panel QRD";
+	compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+	qcom,msm-id = <321 0x20000>;
+	qcom,board-id = <11 1>;
+};
+
+&dsi_nt35597_truly_dsc_cmd_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+	qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+	qcom,mdss-dsi-panel-orientation = "180";
+};
+
+&dsi_sharp_4k_dsc_video_display {
+	qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 98ab8d4..0b55736 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -477,6 +477,10 @@
 	};
 };
 
+&pil_modem {
+	qcom,mss_pdc_offset = <9>;
+};
+
 /* VDD_APC0 */
 &pm8998_s13 {
 	regulator-min-microvolt = <568000>;
@@ -843,6 +847,25 @@
 	qcom,count-unit = <0x10000>;
 };
 
+&cpubw {
+	qcom,bw-tbl =
+		< MHZ_TO_MBPS(150, 16) >, /*  2288 MB/s */
+		< MHZ_TO_MBPS(300, 16) >, /*  4577 MB/s */
+		< MHZ_TO_MBPS(426, 16) >, /*  6500 MB/s */
+		< MHZ_TO_MBPS(533, 16) >, /*  8132 MB/s */
+		< MHZ_TO_MBPS(600, 16) >, /*  9155 MB/s */
+		< MHZ_TO_MBPS(806, 16) >, /* 12298 MB/s */
+		< MHZ_TO_MBPS(933, 16) >; /* 14236 MB/s */
+};
+
+&devfreq_cpufreq {
+	mincpubw-cpufreq {
+		cpu-to-dev-map-4 =
+			< 1881600 MHZ_TO_MBPS(200, 4) >,
+			< 2400000 MHZ_TO_MBPS(681, 4) >;
+	};
+};
+
 &clock_gcc {
 	compatible = "qcom,gcc-sdm845-v2", "syscon";
 };
@@ -885,15 +908,16 @@
 
 &mdss_mdp {
 	clock-max-rate = <0 0 0 0 430000000 19200000 0>;
+	qcom,sde-min-core-ib-kbps = <4800000>;
 };
 
 &energy_costs {
 	CPU_COST_0: core-cost0 {
 		busy-cost-data = <
-			 300000 11
+			 300000 12
 			 403200 17
 			 480000 21
-			 576000 26
+			 576000 27
 			 652800 31
 			 748800 37
 			 825600 42
@@ -901,13 +925,13 @@
 			 979200 52
 			1056000 57
 			1132800 62
-			1228800 69
+			1228800 70
 			1324800 78
 			1420800 89
 			1516800 103
 			1612800 122
-			1689600 140
-			1766400 159
+			1689600 141
+			1766400 160
 		>;
 		idle-cost-data = <
 			22 18 14 12
@@ -915,37 +939,37 @@
 	};
 	CPU_COST_1: core-cost1 {
 		busy-cost-data = <
-			 300000 130
-			 403200 480
-			 480000 730
-			 576000 1030
-			 652800 1260
-			 748800 1530
-			 825600 1740
-			 902400 1930
-			 979200 2110
-			1056000 2290
-			1132800 2460
-			1209600 2630
-			1286400 2800
-			1363200 2980
-			1459200 3240
-			1536000 3490
-			1612800 3780
-			1689600 4120
-			1766400 4530
-			1843200 5020
-			1920000 5590
-			1996800 6230
+			 300000 189
+			 403200 523
+			 480000 763
+			 576000 1052
+			 652800 1273
+			 748800 1536
+			 825600 1736
+			 902400 1926
+			 979200 2108
+			1056000 2284
+			1132800 2456
+			1209600 2628
+			1286400 2804
+			1363200 2992
+			1459200 3255
+			1536000 3499
+			1612800 3786
+			1689600 4128
+			1766400 4535
+			1843200 5019
+			1920000 5583
+			1996800 6226
 			2092800 7120
-			2169600 7870
-			2246400 8620
-			2323200 9330
+			2169600 7876
+			2246400 8628
+			2323200 9344
 			2400000 10030
-			2476800 10830
-			2553600 12080
-			2630400 14580
-			2707200 19960
+			2476800 10806
+			2553600 12045
+			2649600 15686
+			2745600 25586
 		>;
 		idle-cost-data = <
 			100 80 60 40
@@ -1007,8 +1031,8 @@
 			2400000 135
 			2476800 140
 			2553600 145
-			2630400 150
-			2707200 155
+			2649600 150
+			2745600 155
 		>;
 		idle-cost-data = <
 			4 3 2 1
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index d72c91c..1a88ec8 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -828,12 +828,12 @@
 			<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_LLCC>;
 		qcom,active-only;
 		qcom,bw-tbl =
-			<  2288 /* 150 MHz */ >,
-			<  4577 /* 300 MHz */ >,
-			<  6500 /* 426 MHz */ >,
-			<  8132 /* 533 MHz */ >,
-			<  9155 /* 600 MHz */ >,
-			< 10681 /* 700 MHz */ >;
+			< MHZ_TO_MBPS(150, 16) >, /*  2288 MB/s */
+			< MHZ_TO_MBPS(300, 16) >, /*  4577 MB/s */
+			< MHZ_TO_MBPS(426, 16) >, /*  6500 MB/s */
+			< MHZ_TO_MBPS(533, 16) >, /*  8132 MB/s */
+			< MHZ_TO_MBPS(600, 16) >, /*  9155 MB/s */
+			< MHZ_TO_MBPS(700, 16) >; /* 10681 MB/s */
 	};
 
 	bwmon: qcom,cpu-bwmon {
@@ -853,16 +853,16 @@
 			<MSM_BUS_MASTER_LLCC MSM_BUS_SLAVE_EBI_CH0>;
 		qcom,active-only;
 		qcom,bw-tbl =
-			<  762 /*  200 MHz */ >,
-			< 1144 /*  300 MHz */ >,
-			< 1720 /*  451 MHz */ >,
-			< 2086 /*  547 MHz */ >,
-			< 2597 /*  681 MHz */ >,
-			< 2929 /*  768 MHz */ >,
-			< 3879 /* 1017 MHz */ >,
-			< 4943 /* 1296 MHz */ >,
-			< 5931 /* 1555 MHz */ >,
-			< 6881 /* 1804 MHz */ >;
+			< MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+			< MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+			< MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+			< MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+			< MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+			< MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+			< MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+			< MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+			< MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+			< MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
 	};
 
 	llcc_bwmon: qcom,llcc-bwmon {
@@ -883,16 +883,16 @@
 		qcom,src-dst-ports = <1 512>;
 		qcom,active-only;
 		qcom,bw-tbl =
-			<  762 /*  200 MHz */ >,
-			< 1144 /*  300 MHz */ >,
-			< 1720 /*  451 MHz */ >,
-			< 2086 /*  547 MHz */ >,
-			< 2597 /*  681 MHz */ >,
-			< 2929 /*  768 MHz */ >,
-			< 3879 /* 1017 MHz */ >,
-			< 4943 /* 1296 MHz */ >,
-			< 5931 /* 1555 MHz */ >,
-			< 6881 /* 1804 MHz */ >;
+			< MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+			< MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+			< MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+			< MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+			< MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+			< MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+			< MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+			< MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+			< MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+			< MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
 	};
 
 	memlat_cpu4: qcom,memlat-cpu4 {
@@ -902,16 +902,16 @@
 		qcom,active-only;
 		status = "ok";
 		qcom,bw-tbl =
-			<  762 /*  200 MHz */ >,
-			< 1144 /*  300 MHz */ >,
-			< 1720 /*  451 MHz */ >,
-			< 2086 /*  547 MHz */ >,
-			< 2597 /*  681 MHz */ >,
-			< 2929 /*  768 MHz */ >,
-			< 3879 /* 1017 MHz */ >,
-			< 4943 /* 1296 MHz */ >,
-			< 5931 /* 1555 MHz */ >,
-			< 6881 /* 1804 MHz */ >;
+			< MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+			< MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+			< MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+			< MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+			< MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+			< MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+			< MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+			< MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+			< MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+			< MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
 	};
 
 	snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive {
@@ -930,11 +930,11 @@
 		qcom,target-dev = <&memlat_cpu0>;
 		qcom,cachemiss-ev = <0x2A>;
 		qcom,core-dev-table =
-			<  300000  762 >,
-			<  748800 1720 >,
-			< 1132800 2086 >,
-			< 1440000 2929 >,
-			< 1593600 3879 >;
+			<  300000 MHZ_TO_MBPS( 200, 4) >,
+			<  748800 MHZ_TO_MBPS( 451, 4) >,
+			< 1132800 MHZ_TO_MBPS( 547, 4) >,
+			< 1440000 MHZ_TO_MBPS( 768, 4) >,
+			< 1593600 MHZ_TO_MBPS(1017, 4) >;
 	};
 
 	devfreq_memlat_4: qcom,cpu4-memlat-mon {
@@ -943,14 +943,14 @@
 		qcom,target-dev = <&memlat_cpu4>;
 		qcom,cachemiss-ev = <0x2A>;
 		qcom,core-dev-table =
-			<  300000  762 >,
-			<  499200 1720 >,
-			<  806400 2086 >,
-			< 1036800 2929 >,
-			< 1190400 3879 >,
-			< 1574400 4943 >,
-			< 1728000 5931 >,
-			< 1958400 6881 >;
+			<  300000 MHZ_TO_MBPS( 200, 4) >,
+			<  499200 MHZ_TO_MBPS( 451, 4) >,
+			<  806400 MHZ_TO_MBPS( 547, 4) >,
+			< 1036800 MHZ_TO_MBPS( 768, 4) >,
+			< 1190400 MHZ_TO_MBPS(1017, 4) >,
+			< 1574400 MHZ_TO_MBPS(1296, 4) >,
+			< 1728000 MHZ_TO_MBPS(1555, 4) >,
+			< 1958400 MHZ_TO_MBPS(1804, 4) >;
 	};
 
 	l3_cpu0: qcom,l3-cpu0 {
@@ -1008,26 +1008,26 @@
 		qcom,src-dst-ports = <1 512>;
 		qcom,active-only;
 		qcom,bw-tbl =
-			<  762 /*  200 MHz */ >,
-			< 1144 /*  300 MHz */ >,
-			< 1720 /*  451 MHz */ >,
-			< 2086 /*  547 MHz */ >,
-			< 2597 /*  681 MHz */ >,
-			< 2929 /*  768 MHz */ >,
-			< 3879 /* 1017 MHz */ >,
-			< 4943 /* 1296 MHz */ >,
-			< 5931 /* 1555 MHz */ >,
-			< 6881 /* 1804 MHz */ >;
+			< MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+			< MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+			< MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+			< MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+			< MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+			< MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+			< MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+			< MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */
+			< MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+			< MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
 	};
 
-	devfreq-cpufreq {
+	devfreq_cpufreq: devfreq-cpufreq {
 		mincpubw-cpufreq {
 			target-dev = <&mincpubw>;
 			cpu-to-dev-map-0 =
-				< 1708800  762 >;
+				< 1708800 MHZ_TO_MBPS(200, 4) >;
 			cpu-to-dev-map-4 =
-				< 1881600  762 >,
-				< 2208000 2597 >;
+				< 1881600 MHZ_TO_MBPS(200, 4) >,
+				< 2208000 MHZ_TO_MBPS(681, 4) >;
 		};
 	};
 
@@ -1742,6 +1742,7 @@
 		qcom,ssctl-instance-id = <0x12>;
 		qcom,override-acc;
 		qcom,qdsp6v65-1-0;
+		qcom,mss_pdc_offset = <8>;
 		status = "ok";
 		memory-region = <&pil_modem_mem>;
 		qcom,mem-protect-id = <0xF>;
@@ -2540,6 +2541,18 @@
 		qcom,fragmented-data;
 	};
 
+	qcom,qsee_ipc_irq_bridge {
+		compatible = "qcom,qsee-ipc-irq-bridge";
+
+		qcom,qsee-ipq-irq-spss {
+			qcom,rx-irq-clr = <0x1888008 0x4>;
+			qcom,rx-irq-clr-mask = <0x1>;
+			qcom,dev-name = "qsee_ipc_irq_spss";
+			interrupts = <0 349 4>;
+			label = "spss";
+		};
+	};
+
 	qcom,spcom {
 		compatible = "qcom,spcom";
 
@@ -3041,6 +3054,11 @@
 				#cooling-cells = <2>;
 			};
 
+			modem_skin: modem_skin {
+				qcom,qmi-dev-name = "modem_skin";
+				#cooling-cells = <2>;
+			};
+
 			modem_vdd: modem_vdd {
 				qcom,qmi-dev-name = "cpuv_restriction_cold";
 				#cooling-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/smb1355.dtsi b/arch/arm64/boot/dts/qcom/smb1355.dtsi
index 6b7ebbd..bde4d1e 100644
--- a/arch/arm64/boot/dts/qcom/smb1355.dtsi
+++ b/arch/arm64/boot/dts/qcom/smb1355.dtsi
@@ -13,30 +13,75 @@
 #include <dt-bindings/interrupt-controller/irq.h>
 
 &qupv3_se10_i2c {
-	smb1355: qcom,smb1355@8 {
+	smb1355_0: qcom,smb1355@8 {
 		compatible = "qcom,i2c-pmic";
 		reg = <0x8>;
 		#address-cells = <1>;
 		#size-cells = <0>;
 		interrupt-parent = <&spmi_bus>;
 		interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
-		interrupt_names = "smb1355";
+		interrupt_names = "smb1355_0";
 		interrupt-controller;
 		#interrupt-cells = <3>;
 		qcom,periph-map = <0x10 0x12 0x13 0x16>;
 
-		smb1355_revid: qcom,revid@100 {
+		smb1355_revid_0: qcom,revid@100 {
 			compatible = "qcom,qpnp-revid";
 			reg = <0x100 0x100>;
 		};
 
-		smb1355_charger: qcom,smb1355-charger@1000 {
+		smb1355_charger_0: qcom,smb1355-charger@1000 {
 			compatible = "qcom,smb1355";
-			qcom,pmic-revid = <&smb1355_revid>;
+			qcom,pmic-revid = <&smb1355_revid_0>;
 			reg = <0x1000 0x700>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-			interrupt-parent = <&smb1355>;
+			interrupt-parent = <&smb1355_0>;
+			status = "disabled";
+
+			io-channels = <&pmi8998_rradc 2>,
+				      <&pmi8998_rradc 12>;
+			io-channel-names = "charger_temp",
+					   "charger_temp_max";
+
+			qcom,chgr@1000 {
+				reg = <0x1000 0x100>;
+				interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
+				interrupt-names = "chg-state-change";
+			};
+
+			qcom,chgr-misc@1600 {
+				reg = <0x1600 0x100>;
+				interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>;
+				interrupt-names = "wdog-bark";
+			};
+		};
+	};
+
+	smb1355_1: qcom,smb1355@c {
+		compatible = "qcom,i2c-pmic";
+		reg = <0xc>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-parent = <&spmi_bus>;
+		interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
+		interrupt_names = "smb1355_1";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		qcom,periph-map = <0x10 0x12 0x13 0x16>;
+
+		smb1355_revid_1: qcom,revid@100 {
+			compatible = "qcom,qpnp-revid";
+			reg = <0x100 0x100>;
+		};
+
+		smb1355_charger_1: qcom,smb1355-charger@1000 {
+			compatible = "qcom,smb1355";
+			qcom,pmic-revid = <&smb1355_revid_1>;
+			reg = <0x1000 0x700>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			interrupt-parent = <&smb1355_1>;
 			status = "disabled";
 
 			io-channels = <&pmi8998_rradc 2>,
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 07e7ee9..dc09f04 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -321,10 +321,12 @@
 CONFIG_THERMAL_QPNP=y
 CONFIG_THERMAL_QPNP_ADC_TM=y
 CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
 CONFIG_QTI_VIRTUAL_SENSOR=y
 CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
 CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -390,6 +392,7 @@
 CONFIG_USB_PD_POLICY=y
 CONFIG_QPNP_USB_PDPHY=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_LINK_LAYER_TEST=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_MSM_SSPHY_QMP=y
@@ -454,9 +457,14 @@
 CONFIG_MSM_11AD=m
 CONFIG_SEEMP_CORE=y
 CONFIG_QCOM_GENI_SE=y
+CONFIG_MSM_GCC_SDM845=y
+CONFIG_MSM_VIDEOCC_SDM845=y
+CONFIG_MSM_CAMCC_SDM845=y
+CONFIG_MSM_DISPCC_SDM845=y
 CONFIG_CLOCK_QPNP_DIV=y
 CONFIG_MSM_CLK_RPMH=y
 CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
 CONFIG_MSM_CLK_AOP_QMP=y
 CONFIG_QCOM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 48512be..8d3bd72 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -331,6 +331,8 @@
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
 CONFIG_QTI_VIRTUAL_SENSOR=y
 CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
 CONFIG_MFD_I2C_PMIC=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -386,6 +388,7 @@
 CONFIG_USB_PD_POLICY=y
 CONFIG_QPNP_USB_PDPHY=y
 CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_LINK_LAYER_TEST=y
 CONFIG_NOP_USB_XCEIV=y
 CONFIG_DUAL_ROLE_USB_INTF=y
 CONFIG_USB_MSM_SSPHY_QMP=y
@@ -458,9 +461,14 @@
 CONFIG_MSM_11AD=m
 CONFIG_SEEMP_CORE=y
 CONFIG_QCOM_GENI_SE=y
+CONFIG_MSM_GCC_SDM845=y
+CONFIG_MSM_VIDEOCC_SDM845=y
+CONFIG_MSM_CAMCC_SDM845=y
+CONFIG_MSM_DISPCC_SDM845=y
 CONFIG_CLOCK_QPNP_DIV=y
 CONFIG_MSM_CLK_RPMH=y
 CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
 CONFIG_MSM_CLK_AOP_QMP=y
 CONFIG_QCOM_MDSS_PLL=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index d2d2bf0..a04d0f4 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -528,6 +528,7 @@
 CONFIG_QTI_RPM_STATS_LOG=y
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_QSEE_IPC_IRQ_BRIDGE=y
 CONFIG_QCOM_BIMC_BWMON=y
 CONFIG_ARM_MEMLAT_MON=y
 CONFIG_QCOMCCI_HWMON=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 6cc9459..4933500 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -551,6 +551,7 @@
 CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_QMP_DEBUGFS_CLIENT=y
 CONFIG_MSM_REMOTEQDSS=y
+CONFIG_QSEE_IPC_IRQ_BRIDGE=y
 CONFIG_QCOM_BIMC_BWMON=y
 CONFIG_ARM_MEMLAT_MON=y
 CONFIG_QCOMCCI_HWMON=y
@@ -611,6 +612,7 @@
 CONFIG_DEBUG_STACK_USAGE=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
 CONFIG_WQ_WATCHDOG=y
 CONFIG_PANIC_TIMEOUT=5
 CONFIG_PANIC_ON_SCHED_BUG=y
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 88edacd..9f1a1bb 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -3252,6 +3252,7 @@
 err_dead_proc_or_thread:
 	return_error = BR_DEAD_REPLY;
 	return_error_line = __LINE__;
+	binder_dequeue_work(proc, tcomplete);
 err_translate_failed:
 err_bad_object_type:
 err_bad_offset:
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 55687b8..e17ad53 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -208,6 +208,59 @@
 
 #endif
 
+static ssize_t show_sched_load_boost(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	ssize_t rc;
+	unsigned int boost;
+	struct cpu *cpu = container_of(dev, struct cpu, dev);
+	int cpuid = cpu->dev.id;
+
+	boost = per_cpu(sched_load_boost, cpuid);
+	rc = snprintf(buf, PAGE_SIZE-2, "%d\n", boost);
+
+	return rc;
+}
+
+static ssize_t __ref store_sched_load_boost(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int err;
+	int boost;
+	struct cpu *cpu = container_of(dev, struct cpu, dev);
+	int cpuid = cpu->dev.id;
+
+	err = kstrtoint(strstrip((char *)buf), 0, &boost);
+	if (err)
+		return err;
+
+	/*
+	 * -100 is low enough to cancel out CPU's load and make it near zro.
+	 * 1000 is close to the maximum value that cpu_util_freq_{walt,pelt}
+	 * can take without overflow.
+	 */
+	if (boost < -100 || boost > 1000)
+		return -EINVAL;
+
+	per_cpu(sched_load_boost, cpuid) = boost;
+
+	return count;
+}
+
+static DEVICE_ATTR(sched_load_boost, 0644,
+		   show_sched_load_boost,
+		   store_sched_load_boost);
+
+static struct attribute *sched_cpu_attrs[] = {
+	&dev_attr_sched_load_boost.attr,
+	NULL
+};
+
+static struct attribute_group sched_cpu_attr_group = {
+	.attrs = sched_cpu_attrs,
+};
+
 static const struct attribute_group *common_cpu_attr_groups[] = {
 #ifdef CONFIG_KEXEC
 	&crash_note_cpu_attr_group,
@@ -215,6 +268,7 @@
 #ifdef CONFIG_HOTPLUG_CPU
 	&cpu_isolated_attr_group,
 #endif
+	&sched_cpu_attr_group,
 	NULL
 };
 
@@ -225,6 +279,7 @@
 #ifdef CONFIG_HOTPLUG_CPU
 	&cpu_isolated_attr_group,
 #endif
+	&sched_cpu_attr_group,
 	NULL
 };
 
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 636c982..874639f 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -60,6 +60,7 @@
 #define NUM_SESSIONS	9	/*8 compute, 1 cpz*/
 #define M_FDLIST	(16)
 #define M_CRCLIST	(64)
+#define SESSION_ID_INDEX (30)
 
 #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0)
 
@@ -282,6 +283,7 @@
 	struct fastrpc_session_ctx *secsctx;
 	uint32_t mode;
 	uint32_t profile;
+	int sessionid;
 	int tgid;
 	int cid;
 	int ssrcount;
@@ -860,7 +862,7 @@
 	}
 	ctx->retval = -1;
 	ctx->pid = current->pid;
-	ctx->tgid = current->tgid;
+	ctx->tgid = fl->tgid;
 	init_completion(&ctx->work);
 
 	spin_lock(&fl->hlock);
@@ -1351,8 +1353,10 @@
 	VERIFY(err, 0 != channel_ctx->chan);
 	if (err)
 		goto bail;
-	msg->pid = current->tgid;
+	msg->pid = fl->tgid;
 	msg->tid = current->pid;
+	if (fl->sessionid)
+		msg->tid |= (1 << SESSION_ID_INDEX);
 	if (kernel)
 		msg->pid = 0;
 	msg->invoke.header.ctx = ptr_to_uint64(ctx) | fl->pd;
@@ -1407,6 +1411,7 @@
 	if (fl->profile)
 		getnstimeofday(&invoket);
 
+
 	VERIFY(err, fl->sctx != NULL);
 	if (err)
 		goto bail;
@@ -1504,7 +1509,7 @@
 		goto bail;
 	if (init->flags == FASTRPC_INIT_ATTACH) {
 		remote_arg_t ra[1];
-		int tgid = current->tgid;
+		int tgid = fl->tgid;
 
 		ra[0].buf.pv = (void *)&tgid;
 		ra[0].buf.len = sizeof(tgid);
@@ -1532,7 +1537,7 @@
 			int siglen;
 		} inbuf;
 
-		inbuf.pgid = current->tgid;
+		inbuf.pgid = fl->tgid;
 		inbuf.namelen = strlen(current->comm) + 1;
 		inbuf.filelen = init->filelen;
 		fl->pd = 1;
@@ -1645,7 +1650,7 @@
 		uintptr_t vaddrout;
 	} routargs;
 
-	inargs.pid = current->tgid;
+	inargs.pid = fl->tgid;
 	inargs.vaddrin = (uintptr_t)map->va;
 	inargs.flags = flags;
 	inargs.num = fl->apps->compat ? num * sizeof(page) : num;
@@ -1687,7 +1692,7 @@
 		ssize_t size;
 	} inargs;
 
-	inargs.pid = current->tgid;
+	inargs.pid = fl->tgid;
 	inargs.size = map->size;
 	inargs.vaddrout = map->raddr;
 	ra[0].buf.pv = (void *)&inargs;
@@ -2226,6 +2231,7 @@
 	INIT_HLIST_HEAD(&fl->maps);
 	INIT_HLIST_HEAD(&fl->bufs);
 	INIT_HLIST_NODE(&fl->hn);
+	fl->sessionid = 0;
 	fl->tgid = current->tgid;
 	fl->apps = me;
 	fl->mode = FASTRPC_MODE_SERIAL;
@@ -2386,6 +2392,10 @@
 		case FASTRPC_MODE_PROFILE:
 			fl->profile = (uint32_t)ioctl_param;
 			break;
+		case FASTRPC_MODE_SESSION:
+			fl->sessionid = 1;
+			fl->tgid |= (1 << SESSION_ID_INDEX);
+			break;
 		default:
 			err = -ENOTTY;
 			break;
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index 9f964d2..2e8bfc2 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -52,6 +52,9 @@
 /* Driver should operate in profile mode with the co-processor */
 #define FASTRPC_MODE_PROFILE     2
 
+/* Set FastRPC session ID to 1 */
+#define FASTRPC_MODE_SESSION     4
+
 /* INIT a new process or attach to guestos */
 #define FASTRPC_INIT_ATTACH      0
 #define FASTRPC_INIT_CREATE      1
diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c
index 3684b8d..5de7897 100644
--- a/drivers/char/diag/diagfwd_bridge.c
+++ b/drivers/char/diag/diagfwd_bridge.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -90,6 +90,18 @@
 {
 	if (id < 0 || id >= NUM_REMOTE_DEV)
 		return -EINVAL;
+
+	if ((mode == DIAG_USB_MODE &&
+		driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) ||
+		(mode == DIAG_MEMORY_DEVICE_MODE &&
+		driver->logging_mode == DIAG_USB_MODE)) {
+		/*
+		 * Don't close the MHI channels when usb is disconnected
+		 * and a process is running in memory device mode.
+		 */
+		return 0;
+	}
+
 	if (bridge_info[id].dev_ops && bridge_info[id].dev_ops->close)
 		bridge_info[id].dev_ops->close(bridge_info[id].ctxt);
 	return 0;
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index d7e24fc..354c6a0 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -729,8 +729,9 @@
 	struct diagfwd_info *fwd_info_cmd = NULL;
 	char *process_name = NULL;
 	int err = 0;
+	char *root_str = NULL;
 	uint8_t local_diag_id = 0;
-	uint8_t new_request = 0;
+	uint8_t new_request = 0, i = 0;
 
 	if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS)
 		return;
@@ -753,20 +754,31 @@
 		ctrl_pkt.diag_id = diag_id;
 		new_request = 1;
 	}
+	root_str = strnstr(process_name, DIAG_ID_ROOT_STRING,
+		strlen(process_name));
 
 	if (new_request) {
 		fwd_info_data->num_pd++;
 		fwd_info_cmd->num_pd++;
+		if (root_str) {
+			fwd_info_cmd->diagid_root = ctrl_pkt.diag_id;
+			fwd_info_data->diagid_root = ctrl_pkt.diag_id;
+		} else {
+			i = fwd_info_cmd->num_pd - 2;
+			if (i >= 0)
+				fwd_info_cmd->diagid_user[i] =
+				ctrl_pkt.diag_id;
+
+			i = fwd_info_data->num_pd - 2;
+			if (i >= 0)
+				fwd_info_data->diagid_user[i] =
+				ctrl_pkt.diag_id;
+		}
 	}
 
-	if (strnstr(process_name, DIAG_ID_ROOT_STRING, strlen(process_name))) {
-		fwd_info_cmd->diagid_root = diag_id;
-		fwd_info_data->diagid_root = diag_id;
+	if (root_str)
 		driver->diag_id_sent[peripheral] = 0;
-	} else {
-		fwd_info_cmd->diagid_user[fwd_info_cmd->num_pd - 2] = diag_id;
-		fwd_info_data->diagid_user[fwd_info_data->num_pd - 2] = diag_id;
-	}
+
 
 	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
 		"diag: peripheral = %d: diag_id string = %s,diag_id = %d\n",
@@ -794,6 +806,10 @@
 	 * to peripherals.
 	 */
 		driver->diag_id_sent[peripheral] = 1;
+		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+		"diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n",
+			driver->diag_id_sent[peripheral], peripheral,
+			ctrl_pkt.diag_id, process_name);
 		diag_send_updates_peripheral(peripheral);
 		diagfwd_buffers_init(fwd_info_data);
 	}
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 13904fd..9f7f699 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -1058,7 +1058,7 @@
 		return -ENODEV;
 
 	if (type == TYPE_CMD) {
-		if (driver->feature[peripheral].untag_header)
+		if (driver->feature[peripheral].diag_id_support)
 			if (!fwd_info->diagid_root ||
 				(!driver->diag_id_sent[peripheral])) {
 			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index e7d3ee4..afb2c01 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -459,6 +459,37 @@
 	}
 }
 
+static int clk_fabia_pll_latch_input(struct clk_alpha_pll *pll,
+					struct regmap *regmap)
+{
+	u32 regval;
+	int ret = 0;
+
+	/* Latch the PLL input */
+	ret = regmap_update_bits(regmap, pll->offset + PLL_MODE,
+			   FABIA_PLL_UPDATE, FABIA_PLL_UPDATE);
+	if (ret)
+		return ret;
+
+	/* Wait for 2 reference cycles before checking the ACK bit. */
+	udelay(1);
+	regmap_read(regmap, pll->offset + PLL_MODE, &regval);
+	if (!(regval & FABIA_PLL_ACK_LATCH)) {
+		WARN(1, "clk: PLL latch failed. Output may be unstable!\n");
+		return -EINVAL;
+	}
+
+	/* Return the latch input to 0 */
+	ret = regmap_update_bits(regmap, pll->offset + PLL_MODE,
+			   FABIA_PLL_UPDATE, 0);
+	if (ret)
+		return ret;
+
+	/* Wait for PLL output to stabilize */
+	udelay(100);
+	return ret;
+}
+
 void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
 				const struct pll_config *config)
 {
@@ -471,6 +502,7 @@
 	if (config->frac)
 		regmap_write(regmap, pll->offset + FABIA_FRAC_VAL,
 						config->frac);
+
 	if (config->config_ctl_val)
 		regmap_write(regmap, pll->offset + PLL_CONFIG_CTL,
 				config->config_ctl_val);
@@ -482,6 +514,14 @@
 					mask, val);
 	}
 
+	/*
+	 * If the PLL has already been initialized, it would now be in a STANDBY
+	 * state. Any new updates to the PLL frequency will require setting the
+	 * PLL_UPDATE bit.
+	 */
+	if (pll->inited)
+		clk_fabia_pll_latch_input(pll, regmap);
+
 	regmap_update_bits(regmap, pll->offset + PLL_MODE,
 				 FABIA_PLL_HW_UPDATE_LOGIC_BYPASS,
 				 FABIA_PLL_HW_UPDATE_LOGIC_BYPASS);
@@ -627,29 +667,8 @@
 	regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l);
 	regmap_write(pll->clkr.regmap, off + FABIA_FRAC_VAL, a);
 
-	/* Latch the PLL input */
-	ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
-			   FABIA_PLL_UPDATE, FABIA_PLL_UPDATE);
-	if (ret)
-		return ret;
-
-	/* Wait for 2 reference cycles before checking the ACK bit. */
-	udelay(1);
-	regmap_read(pll->clkr.regmap, off + PLL_MODE, &regval);
-	if (!(regval & FABIA_PLL_ACK_LATCH)) {
-		WARN(1, "clk: PLL latch failed. Output may be unstable!\n");
-		return -EINVAL;
-	}
-
-	/* Return the latch input to 0 */
-	ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
-			   FABIA_PLL_UPDATE, 0);
-	if (ret)
-		return ret;
-
-	/* Wait for PLL output to stabilize */
-	udelay(100);
-	return 0;
+	ret = clk_fabia_pll_latch_input(pll, pll->clkr.regmap);
+	return ret;
 }
 
 static void clk_fabia_pll_list_registers(struct seq_file *f, struct clk_hw *hw)
diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c
index 4b89cbf..038e89c 100644
--- a/drivers/edac/qcom_llcc_edac.c
+++ b/drivers/edac/qcom_llcc_edac.c
@@ -397,21 +397,6 @@
 	if (rc)
 		goto out_mem;
 
-	if (interrupt_mode) {
-		drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq");
-		if (!drv->ecc_irq) {
-			rc = -ENODEV;
-			goto out_dev;
-		}
-
-		rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
-				IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
-		if (rc) {
-			dev_err(dev, "failed to request ecc irq\n");
-			goto out_dev;
-		}
-	}
-
 	drv->llcc_banks = devm_kzalloc(&pdev->dev,
 		sizeof(u32) * drv->num_banks, GFP_KERNEL);
 
@@ -437,6 +422,21 @@
 
 	platform_set_drvdata(pdev, edev_ctl);
 
+	if (interrupt_mode) {
+		drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq");
+		if (!drv->ecc_irq) {
+			rc = -ENODEV;
+			goto out_dev;
+		}
+
+		rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
+				IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
+		if (rc) {
+			dev_err(dev, "failed to request ecc irq\n");
+			goto out_dev;
+		}
+	}
+
 	return 0;
 
 out_dev:
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
index c263115..67b6072 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -379,7 +379,7 @@
 	case DP_LINK_BW_5_4:
 		select = 2;
 		break;
-	case DP_LINK_RATE_810:
+	case DP_LINK_BW_8_1:
 		select = 3;
 		break;
 	default:
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 94bd199..3a33ce4 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -15,6 +15,7 @@
 #define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
 
 #include <linux/delay.h>
+#include <drm/drm_dp_helper.h>
 
 #include "dp_catalog.h"
 #include "dp_reg.h"
@@ -408,7 +409,8 @@
 	u32 mvid, nvid;
 	u64 mvid_calc;
 	u32 const nvid_fixed = 0x8000;
-	u32 const link_rate = 540000;
+	u32 const link_rate_hbr2 = 540000;
+	u32 const link_rate_hbr3 = 810000;
 	struct dp_catalog_private *catalog;
 	void __iomem *base_cc, *base_ctrl;
 
@@ -449,8 +451,11 @@
 
 		pr_debug("rate = %d\n", rate);
 
-		if (link_rate == rate)
+		if (link_rate_hbr2 == rate)
 			nvid *= 2;
+
+		if (link_rate_hbr3 == rate)
+			nvid *= 3;
 	}
 
 	base_ctrl = catalog->io->ctrl_io.base;
@@ -493,6 +498,43 @@
 		pr_err("set link_train=%d failed\n", pattern);
 }
 
+static void dp_catalog_ctrl_usb_reset(struct dp_catalog_ctrl *ctrl, bool flip)
+{
+	struct dp_catalog_private *catalog;
+	void __iomem *base;
+
+	if (!ctrl) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	dp_catalog_get_priv(ctrl);
+
+	base = catalog->io->usb3_dp_com.base;
+
+	dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x0a);
+	dp_write(base + USB3_DP_COM_PHY_MODE_CTRL, 0x02);
+	dp_write(base + USB3_DP_COM_SW_RESET, 0x01);
+	/* make sure usb3 com phy software reset is done */
+	wmb();
+
+	if (!flip) /* CC1 */
+		dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x02);
+	else /* CC2 */
+		dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x03);
+
+	dp_write(base + USB3_DP_COM_SWI_CTRL, 0x00);
+	dp_write(base + USB3_DP_COM_SW_RESET, 0x00);
+	/* make sure the software reset is done */
+	wmb();
+
+	dp_write(base + USB3_DP_COM_POWER_DOWN_CTRL, 0x01);
+	dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
+	/* make sure phy is brought out of reset */
+	wmb();
+
+}
+
 static void dp_catalog_ctrl_reset(struct dp_catalog_ctrl *ctrl)
 {
 	u32 sw_reset;
@@ -706,6 +748,82 @@
 	}
 }
 
+static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl,
+			u32 pattern)
+{
+	struct dp_catalog_private *catalog;
+	u32 value = 0x0;
+	void __iomem *base = NULL;
+
+	if (!ctrl) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	dp_catalog_get_priv(ctrl);
+
+	base = catalog->io->ctrl_io.base;
+
+	dp_write(base + DP_STATE_CTRL, 0x0);
+
+	switch (pattern) {
+	case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
+		dp_write(base + DP_STATE_CTRL, 0x1);
+		break;
+	case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+		value &= ~(1 << 16);
+		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		value |= 0xFC;
+		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		dp_write(base + DP_MAINLINK_LEVELS, 0x2);
+		dp_write(base + DP_STATE_CTRL, 0x10);
+		break;
+	case DP_TEST_PHY_PATTERN_PRBS7:
+		dp_write(base + DP_STATE_CTRL, 0x20);
+		break;
+	case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
+		dp_write(base + DP_STATE_CTRL, 0x40);
+		/* 00111110000011111000001111100000 */
+		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0);
+		/* 00001111100000111110000011111000 */
+		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8);
+		/* 1111100000111110 */
+		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E);
+		break;
+	case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
+		value = BIT(16);
+		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		value |= 0xFC;
+		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
+		dp_write(base + DP_MAINLINK_LEVELS, 0x2);
+		dp_write(base + DP_STATE_CTRL, 0x10);
+		break;
+	default:
+		pr_debug("No valid test pattern requested: 0x%x\n", pattern);
+		return;
+	}
+
+	/* Make sure the test pattern is programmed in the hardware */
+	wmb();
+}
+
+static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl)
+{
+	struct dp_catalog_private *catalog;
+	void __iomem *base = NULL;
+
+	if (!ctrl) {
+		pr_err("invalid input\n");
+		return 0;
+	}
+
+	dp_catalog_get_priv(ctrl);
+
+	base = catalog->io->ctrl_io.base;
+
+	return dp_read(base + DP_MAINLINK_READY);
+}
+
 /* panel related catalog functions */
 static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel)
 {
@@ -937,6 +1055,7 @@
 		.config_msa     = dp_catalog_ctrl_config_msa,
 		.set_pattern    = dp_catalog_ctrl_set_pattern,
 		.reset          = dp_catalog_ctrl_reset,
+		.usb_reset      = dp_catalog_ctrl_usb_reset,
 		.mainlink_ready = dp_catalog_ctrl_mainlink_ready,
 		.enable_irq     = dp_catalog_ctrl_enable_irq,
 		.hpd_config     = dp_catalog_ctrl_hpd_config,
@@ -946,6 +1065,8 @@
 		.get_interrupt  = dp_catalog_ctrl_get_interrupt,
 		.update_transfer_unit = dp_catalog_ctrl_update_transfer_unit,
 		.read_hdcp_status     = dp_catalog_ctrl_read_hdcp_status,
+		.send_phy_pattern    = dp_catalog_ctrl_send_phy_pattern,
+		.read_phy_pattern = dp_catalog_ctrl_read_phy_pattern,
 	};
 	struct dp_catalog_audio audio = {
 		.init       = dp_catalog_audio_init,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 47c10bf..4523b4f 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -65,6 +65,7 @@
 				u32 stream_rate_khz, bool fixed_nvid);
 	void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern);
 	void (*reset)(struct dp_catalog_ctrl *ctrl);
+	void (*usb_reset)(struct dp_catalog_ctrl *ctrl, bool flip);
 	bool (*mainlink_ready)(struct dp_catalog_ctrl *ctrl);
 	void (*enable_irq)(struct dp_catalog_ctrl *ctrl, bool enable);
 	void (*hpd_config)(struct dp_catalog_ctrl *ctrl, bool enable);
@@ -76,6 +77,9 @@
 	void (*get_interrupt)(struct dp_catalog_ctrl *ctrl);
 	void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl);
 	u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
+	void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl,
+			u32 pattern);
+	u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl);
 };
 
 enum dp_catalog_audio_sdp_type {
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 51abcf5..9ce23b1 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -36,6 +36,11 @@
 #define ST_SEND_VIDEO			BIT(7)
 #define ST_PUSH_IDLE			BIT(8)
 
+#define MR_LINK_TRAINING1  0x8
+#define MR_LINK_SYMBOL_ERM 0x80
+#define MR_LINK_PRBS7 0x100
+#define MR_LINK_CUSTOM80 0x200
+
 struct dp_vc_tu_mapping_table {
 	u32 vic;
 	u8 lanes;
@@ -63,7 +68,6 @@
 
 	struct completion idle_comp;
 	struct completion video_comp;
-	struct completion irq_comp;
 
 	bool psm_enabled;
 	bool orientation;
@@ -155,7 +159,7 @@
 	config |= tbd << 8;
 
 	/* Num of Lanes */
-	config |= ((ctrl->link->lane_count - 1) << 4);
+	config |= ((ctrl->link->link_params.lane_count - 1) << 4);
 
 	if (drm_dp_enhanced_frame_cap(dpcd))
 		config |= 0x40;
@@ -303,7 +307,7 @@
 	u64 brute_force_threshold = 10;
 	u64 diff_abs;
 
-	ln_cnt =  ctrl->link->lane_count;
+	ln_cnt =  ctrl->link->link_params.lane_count;
 
 	bpp = pinfo->bpp;
 	lwidth = pinfo->h_active;
@@ -322,7 +326,8 @@
 	even_distribution = 0;
 	min_hblank = 0;
 
-	lclk = drm_dp_bw_code_to_link_rate(ctrl->link->bw_code) * DP_KHZ_TO_HZ;
+	lclk = drm_dp_bw_code_to_link_rate(
+		ctrl->link->link_params.bw_code) * DP_KHZ_TO_HZ;
 
 	pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n",
 						pclk, lwidth, h_blank);
@@ -761,9 +766,10 @@
 	struct dp_link *link = ctrl->link;
 
 	ctrl->catalog->update_vx_px(ctrl->catalog,
-			link->v_level, link->p_level);
+		link->phy_params.v_level, link->phy_params.p_level);
 
-	dp_ctrl_update_sink_vx_px(ctrl, link->v_level, link->p_level);
+	dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level,
+		link->phy_params.p_level);
 }
 
 static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
@@ -816,7 +822,7 @@
 	dp_ctrl_update_vx_px(ctrl);
 
 	tries = 0;
-	old_v_level = ctrl->link->v_level;
+	old_v_level = ctrl->link->phy_params.v_level;
 	while (1) {
 		drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
 
@@ -825,26 +831,26 @@
 			break;
 
 		if (drm_dp_clock_recovery_ok(link_status,
-			ctrl->link->lane_count)) {
+			ctrl->link->link_params.lane_count)) {
 			break;
 		}
 
-		if (ctrl->link->v_level == DP_LINK_VOLTAGE_MAX) {
+		if (ctrl->link->phy_params.v_level == DP_LINK_VOLTAGE_MAX) {
 			pr_err_ratelimited("max v_level reached\n");
 			ret = -EAGAIN;
 			break;
 		}
 
-		if (old_v_level == ctrl->link->v_level) {
+		if (old_v_level == ctrl->link->phy_params.v_level) {
 			tries++;
 			if (tries >= maximum_retries) {
 				pr_err("max tries reached\n");
-				ret = -EAGAIN;
+				ret = -ETIMEDOUT;
 				break;
 			}
 		} else {
 			tries = 0;
-			old_v_level = ctrl->link->v_level;
+			old_v_level = ctrl->link->phy_params.v_level;
 		}
 
 		pr_debug("clock recovery not done, adjusting vx px\n");
@@ -859,41 +865,25 @@
 static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
 {
 	int ret = 0;
-	u32 min_req_link_rate_khz;
-	u32 new_proposed_link_bw_code;
-	u32 new_proposed_link_rate_khz;
 
 	if (!ctrl)
 		return -EINVAL;
 
-	min_req_link_rate_khz = ctrl->panel->get_min_req_link_rate(ctrl->panel);
-
-	switch (ctrl->link->bw_code) {
-	case DP_LINK_RATE_810:
-		new_proposed_link_bw_code = DP_LINK_BW_5_4;
+	switch (ctrl->link->link_params.bw_code) {
+	case DP_LINK_BW_8_1:
+		ctrl->link->link_params.bw_code = DP_LINK_BW_5_4;
 		break;
 	case DP_LINK_BW_5_4:
-		new_proposed_link_bw_code = DP_LINK_BW_2_7;
+		ctrl->link->link_params.bw_code = DP_LINK_BW_2_7;
 		break;
 	case DP_LINK_BW_2_7:
 	case DP_LINK_BW_1_62:
 	default:
-		new_proposed_link_bw_code = DP_LINK_BW_1_62;
+		ctrl->link->link_params.bw_code = DP_LINK_BW_1_62;
 		break;
 	};
 
-	new_proposed_link_rate_khz = drm_dp_bw_code_to_link_rate(
-						new_proposed_link_bw_code);
-
-	pr_debug("new proposed link rate=%d khz\n", new_proposed_link_rate_khz);
-	pr_debug("min required link rate=%d khz\n", min_req_link_rate_khz);
-
-	if (new_proposed_link_rate_khz >= min_req_link_rate_khz)
-		ctrl->link->bw_code = new_proposed_link_bw_code;
-	else
-		pr_debug("can't go below min required link rate\n");
-
-	pr_debug("new bw code=0x%x\n", ctrl->link->bw_code);
+	pr_debug("new bw code=0x%x\n", ctrl->link->link_params.bw_code);
 
 	return ret;
 }
@@ -931,11 +921,12 @@
 		if (ret)
 			break;
 
-		if (drm_dp_channel_eq_ok(link_status, ctrl->link->lane_count))
+		if (drm_dp_channel_eq_ok(link_status,
+			ctrl->link->link_params.lane_count))
 			break;
 
 		if (tries > maximum_retries) {
-			ret = -EAGAIN;
+			ret = -ETIMEDOUT;
 			break;
 		}
 		tries++;
@@ -953,13 +944,14 @@
 	u8 encoding = 0x1;
 	struct drm_dp_link link_info = {0};
 
-	ctrl->link->p_level = 0;
-	ctrl->link->v_level = 0;
+	ctrl->link->phy_params.p_level = 0;
+	ctrl->link->phy_params.v_level = 0;
 
 	dp_ctrl_config_ctrl(ctrl);
 
-	link_info.num_lanes = ctrl->link->lane_count;
-	link_info.rate = drm_dp_bw_code_to_link_rate(ctrl->link->bw_code);
+	link_info.num_lanes = ctrl->link->link_params.lane_count;
+	link_info.rate = drm_dp_bw_code_to_link_rate(
+		ctrl->link->link_params.bw_code);
 	link_info.capabilities = ctrl->panel->link_info.capabilities;
 
 	drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
@@ -1002,7 +994,7 @@
 
 	drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->link_info);
 
-	if (ctrl->link->phy_pattern_requested(ctrl->link))
+	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
 		goto end;
 
 	if (!train)
@@ -1060,7 +1052,7 @@
 	ctrl->power->set_pixel_clk_parent(ctrl->power);
 
 	dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk",
-		drm_dp_bw_code_to_link_rate(ctrl->link->bw_code));
+		drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code));
 
 	dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate);
 
@@ -1093,6 +1085,7 @@
 	ctrl->orientation = flip;
 	catalog = ctrl->catalog;
 
+	catalog->usb_reset(ctrl->catalog, flip);
 	catalog->reset(ctrl->catalog);
 	catalog->phy_reset(ctrl->catalog);
 	catalog->enable_irq(ctrl->catalog, true);
@@ -1147,95 +1140,223 @@
 	return false;
 }
 
-static int dp_ctrl_on_irq(struct dp_ctrl_private *ctrl, bool lt_needed)
+static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
 {
 	int ret = 0;
 
+	ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
+	ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
+
+	ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
+
 	do {
-		if (ret == -EAGAIN)
+		if (ret == -EAGAIN) {
+			/* try with lower link rate */
+			dp_ctrl_link_rate_down_shift(ctrl);
+
 			ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
+		}
 
 		ctrl->catalog->phy_lane_cfg(ctrl->catalog,
-			ctrl->orientation, ctrl->link->lane_count);
+			ctrl->orientation, ctrl->link->link_params.lane_count);
 
-		if (lt_needed) {
-			/*
-			 * Diasable and re-enable the mainlink clock since the
-			 * link clock might have been adjusted as part of the
-			 * link maintenance.
-			 */
-			if (!ctrl->link->phy_pattern_requested(
-					ctrl->link))
-				dp_ctrl_disable_mainlink_clocks(ctrl);
+		/*
+		 * Disable and re-enable the mainlink clock since the
+		 * link clock might have been adjusted as part of the
+		 * link maintenance.
+		 */
+		dp_ctrl_disable_mainlink_clocks(ctrl);
 
-			ret = dp_ctrl_enable_mainlink_clocks(ctrl);
-			if (ret)
-				continue;
-		}
+		ret = dp_ctrl_enable_mainlink_clocks(ctrl);
+		if (ret)
+			continue;
 
 		dp_ctrl_configure_source_params(ctrl);
 
 		ctrl->catalog->config_msa(ctrl->catalog,
-			drm_dp_bw_code_to_link_rate(ctrl->link->bw_code),
+			drm_dp_bw_code_to_link_rate(
+			ctrl->link->link_params.bw_code),
 			ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
 
 		reinit_completion(&ctrl->idle_comp);
 
-		if (ctrl->psm_enabled) {
-			ret = ctrl->link->send_psm_request(ctrl->link, false);
-			if (ret) {
-				pr_err("failed to exit low power mode, rc=%d\n",
-					ret);
-				continue;
-			}
-		}
-
-		ret = dp_ctrl_setup_main_link(ctrl, lt_needed);
+		ret = dp_ctrl_setup_main_link(ctrl, true);
 	} while (ret == -EAGAIN);
 
 	return ret;
 }
 
-static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl)
+static void dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
 {
 	int ret = 0;
-	u32 rate = ctrl->panel->link_info.rate;
+
+	if (!ctrl->link->phy_params.phy_test_pattern_sel) {
+		pr_debug("no test pattern selected by sink\n");
+		return;
+	}
+
+	pr_debug("start\n");
+
+	ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
+	/*
+	 * The global reset will need DP link ralated clocks to be
+	 * running. Add the global reset just before disabling the
+	 * link clocks and core clocks.
+	 */
+	ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
+	ctrl->dp_ctrl.off(&ctrl->dp_ctrl);
+
+	ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl);
+	if (ret)
+		pr_err("failed to enable DP controller\n");
+
+	pr_debug("end\n");
+}
+
+static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
+{
+	bool success = false;
+	u32 pattern_sent = 0x0;
+	u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
+
+	pr_debug("request: %s\n",
+			dp_link_get_phy_test_pattern(pattern_requested));
+
+	ctrl->catalog->update_vx_px(ctrl->catalog,
+			ctrl->link->phy_params.v_level,
+			ctrl->link->phy_params.p_level);
+	ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested);
+	ctrl->link->send_test_response(ctrl->link);
+
+	pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog);
+
+	switch (pattern_sent) {
+	case MR_LINK_TRAINING1:
+		if (pattern_requested ==
+				DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING)
+			success = true;
+		break;
+	case MR_LINK_SYMBOL_ERM:
+		if ((pattern_requested ==
+				DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT)
+			|| (pattern_requested ==
+				DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN))
+			success = true;
+		break;
+	case MR_LINK_PRBS7:
+		if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7)
+			success = true;
+		break;
+	case MR_LINK_CUSTOM80:
+		if (pattern_requested ==
+				DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN)
+			success = true;
+		break;
+	default:
+		success = false;
+		return;
+	}
+
+	pr_debug("%s: %s\n", success ? "success" : "failed",
+			dp_link_get_phy_test_pattern(pattern_requested));
+}
+
+static void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl)
+{
+	struct dp_ctrl_private *ctrl;
+	u32 sink_request = 0x0;
+
+	if (!dp_ctrl) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+	sink_request = ctrl->link->sink_request;
+
+	if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
+		pr_info("PHY_TEST_PATTERN request\n");
+		dp_ctrl_process_phy_test_request(ctrl);
+	}
+
+	if (sink_request & DP_LINK_STATUS_UPDATED)
+		dp_ctrl_link_maintenance(ctrl);
+
+	if (sink_request & DP_TEST_LINK_TRAINING) {
+		ctrl->link->send_test_response(ctrl->link);
+		dp_ctrl_link_maintenance(ctrl);
+	}
+}
+
+static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl)
+{
+	struct dp_ctrl_private *ctrl;
+
+	if (!dp_ctrl) {
+		pr_err("invalid params\n");
+		return;
+	}
+
+	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+	ctrl->catalog->reset(ctrl->catalog);
+}
+
+static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
+{
+	int rc = 0;
+	struct dp_ctrl_private *ctrl;
+	u32 rate = 0;
 	u32 link_train_max_retries = 100;
+	u32 const phy_cts_pixel_clk_khz = 148500;
+
+	if (!dp_ctrl) {
+		rc = -EINVAL;
+		goto end;
+	}
+
+	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
 	atomic_set(&ctrl->aborted, 0);
+	rate = ctrl->panel->link_info.rate;
 
 	ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true);
 	ctrl->catalog->hpd_config(ctrl->catalog, true);
 
-	ctrl->link->bw_code  = drm_dp_link_rate_to_bw_code(rate);
-	ctrl->link->lane_count = ctrl->panel->link_info.num_lanes;
-	ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
+	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
+		pr_debug("using phy test link parameters\n");
+		if (!ctrl->panel->pinfo.pixel_clk_khz)
+			ctrl->pixel_rate = phy_cts_pixel_clk_khz;
+	} else {
+		ctrl->link->link_params.bw_code =
+			drm_dp_link_rate_to_bw_code(rate);
+		ctrl->link->link_params.lane_count =
+			ctrl->panel->link_info.num_lanes;
+		ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
+	}
 
 	pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n",
-		ctrl->link->bw_code, ctrl->link->lane_count,
-		ctrl->pixel_rate);
+		ctrl->link->link_params.bw_code,
+		ctrl->link->link_params.lane_count, ctrl->pixel_rate);
 
 	ctrl->catalog->phy_lane_cfg(ctrl->catalog,
-			ctrl->orientation, ctrl->link->lane_count);
+			ctrl->orientation, ctrl->link->link_params.lane_count);
 
-	ret = dp_ctrl_enable_mainlink_clocks(ctrl);
-	if (ret)
-		goto exit;
+	rc = dp_ctrl_enable_mainlink_clocks(ctrl);
+	if (rc)
+		goto end;
 
 	reinit_completion(&ctrl->idle_comp);
 
 	dp_ctrl_configure_source_params(ctrl);
 
-	if (ctrl->psm_enabled)
-		ret = ctrl->link->send_psm_request(ctrl->link, false);
-
 	while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
 		ctrl->catalog->config_msa(ctrl->catalog,
-			drm_dp_bw_code_to_link_rate(ctrl->link->bw_code),
+			drm_dp_bw_code_to_link_rate(
+			ctrl->link->link_params.bw_code),
 			ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
 
-		ret = dp_ctrl_setup_main_link(ctrl, true);
-		if (!ret)
+		rc = dp_ctrl_setup_main_link(ctrl, true);
+		if (!rc)
 			break;
 
 		/* try with lower link rate */
@@ -1250,50 +1371,16 @@
 		dp_ctrl_enable_mainlink_clocks(ctrl);
 	}
 
+	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
+		dp_ctrl_send_phy_test_pattern(ctrl);
+
 	pr_debug("End-\n");
 
-exit:
-	return ret;
-}
-
-static void dp_ctrl_off_irq(struct dp_ctrl_private *ctrl)
-{
-	ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
-
-	/* Make sure DP mainlink and audio engines are disabled */
-	wmb();
-
-	complete_all(&ctrl->irq_comp);
-	pr_debug("end\n");
-}
-
-static void dp_ctrl_off_hpd(struct dp_ctrl_private *ctrl)
-{
-	ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
-	pr_debug("DP off done\n");
-}
-
-static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool hpd_irq)
-{
-	int rc = 0;
-	struct dp_ctrl_private *ctrl;
-
-	if (!dp_ctrl) {
-		rc = -EINVAL;
-		goto end;
-	}
-
-	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
-
-	if (hpd_irq)
-		rc = dp_ctrl_on_irq(ctrl, false);
-	else
-		rc = dp_ctrl_on_hpd(ctrl);
 end:
 	return rc;
 }
 
-static void dp_ctrl_off(struct dp_ctrl *dp_ctrl, bool hpd_irq)
+static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
 {
 	struct dp_ctrl_private *ctrl;
 
@@ -1302,10 +1389,9 @@
 
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
-	if (hpd_irq)
-		dp_ctrl_off_irq(ctrl);
-	else
-		dp_ctrl_off_hpd(ctrl);
+	ctrl->catalog->mainlink_ctrl(ctrl->catalog, false);
+	pr_debug("DP off done\n");
+
 }
 
 static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
@@ -1347,7 +1433,6 @@
 
 	init_completion(&ctrl->idle_comp);
 	init_completion(&ctrl->video_comp);
-	init_completion(&ctrl->irq_comp);
 
 	/* in parameters */
 	ctrl->parser   = in->parser;
@@ -1367,6 +1452,8 @@
 	dp_ctrl->push_idle = dp_ctrl_push_idle;
 	dp_ctrl->abort     = dp_ctrl_abort;
 	dp_ctrl->isr       = dp_ctrl_isr;
+	dp_ctrl->reset	   = dp_ctrl_reset;
+	dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request;
 
 	return dp_ctrl;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 2ecfa0d..69cf6b6 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -23,13 +23,16 @@
 #include "dp_catalog.h"
 
 struct dp_ctrl {
+
 	int (*init)(struct dp_ctrl *dp_ctrl, bool flip);
 	void (*deinit)(struct dp_ctrl *dp_ctrl);
-	int (*on)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
-	void (*off)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
+	int (*on)(struct dp_ctrl *dp_ctrl);
+	void (*off)(struct dp_ctrl *dp_ctrl);
+	void (*reset)(struct dp_ctrl *dp_ctrl);
 	void (*push_idle)(struct dp_ctrl *dp_ctrl);
 	void (*abort)(struct dp_ctrl *dp_ctrl);
 	void (*isr)(struct dp_ctrl *dp_ctrl);
+	void (*handle_sink_request)(struct dp_ctrl *dp_ctrl);
 };
 
 struct dp_ctrl_in {
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 82e34df..cc9e623 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -306,33 +306,34 @@
 	/* Link Information */
 	rc = snprintf(buf + len, max_size,
 		"\tdp_link:\n\t\ttest_requested = %d\n",
-		debug->link->test_requested);
+		debug->link->sink_request);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tlane_count = %d\n", debug->link->lane_count);
+		"\t\tlane_count = %d\n", debug->link->link_params.lane_count);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tbw_code = %d\n", debug->link->bw_code);
+		"\t\tbw_code = %d\n", debug->link->link_params.bw_code);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	lclk = drm_dp_bw_code_to_link_rate(debug->link->bw_code) * 1000;
+	lclk = drm_dp_bw_code_to_link_rate(
+			debug->link->link_params.bw_code) * 1000;
 	rc = snprintf(buf + len, max_size,
 		"\t\tlclk = %lld\n", lclk);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tv_level = %d\n", debug->link->v_level);
+		"\t\tv_level = %d\n", debug->link->phy_params.v_level);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tp_level = %d\n", debug->link->p_level);
+		"\t\tp_level = %d\n", debug->link->phy_params.p_level);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 7e40cc6..3fa376b 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -422,6 +422,50 @@
 	.unbind = dp_display_unbind,
 };
 
+static bool dp_display_is_ds_bridge(struct dp_panel *panel)
+{
+	return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+		DP_DWN_STRM_PORT_PRESENT);
+}
+
+static bool dp_display_is_sink_count_zero(struct dp_display_private *dp)
+{
+	return dp_display_is_ds_bridge(dp->panel) &&
+		(dp->link->sink_count.count == 0);
+}
+
+static int dp_display_send_hpd_notification(struct dp_display_private *dp,
+		bool hpd)
+{
+
+	if ((hpd && dp->dp_display.is_connected) ||
+			(!hpd && !dp->dp_display.is_connected)) {
+		pr_info("HPD already %s\n", (hpd ? "on" : "off"));
+		return 0;
+	}
+
+	dp->dp_display.is_connected = hpd;
+	reinit_completion(&dp->notification_comp);
+	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+
+	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) {
+		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void dp_display_handle_test_edid(struct dp_display_private *dp)
+{
+	if (dp->link->sink_request & DP_TEST_LINK_EDID_READ) {
+		drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_EDID_CHECKSUM,
+			&dp->panel->edid_ctrl->edid->checksum, 1);
+		drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_RESPONSE,
+			&dp->link->test_response, 1);
+	}
+}
+
 static int dp_display_process_hpd_high(struct dp_display_private *dp)
 {
 	int rc = 0;
@@ -432,23 +476,28 @@
 	if (rc)
 		return rc;
 
+	dp->link->process_request(dp->link);
+
+	if (dp_display_is_sink_count_zero(dp)) {
+		pr_debug("no downstream devices connected\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
 	edid = dp->panel->edid_ctrl->edid;
 
 	dp->audio_supported = drm_detect_monitor_audio(edid);
 
+	dp_display_handle_test_edid(dp);
+
 	max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);
 
 	dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
 		dp->parser->max_pclk_khz);
 
-	dp->dp_display.is_connected = true;
+	dp_display_send_hpd_notification(dp, true);
 
-	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
-
-	reinit_completion(&dp->notification_comp);
-	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
-		pr_warn("timeout\n");
-
+end:
 	return rc;
 }
 
@@ -498,12 +547,7 @@
 	if (dp->audio_supported)
 		dp->audio->off(dp->audio);
 
-	dp->dp_display.is_connected = false;
-	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
-
-	reinit_completion(&dp->notification_comp);
-	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2))
-		pr_warn("timeout\n");
+	dp_display_send_hpd_notification(dp, false);
 }
 
 static int dp_display_usbpd_configure_cb(struct device *dev)
@@ -543,7 +587,7 @@
 	}
 
 	dp->ctrl->push_idle(dp->ctrl);
-	dp->ctrl->off(dp->ctrl, false);
+	dp->ctrl->off(dp->ctrl);
 }
 
 static int dp_display_usbpd_disconnect_cb(struct device *dev)
@@ -570,22 +614,34 @@
 	if (dp->audio_supported)
 		dp->audio->off(dp->audio);
 
-	dp->dp_display.is_connected = false;
-	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+	rc = dp_display_send_hpd_notification(dp, false);
 
-	reinit_completion(&dp->notification_comp);
-	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) {
-		pr_warn("timeout\n");
-
-		if (dp->power_on)
-			dp_display_clean(dp);
-	}
+	if ((rc < 0) && dp->power_on)
+		dp_display_clean(dp);
 
 	dp_display_host_deinit(dp);
 end:
 	return rc;
 }
 
+static int dp_display_handle_hpd_irq(struct dp_display_private *dp)
+{
+	if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) {
+		dp_display_send_hpd_notification(dp, false);
+
+		if (dp_display_is_sink_count_zero(dp)) {
+			pr_debug("sink count is zero, nothing to do\n");
+			return 0;
+		}
+
+		return dp_display_process_hpd_high(dp);
+	}
+
+	dp->ctrl->handle_sink_request(dp->ctrl);
+
+	return 0;
+}
+
 static int dp_display_usbpd_attention_cb(struct device *dev)
 {
 	int rc = 0;
@@ -611,9 +667,12 @@
 		}
 
 		rc = dp->link->process_request(dp->link);
-		dp->hpd_irq_on = false;
+		/* check for any test request issued by sink */
 		if (!rc)
-			goto end;
+			dp_display_handle_hpd_irq(dp);
+
+		dp->hpd_irq_on = false;
+		goto end;
 	}
 
 	if (!dp->usbpd->hpd_high) {
@@ -757,7 +816,12 @@
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
-	rc = dp->ctrl->on(dp->ctrl, dp->hpd_irq_on);
+	if (dp->power_on) {
+		pr_debug("Link already setup, return\n");
+		return 0;
+	}
+
+	rc = dp->ctrl->on(dp->ctrl);
 	if (!rc)
 		dp->power_on = true;
 error:
@@ -778,8 +842,8 @@
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
 	if (dp->audio_supported) {
-		dp->audio->bw_code = dp->link->bw_code;
-		dp->audio->lane_count = dp->link->lane_count;
+		dp->audio->bw_code = dp->link->link_params.bw_code;
+		dp->audio->lane_count = dp->link->link_params.lane_count;
 		dp->audio->on(dp->audio);
 	}
 
@@ -840,7 +904,7 @@
 	if (!dp->power_on || !dp->core_initialized)
 		goto error;
 
-	dp->ctrl->off(dp->ctrl, dp->hpd_irq_on);
+	dp->ctrl->off(dp->ctrl);
 
 	dp->power_on = false;
 
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 48e6c8f..b62c1e9 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -17,8 +17,6 @@
 #include "dp_link.h"
 #include "dp_panel.h"
 
-#define DP_LINK_ENUM_STR(x)		#x
-
 enum dp_lane_count {
 	DP_LANE_COUNT_1	= 1,
 	DP_LANE_COUNT_2	= 2,
@@ -50,48 +48,15 @@
 	u32 test_requested;
 	u32 test_link_rate;
 	u32 test_lane_count;
-	u32 phy_test_pattern_sel;
-	u32 test_video_pattern;
-	u32 test_bit_depth;
-	u32 test_dyn_range;
-	u32 test_h_total;
-	u32 test_v_total;
-	u32 test_h_start;
-	u32 test_v_start;
-	u32 test_hsync_pol;
-	u32 test_hsync_width;
-	u32 test_vsync_pol;
-	u32 test_vsync_width;
-	u32 test_h_width;
-	u32 test_v_height;
-	u32 test_rr_d;
-	u32 test_rr_n;
-	u32 test_audio_sampling_rate;
-	u32 test_audio_channel_count;
-	u32 test_audio_pattern_type;
-	u32 test_audio_period_ch_1;
-	u32 test_audio_period_ch_2;
-	u32 test_audio_period_ch_3;
-	u32 test_audio_period_ch_4;
-	u32 test_audio_period_ch_5;
-	u32 test_audio_period_ch_6;
-	u32 test_audio_period_ch_7;
-	u32 test_audio_period_ch_8;
-	u32 response;
-};
-
-struct dp_link_sink_count {
-	u32 count;
-	bool cp_ready;
 };
 
 struct dp_link_private {
+	u32 prev_sink_count;
 	struct device *dev;
 	struct dp_aux *aux;
 	struct dp_link dp_link;
 
 	struct dp_link_request request;
-	struct dp_link_sink_count sink_count;
 	u8 link_status[DP_LINK_STATUS_SIZE];
 };
 
@@ -131,30 +96,6 @@
 	return bpp;
 }
 
-static char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel)
-{
-	switch (phy_test_pattern_sel) {
-	case DP_TEST_PHY_PATTERN_NONE:
-		return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE);
-	case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
-		return DP_LINK_ENUM_STR(
-			DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING);
-	case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
-		return DP_LINK_ENUM_STR(
-			DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
-	case DP_TEST_PHY_PATTERN_PRBS7:
-		return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7);
-	case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
-		return DP_LINK_ENUM_STR(
-			DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN);
-	case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
-		return DP_LINK_ENUM_STR(
-			DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN);
-	default:
-		return "unknown";
-	}
-}
-
 static char *dp_link_get_audio_test_pattern(u32 pattern)
 {
 	switch (pattern) {
@@ -223,7 +164,7 @@
 static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
 {
 	int ret = 0;
-	struct dp_link_request *req = &link->request;
+	struct dp_link_test_audio *req = &link->dp_link.test_audio;
 
 	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1);
 	if (ret == -EINVAL)
@@ -310,7 +251,7 @@
 		goto exit;
 	}
 
-	link->request.test_audio_pattern_type = data;
+	link->dp_link.test_audio.test_audio_pattern_type = data;
 	pr_debug("audio pattern type = %s\n",
 			dp_link_get_audio_test_pattern(data));
 exit:
@@ -356,8 +297,8 @@
 		goto exit;
 	}
 
-	link->request.test_audio_sampling_rate = sampling_rate;
-	link->request.test_audio_channel_count = channel_count;
+	link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate;
+	link->dp_link.test_audio.test_audio_channel_count = channel_count;
 	pr_debug("sampling_rate = %s, channel_count = 0x%x\n",
 		dp_link_get_audio_sample_rate(sampling_rate), channel_count);
 exit:
@@ -578,11 +519,11 @@
 		goto exit;
 	}
 
-	link->request.test_video_pattern = data;
+	link->dp_link.test_video.test_video_pattern = data;
 	pr_debug("link video pattern = 0x%x (%s)\n",
-		link->request.test_video_pattern,
+		link->dp_link.test_video.test_video_pattern,
 		dp_link_video_pattern_to_string(
-			link->request.test_video_pattern));
+			link->dp_link.test_video.test_video_pattern));
 
 	/* Read the requested color bit depth and dynamic range (Byte 0x232) */
 	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_MISC0,
@@ -601,11 +542,11 @@
 		ret = -EINVAL;
 		goto exit;
 	}
-	link->request.test_dyn_range = dyn_range;
+	link->dp_link.test_video.test_dyn_range = dyn_range;
 	pr_debug("link dynamic range = 0x%x (%s)\n",
-		link->request.test_dyn_range,
+		link->dp_link.test_video.test_dyn_range,
 		dp_link_dynamic_range_to_string(
-			link->request.test_dyn_range));
+			link->dp_link.test_video.test_dyn_range));
 
 	/* Color bit depth */
 	data &= DP_TEST_BIT_DEPTH_MASK;
@@ -615,96 +556,104 @@
 		goto exit;
 	}
 
-	link->request.test_bit_depth = data;
+	link->dp_link.test_video.test_bit_depth = data;
 	pr_debug("link bit depth = 0x%x (%s)\n",
-		link->request.test_bit_depth,
-		dp_link_bit_depth_to_string(link->request.test_bit_depth));
+		link->dp_link.test_video.test_bit_depth,
+		dp_link_bit_depth_to_string(
+		link->dp_link.test_video.test_bit_depth));
 
 	/* resolution timing params */
 	ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2,
-			&link->request.test_h_total);
+			&link->dp_link.test_video.test_h_total);
 	if (ret) {
 		pr_err("failed to parse test_h_total (DP_TEST_H_TOTAL_HI)\n");
 		goto exit;
 	}
-	pr_debug("TEST_H_TOTAL = %d\n", link->request.test_h_total);
+	pr_debug("TEST_H_TOTAL = %d\n", link->dp_link.test_video.test_h_total);
 
 	ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2,
-			&link->request.test_v_total);
+			&link->dp_link.test_video.test_v_total);
 	if (ret) {
 		pr_err("failed to parse test_v_total (DP_TEST_V_TOTAL_HI)\n");
 		goto exit;
 	}
-	pr_debug("TEST_V_TOTAL = %d\n", link->request.test_v_total);
+	pr_debug("TEST_V_TOTAL = %d\n", link->dp_link.test_video.test_v_total);
 
 	ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2,
-			&link->request.test_h_start);
+			&link->dp_link.test_video.test_h_start);
 	if (ret) {
 		pr_err("failed to parse test_h_start (DP_TEST_H_START_HI)\n");
 		goto exit;
 	}
-	pr_debug("TEST_H_START = %d\n", link->request.test_h_start);
+	pr_debug("TEST_H_START = %d\n", link->dp_link.test_video.test_h_start);
 
 	ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2,
-			&link->request.test_v_start);
+			&link->dp_link.test_video.test_v_start);
 	if (ret) {
 		pr_err("failed to parse test_v_start (DP_TEST_V_START_HI)\n");
 		goto exit;
 	}
-	pr_debug("TEST_V_START = %d\n", link->request.test_v_start);
+	pr_debug("TEST_V_START = %d\n", link->dp_link.test_video.test_v_start);
 
 	ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2,
-			&link->request.test_hsync_pol,
-			&link->request.test_hsync_width);
+			&link->dp_link.test_video.test_hsync_pol,
+			&link->dp_link.test_video.test_hsync_width);
 	if (ret) {
 		pr_err("failed to parse (DP_TEST_HSYNC_HI)\n");
 		goto exit;
 	}
-	pr_debug("TEST_HSYNC_POL = %d\n", link->request.test_hsync_pol);
-	pr_debug("TEST_HSYNC_WIDTH = %d\n", link->request.test_hsync_width);
+	pr_debug("TEST_HSYNC_POL = %d\n",
+		link->dp_link.test_video.test_hsync_pol);
+	pr_debug("TEST_HSYNC_WIDTH = %d\n",
+		link->dp_link.test_video.test_hsync_width);
 
 	ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2,
-			&link->request.test_vsync_pol,
-			&link->request.test_vsync_width);
+			&link->dp_link.test_video.test_vsync_pol,
+			&link->dp_link.test_video.test_vsync_width);
 	if (ret) {
 		pr_err("failed to parse (DP_TEST_VSYNC_HI)\n");
 		goto exit;
 	}
-	pr_debug("TEST_VSYNC_POL = %d\n", link->request.test_vsync_pol);
-	pr_debug("TEST_VSYNC_WIDTH = %d\n", link->request.test_vsync_width);
+	pr_debug("TEST_VSYNC_POL = %d\n",
+		link->dp_link.test_video.test_vsync_pol);
+	pr_debug("TEST_VSYNC_WIDTH = %d\n",
+		link->dp_link.test_video.test_vsync_width);
 
 	ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2,
-			&link->request.test_h_width);
+			&link->dp_link.test_video.test_h_width);
 	if (ret) {
 		pr_err("failed to parse test_h_width (DP_TEST_H_WIDTH_HI)\n");
 		goto exit;
 	}
-	pr_debug("TEST_H_WIDTH = %d\n", link->request.test_h_width);
+	pr_debug("TEST_H_WIDTH = %d\n", link->dp_link.test_video.test_h_width);
 
 	ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2,
-			&link->request.test_v_height);
+			&link->dp_link.test_video.test_v_height);
 	if (ret) {
 		pr_err("failed to parse test_v_height (DP_TEST_V_HEIGHT_HI)\n");
 		goto exit;
 	}
-	pr_debug("TEST_V_HEIGHT = %d\n", link->request.test_v_height);
+	pr_debug("TEST_V_HEIGHT = %d\n",
+		link->dp_link.test_video.test_v_height);
 
 	ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1,
-		&link->request.test_rr_d);
-	link->request.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;
+		&link->dp_link.test_video.test_rr_d);
+	link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;
 	if (ret) {
 		pr_err("failed to parse test_rr_d (DP_TEST_MISC1)\n");
 		goto exit;
 	}
-	pr_debug("TEST_REFRESH_DENOMINATOR = %d\n", link->request.test_rr_d);
+	pr_debug("TEST_REFRESH_DENOMINATOR = %d\n",
+		link->dp_link.test_video.test_rr_d);
 
 	ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR,
-		&link->request.test_rr_n);
+		&link->dp_link.test_video.test_rr_n);
 	if (ret) {
 		pr_err("failed to parse test_rr_n (DP_TEST_REFRESH_RATE_NUMERATOR)\n");
 		goto exit;
 	}
-	pr_debug("TEST_REFRESH_NUMERATOR = %d\n", link->request.test_rr_n);
+	pr_debug("TEST_REFRESH_NUMERATOR = %d\n",
+		link->dp_link.test_video.test_rr_n);
 exit:
 	return ret;
 }
@@ -720,7 +669,7 @@
 	return ((bw_code == DP_LINK_BW_1_62) ||
 		(bw_code == DP_LINK_BW_2_7) ||
 		(bw_code == DP_LINK_BW_5_4) ||
-		(bw_code == DP_LINK_RATE_810));
+		(bw_code == DP_LINK_BW_8_1));
 }
 
 /**
@@ -832,7 +781,7 @@
 
 	data = bp;
 
-	link->request.phy_test_pattern_sel = data;
+	link->dp_link.phy_params.phy_test_pattern_sel = data;
 
 	pr_debug("phy_test_pattern_sel = %s\n",
 			dp_link_get_phy_test_pattern(data));
@@ -891,6 +840,11 @@
 		dp_link_is_video_audio_test_requested(test_requested);
 }
 
+static bool dp_link_is_test_edid_read(struct dp_link_private *link)
+{
+	return (link->request.test_requested == DP_TEST_LINK_EDID_READ);
+}
+
 /**
  * dp_sink_parse_test_request() - parses link request parameters from sink
  * @link: Display Port Driver data
@@ -972,10 +926,15 @@
 	 * Send a DP_TEST_ACK if all link parameters are valid, otherwise send
 	 * a DP_TEST_NAK.
 	 */
-	if (ret)
-		link->request.response = DP_TEST_NAK;
-	else
-		link->request.response = DP_TEST_ACK;
+	if (ret) {
+		link->dp_link.test_response = DP_TEST_NAK;
+	} else {
+		if (!dp_link_is_test_edid_read(link))
+			link->dp_link.test_response = DP_TEST_ACK;
+		else
+			link->dp_link.test_response =
+				DP_TEST_EDID_CHECKSUM_WRITE;
+	}
 
 	return ret;
 }
@@ -987,46 +946,49 @@
  * (Byte 0x200), and whether all the sink devices connected have Content
  * Protection enabled.
  */
-static void dp_link_parse_sink_count(struct dp_link_private *link)
+static int dp_link_parse_sink_count(struct dp_link *dp_link)
 {
-	u8 bp;
-	u8 data;
 	int rlen;
 	int const param_len = 0x1;
+	struct dp_link_private *link = container_of(dp_link,
+			struct dp_link_private, dp_link);
 
 	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_SINK_COUNT,
-			&bp, param_len);
+			&link->dp_link.sink_count.count, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read sink count\n");
-		return;
+		return -EINVAL;
 	}
 
-	data = bp;
-
+	link->dp_link.sink_count.cp_ready =
+		link->dp_link.sink_count.count & DP_SINK_CP_READY;
 	/* BIT 7, BIT 5:0 */
-	link->sink_count.count = (data & BIT(7)) << 6 | (data & 0x63);
-	/* BIT 6*/
-	link->sink_count.cp_ready = data & BIT(6);
+	link->dp_link.sink_count.count =
+		DP_GET_SINK_COUNT(link->dp_link.sink_count.count);
 
 	pr_debug("sink_count = 0x%x, cp_ready = 0x%x\n",
-		link->sink_count.count, link->sink_count.cp_ready);
+		link->dp_link.sink_count.count,
+		link->dp_link.sink_count.cp_ready);
+	return 0;
 }
 
 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);
+	link->prev_sink_count = link->dp_link.sink_count.count;
+	dp_link_parse_sink_count(&link->dp_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");
+	dp_link_parse_request(link);
 }
 
 static bool dp_link_is_link_training_requested(struct dp_link_private *link)
 {
-	return (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN);
+	return (link->request.test_requested == DP_TEST_LINK_TRAINING);
 }
 
 /**
@@ -1046,24 +1008,34 @@
 		return -EINVAL;
 
 	pr_debug("%s link rate = 0x%x, lane count = 0x%x\n",
-			dp_link_get_test_name(DP_TEST_LINK_PHY_TEST_PATTERN),
+			dp_link_get_test_name(DP_TEST_LINK_TRAINING),
 			link->request.test_link_rate,
 			link->request.test_lane_count);
 
-	link->dp_link.lane_count = link->request.test_lane_count;
-	link->dp_link.bw_code = link->request.test_link_rate;
+	link->dp_link.link_params.lane_count = link->request.test_lane_count;
+	link->dp_link.link_params.bw_code = link->request.test_link_rate;
 
 	return 0;
 }
 
-static bool dp_link_phy_pattern_requested(struct dp_link *dp_link)
+static void dp_link_send_test_response(struct dp_link *dp_link)
 {
-	struct dp_link_private *link = container_of(dp_link,
-			struct dp_link_private, dp_link);
+	struct dp_link_private *link = NULL;
+	u32 const test_response_addr = 0x260;
+	u32 const response_len = 0x1;
 
-	return (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN);
+	if (!dp_link) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	link = container_of(dp_link, struct dp_link_private, dp_link);
+
+	drm_dp_dpcd_write(link->aux->drm_aux, test_response_addr,
+			&dp_link->test_response, response_len);
 }
 
+
 static int dp_link_parse_vx_px(struct dp_link_private *link)
 {
 	u8 bp;
@@ -1127,10 +1099,11 @@
 	 * vector.
 	 */
 	pr_debug("Current: v_level = 0x%x, p_level = 0x%x\n",
-			link->dp_link.v_level, link->dp_link.p_level);
+			link->dp_link.phy_params.v_level,
+			link->dp_link.phy_params.p_level);
 	pr_debug("Requested: v_level = 0x%x, p_level = 0x%x\n", v0, p0);
-	link->dp_link.v_level = v0;
-	link->dp_link.p_level = p0;
+	link->dp_link.phy_params.v_level = v0;
+	link->dp_link.phy_params.p_level = p0;
 
 	pr_debug("Success\n");
 end:
@@ -1150,8 +1123,10 @@
 {
 	u32 test_link_rate = 0, test_lane_count = 0;
 
-	if (!dp_link_phy_pattern_requested(&link->dp_link))
+	if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) {
+		pr_debug("no phy test\n");
 		return -EINVAL;
+	}
 
 	test_link_rate = link->request.test_link_rate;
 	test_lane_count = link->request.test_lane_count;
@@ -1165,8 +1140,15 @@
 
 	pr_debug("start\n");
 
-	link->dp_link.lane_count = link->request.test_lane_count;
-	link->dp_link.bw_code = link->request.test_link_rate;
+	pr_info("Current: bw_code = 0x%x, lane count = 0x%x\n",
+			link->dp_link.link_params.bw_code,
+			link->dp_link.link_params.lane_count);
+
+	pr_info("Requested: bw_code = 0x%x, lane count = 0x%x\n",
+			test_link_rate, test_lane_count);
+
+	link->dp_link.link_params.lane_count = link->request.test_lane_count;
+	link->dp_link.link_params.bw_code = link->request.test_link_rate;
 
 	dp_link_parse_vx_px(link);
 
@@ -1196,16 +1178,16 @@
 	if (!(get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
 		DP_LINK_STATUS_UPDATED) || /* link status updated */
 		(drm_dp_clock_recovery_ok(link->link_status,
-			link->dp_link.lane_count) &&
+			link->dp_link.link_params.lane_count) &&
 	     drm_dp_channel_eq_ok(link->link_status,
-			link->dp_link.lane_count)))
+			link->dp_link.link_params.lane_count)))
 		return -EINVAL;
 
 	pr_debug("channel_eq_done = %d, clock_recovery_done = %d\n",
 			drm_dp_clock_recovery_ok(link->link_status,
-			link->dp_link.lane_count),
+			link->dp_link.link_params.lane_count),
 			drm_dp_clock_recovery_ok(link->link_status,
-			link->dp_link.lane_count));
+			link->dp_link.link_params.lane_count));
 
 	return 0;
 }
@@ -1216,6 +1198,9 @@
 		DP_DOWNSTREAM_PORT_STATUS_CHANGED) /* port status changed */
 		return true;
 
+	if (link->prev_sink_count != link->dp_link.sink_count.count)
+		return true;
+
 	return false;
 }
 
@@ -1235,6 +1220,9 @@
 	if (!dp_link_is_ds_port_status_changed(link))
 		return -EINVAL;
 
+	/* reset prev_sink_count */
+	link->prev_sink_count = link->dp_link.sink_count.count;
+
 	return 0;
 }
 
@@ -1267,10 +1255,11 @@
 
 	pr_debug("%s: bit depth=%d(%d bpp) pattern=%s\n",
 		dp_link_get_test_name(DP_TEST_LINK_VIDEO_PATTERN),
-		link->request.test_bit_depth,
-		dp_link_bit_depth_to_bpp(link->request.test_bit_depth),
+		link->dp_link.test_video.test_bit_depth,
+		dp_link_bit_depth_to_bpp(
+		link->dp_link.test_video.test_bit_depth),
 		dp_link_video_pattern_to_string(
-			link->request.test_video_pattern));
+			link->dp_link.test_video.test_video_pattern));
 
 	return 0;
 end:
@@ -1293,22 +1282,22 @@
 
 	pr_debug("sampling_rate=%s, channel_count=%d, pattern_type=%s\n",
 		dp_link_get_audio_sample_rate(
-			link->request.test_audio_sampling_rate),
-		link->request.test_audio_channel_count,
+			link->dp_link.test_audio.test_audio_sampling_rate),
+		link->dp_link.test_audio.test_audio_channel_count,
 		dp_link_get_audio_test_pattern(
-			link->request.test_audio_pattern_type));
+			link->dp_link.test_audio.test_audio_pattern_type));
 
 	pr_debug("audio_period: ch1=0x%x, ch2=0x%x, ch3=0x%x, ch4=0x%x\n",
-		link->request.test_audio_period_ch_1,
-		link->request.test_audio_period_ch_2,
-		link->request.test_audio_period_ch_3,
-		link->request.test_audio_period_ch_4);
+		link->dp_link.test_audio.test_audio_period_ch_1,
+		link->dp_link.test_audio.test_audio_period_ch_2,
+		link->dp_link.test_audio.test_audio_period_ch_3,
+		link->dp_link.test_audio.test_audio_period_ch_4);
 
 	pr_debug("audio_period: ch5=0x%x, ch6=0x%x, ch7=0x%x, ch8=0x%x\n",
-		link->request.test_audio_period_ch_5,
-		link->request.test_audio_period_ch_6,
-		link->request.test_audio_period_ch_7,
-		link->request.test_audio_period_ch_8);
+		link->dp_link.test_audio.test_audio_period_ch_5,
+		link->dp_link.test_audio.test_audio_period_ch_6,
+		link->dp_link.test_audio.test_audio_period_ch_7,
+		link->dp_link.test_audio.test_audio_period_ch_8);
 
 	return 0;
 }
@@ -1316,8 +1305,12 @@
 static void dp_link_reset_data(struct dp_link_private *link)
 {
 	link->request = (const struct dp_link_request){ 0 };
-	link->request.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;
-	link->dp_link.test_requested = 0;
+	link->dp_link.test_video = (const struct dp_link_test_video){ 0 };
+	link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;
+	link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 };
+	link->dp_link.phy_params.phy_test_pattern_sel = 0;
+	link->dp_link.sink_request = 0;
+	link->dp_link.test_response = 0;
 }
 
 /**
@@ -1346,39 +1339,44 @@
 
 	dp_link_parse_sink_status_field(link);
 
-	ret = dp_link_process_link_training_request(link);
-	if (!ret) {
-		dp_link->test_requested |= DP_TEST_LINK_TRAINING;
-		goto exit;
-	}
-
-	ret = dp_link_process_phy_test_pattern_request(link);
-	if (!ret) {
-		dp_link->test_requested |= DP_TEST_LINK_PHY_TEST_PATTERN;
-		goto exit;
-	}
-
-	ret = dp_link_process_link_status_update(link);
-	if (!ret) {
-		dp_link->test_requested |= DP_LINK_STATUS_UPDATED;
+	if (dp_link_is_test_edid_read(link)) {
+		dp_link->sink_request |= DP_TEST_LINK_EDID_READ;
 		goto exit;
 	}
 
 	ret = dp_link_process_ds_port_status_change(link);
 	if (!ret) {
-		dp_link->test_requested |= DS_PORT_STATUS_CHANGED;
+		dp_link->sink_request |= DS_PORT_STATUS_CHANGED;
+		goto exit;
+	}
+
+	ret = dp_link_process_link_training_request(link);
+	if (!ret) {
+		dp_link->sink_request |= DP_TEST_LINK_TRAINING;
+		goto exit;
+	}
+
+	ret = dp_link_process_phy_test_pattern_request(link);
+	if (!ret) {
+		dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN;
+		goto exit;
+	}
+
+	ret = dp_link_process_link_status_update(link);
+	if (!ret) {
+		dp_link->sink_request |= DP_LINK_STATUS_UPDATED;
 		goto exit;
 	}
 
 	ret = dp_link_process_video_pattern_request(link);
 	if (!ret) {
-		dp_link->test_requested |= DP_TEST_LINK_VIDEO_PATTERN;
+		dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN;
 		goto exit;
 	}
 
 	ret = dp_link_process_audio_pattern_request(link);
 	if (!ret) {
-		dp_link->test_requested |= DP_TEST_LINK_AUDIO_PATTERN;
+		dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN;
 		goto exit;
 	}
 
@@ -1402,7 +1400,7 @@
 
 	/* unless a video pattern CTS test is ongoing, use CEA_VESA */
 	if (dp_link_is_video_pattern_requested(link))
-		dr = link->request.test_dyn_range;
+		dr = link->dp_link.test_video.test_dyn_range;
 	else
 		dr = DP_DYNAMIC_RANGE_RGB_VESA;
 
@@ -1434,51 +1432,52 @@
 	link = container_of(dp_link, struct dp_link_private, dp_link);
 
 	/* use the max level across lanes */
-	for (i = 0; i < dp_link->lane_count; i++) {
+	for (i = 0; i < dp_link->link_params.lane_count; 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_TRAIN_VOLTAGE_SWING_SHIFT;
+	dp_link->phy_params.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++) {
+	for (i = 0; i < dp_link->link_params.lane_count; 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_TRAIN_PRE_EMPHASIS_SHIFT;
+	dp_link->phy_params.p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
 
 	/**
 	 * Adjust the voltage swing and pre-emphasis level combination to within
 	 * the allowable range.
 	 */
-	if (dp_link->v_level > DP_LINK_VOLTAGE_MAX) {
+	if (dp_link->phy_params.v_level > DP_LINK_VOLTAGE_MAX) {
 		pr_debug("Requested vSwingLevel=%d, change to %d\n",
-				dp_link->v_level, DP_LINK_VOLTAGE_MAX);
-		dp_link->v_level = DP_LINK_VOLTAGE_MAX;
+			dp_link->phy_params.v_level, DP_LINK_VOLTAGE_MAX);
+		dp_link->phy_params.v_level = DP_LINK_VOLTAGE_MAX;
 	}
 
-	if (dp_link->p_level > DP_LINK_PRE_EMPHASIS_MAX) {
+	if (dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_MAX) {
 		pr_debug("Requested preEmphasisLevel=%d, change to %d\n",
-				dp_link->p_level, DP_LINK_PRE_EMPHASIS_MAX);
-		dp_link->p_level = DP_LINK_PRE_EMPHASIS_MAX;
+			dp_link->phy_params.p_level, DP_LINK_PRE_EMPHASIS_MAX);
+		dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_MAX;
 	}
 
-	if ((dp_link->p_level > DP_LINK_PRE_EMPHASIS_LEVEL_1)
-			&& (dp_link->v_level == DP_LINK_VOLTAGE_LEVEL_2)) {
+	if ((dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_LEVEL_1)
+		&& (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_2)) {
 		pr_debug("Requested preEmphasisLevel=%d, change to %d\n",
-				dp_link->p_level, DP_LINK_PRE_EMPHASIS_LEVEL_1);
-		dp_link->p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1;
+			dp_link->phy_params.p_level,
+			DP_LINK_PRE_EMPHASIS_LEVEL_1);
+		dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1;
 	}
 
 	pr_debug("adjusted: v_level=%d, p_level=%d\n",
-		dp_link->v_level, dp_link->p_level);
+		dp_link->phy_params.v_level, dp_link->phy_params.p_level);
 
 	return 0;
 }
@@ -1555,7 +1554,7 @@
 	dp_link->get_colorimetry_config = dp_link_get_colorimetry_config;
 	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;
+	dp_link->send_test_response     = dp_link_send_test_response;
 
 	return dp_link;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 419186f..9a5b75a 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -17,6 +17,10 @@
 
 #include "dp_aux.h"
 
+#define DS_PORT_STATUS_CHANGED 0x200
+#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF
+#define DP_LINK_ENUM_STR(x)		#x
+
 enum dp_link_voltage_level {
 	DP_LINK_VOLTAGE_LEVEL_0	= 0,
 	DP_LINK_VOLTAGE_LEVEL_1	= 1,
@@ -31,25 +35,96 @@
 	DP_LINK_PRE_EMPHASIS_MAX	= DP_LINK_PRE_EMPHASIS_LEVEL_2,
 };
 
-#define DS_PORT_STATUS_CHANGED 0x200
-#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF
+struct dp_link_sink_count {
+	u32 count;
+	bool cp_ready;
+};
 
-struct dp_link {
-	u32 test_requested;
+struct dp_link_test_video {
+	u32 test_video_pattern;
+	u32 test_bit_depth;
+	u32 test_dyn_range;
+	u32 test_h_total;
+	u32 test_v_total;
+	u32 test_h_start;
+	u32 test_v_start;
+	u32 test_hsync_pol;
+	u32 test_hsync_width;
+	u32 test_vsync_pol;
+	u32 test_vsync_width;
+	u32 test_h_width;
+	u32 test_v_height;
+	u32 test_rr_d;
+	u32 test_rr_n;
+};
 
+struct dp_link_test_audio {
+	u32 test_audio_sampling_rate;
+	u32 test_audio_channel_count;
+	u32 test_audio_pattern_type;
+	u32 test_audio_period_ch_1;
+	u32 test_audio_period_ch_2;
+	u32 test_audio_period_ch_3;
+	u32 test_audio_period_ch_4;
+	u32 test_audio_period_ch_5;
+	u32 test_audio_period_ch_6;
+	u32 test_audio_period_ch_7;
+	u32 test_audio_period_ch_8;
+};
+
+struct dp_link_phy_params {
+	u32 phy_test_pattern_sel;
+	u8 v_level;
+	u8 p_level;
+};
+
+struct dp_link_params {
 	u32 lane_count;
 	u32 bw_code;
-	u32 v_level;
-	u32 p_level;
+};
+
+struct dp_link {
+	u32 sink_request;
+	u32 test_response;
+
+	struct dp_link_sink_count sink_count;
+	struct dp_link_test_video test_video;
+	struct dp_link_test_audio test_audio;
+	struct dp_link_phy_params phy_params;
+	struct dp_link_params link_params;
 
 	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, u8 *link_status);
 	int (*send_psm_request)(struct dp_link *dp_link, bool req);
-	bool (*phy_pattern_requested)(struct dp_link *dp_link);
+	void (*send_test_response)(struct dp_link *dp_link);
 };
 
+static inline char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel)
+{
+	switch (phy_test_pattern_sel) {
+	case DP_TEST_PHY_PATTERN_NONE:
+		return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE);
+	case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
+		return DP_LINK_ENUM_STR(
+			DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING);
+	case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+		return DP_LINK_ENUM_STR(
+			DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
+	case DP_TEST_PHY_PATTERN_PRBS7:
+		return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7);
+	case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
+		return DP_LINK_ENUM_STR(
+			DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN);
+	case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
+		return DP_LINK_ENUM_STR(
+			DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN);
+	default:
+		return "unknown";
+	}
+}
+
 /**
  * dp_link_get() - get the functionalities of dp test module
  *
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 2e21033..56b2d37 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -17,6 +17,7 @@
 #include "dp_panel.h"
 
 #define DP_PANEL_DEFAULT_BPP 24
+#define DP_MAX_DS_PORT_COUNT 1
 
 enum {
 	DP_LINK_RATE_MULTIPLIER = 27000000,
@@ -27,7 +28,6 @@
 	struct dp_panel dp_panel;
 	struct dp_aux *aux;
 	struct dp_catalog_panel *catalog;
-	bool lane_switch_supported;
 	bool aux_cfg_update_done;
 };
 
@@ -36,7 +36,8 @@
 	int rlen, rc = 0;
 	struct dp_panel_private *panel;
 	struct drm_dp_link *link_info;
-	u8 major = 0, minor = 0;
+	u8 *dpcd, major = 0, minor = 0;
+	u32 dfp_count = 0;
 	unsigned long caps = DP_LINK_CAP_ENHANCED_FRAMING;
 
 	if (!dp_panel) {
@@ -45,11 +46,13 @@
 		goto end;
 	}
 
+	dpcd = dp_panel->dpcd;
+
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
 	link_info = &dp_panel->link_info;
 
 	rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV,
-		dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1));
+		dpcd, (DP_RECEIVER_CAP_SIZE + 1));
 	if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) {
 		pr_err("dpcd read failed, rlen=%d\n", rlen);
 		rc = -EINVAL;
@@ -66,17 +69,33 @@
 		drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]);
 	pr_debug("link_rate=%d\n", link_info->rate);
 
-	if (panel->lane_switch_supported)
-		link_info->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
-			DP_MAX_LANE_COUNT_MASK;
-	else
-		link_info->num_lanes = 2;
+	link_info->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
+				DP_MAX_LANE_COUNT_MASK;
 
 	pr_debug("lane_count=%d\n", link_info->num_lanes);
 
-	if (dp_panel->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)
+	if (drm_dp_enhanced_frame_cap(dpcd))
 		link_info->capabilities |= caps;
 
+	dfp_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] &
+						DP_DOWN_STREAM_PORT_COUNT;
+
+	if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT)
+		&& (dpcd[DP_DPCD_REV] > 0x10)) {
+		rlen = drm_dp_dpcd_read(panel->aux->drm_aux,
+			DP_DOWNSTREAM_PORT_0, dp_panel->ds_ports,
+			DP_MAX_DOWNSTREAM_PORTS);
+		if (rlen < DP_MAX_DOWNSTREAM_PORTS) {
+			pr_err("ds port status failed, rlen=%d\n", rlen);
+			rc = -EINVAL;
+			goto end;
+		}
+	}
+
+	if (dfp_count > DP_MAX_DS_PORT_COUNT)
+		pr_debug("DS port count %d greater that max (%d) supported\n",
+			dfp_count, DP_MAX_DS_PORT_COUNT);
+
 end:
 	return rc;
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index ab9a451..a94f4b8 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -18,7 +18,7 @@
 #include "dp_aux.h"
 #include "sde_edid_parser.h"
 
-#define DP_LINK_RATE_810	30	/* 8.10G = 270M * 30 */
+#define DP_MAX_DOWNSTREAM_PORTS 0x10
 
 struct dp_panel_info {
 	u32 h_active;
@@ -40,8 +40,9 @@
 struct dp_panel {
 	/* dpcd raw data */
 	u8 dpcd[DP_RECEIVER_CAP_SIZE];
-	struct drm_dp_link link_info;
+	u8 ds_ports[DP_MAX_DOWNSTREAM_PORTS];
 
+	struct drm_dp_link link_info;
 	struct sde_edid_ctrl *edid_ctrl;
 	struct drm_connector *connector;
 	struct dp_panel_info pinfo;
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index c85c2a2..c8da99a 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -22,22 +22,15 @@
 {
 	struct dp_io *io = &parser->io;
 
-	if (&io->ctrl_io)
-		msm_dss_iounmap(&io->ctrl_io);
-	if (&io->phy_io)
-		msm_dss_iounmap(&io->phy_io);
-	if (&io->ln_tx0_io)
-		msm_dss_iounmap(&io->ln_tx0_io);
-	if (&io->ln_tx1_io)
-		msm_dss_iounmap(&io->ln_tx0_io);
-	if (&io->dp_pll_io)
-		msm_dss_iounmap(&io->dp_pll_io);
-	if (&io->dp_cc_io)
-		msm_dss_iounmap(&io->dp_cc_io);
-	if (&io->qfprom_io)
-		msm_dss_iounmap(&io->qfprom_io);
-	if (&io->hdcp_io)
-		msm_dss_iounmap(&io->hdcp_io);
+	msm_dss_iounmap(&io->ctrl_io);
+	msm_dss_iounmap(&io->phy_io);
+	msm_dss_iounmap(&io->ln_tx0_io);
+	msm_dss_iounmap(&io->ln_tx0_io);
+	msm_dss_iounmap(&io->dp_pll_io);
+	msm_dss_iounmap(&io->dp_cc_io);
+	msm_dss_iounmap(&io->usb3_dp_com);
+	msm_dss_iounmap(&io->qfprom_io);
+	msm_dss_iounmap(&io->hdcp_io);
 }
 
 static int dp_parser_ctrl_res(struct dp_parser *parser)
@@ -84,6 +77,12 @@
 		goto err;
 	}
 
+	rc = msm_dss_ioremap_byname(pdev, &io->usb3_dp_com, "usb3_dp_com");
+	if (rc) {
+		pr_err("unable to remap USB3 DP com resources\n");
+		goto err;
+	}
+
 	if (msm_dss_ioremap_byname(pdev, &io->dp_cc_io, "dp_mmss_cc")) {
 		pr_err("unable to remap dp MMSS_CC resources\n");
 		goto err;
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index 7794da5..76a72a2 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -65,6 +65,7 @@
  * @dp_cc_io: DP cc's mapped memory address
  * @qfprom_io: qfprom's mapped memory address
  * @dp_pll_io: DP PLL mapped memory address
+ * @usb3_dp_com: USB3 DP PHY combo mapped memory address
  * @hdcp_io: hdcp's mapped memory address
  */
 struct dp_io {
@@ -75,6 +76,7 @@
 	struct dss_io_data dp_cc_io;
 	struct dss_io_data qfprom_io;
 	struct dss_io_data dp_pll_io;
+	struct dss_io_data usb3_dp_com;
 	struct dss_io_data hdcp_io;
 };
 
diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h
index 30377a0..27cf147 100644
--- a/drivers/gpu/drm/msm/dp/dp_reg.h
+++ b/drivers/gpu/drm/msm/dp/dp_reg.h
@@ -205,4 +205,14 @@
 #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11     (0x01C)
 #define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12     (0x020)
 
+/* USB3 DP COM registers */
+#define USB3_DP_COM_RESET_OVRD_CTRL (0x1C)
+#define USB3_DP_COM_PHY_MODE_CTRL   (0x00)
+#define USB3_DP_COM_SW_RESET        (0x04)
+#define USB3_DP_COM_TYPEC_CTRL      (0x10)
+#define USB3_DP_COM_SWI_CTRL        (0x0c)
+#define USB3_DP_COM_POWER_DOWN_CTRL (0x08)
+
+
+
 #endif /* _DP_REG_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index bd7a66e..c0bcdda 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -377,6 +377,18 @@
 
 		pd->dp_usbpd.orientation = usbpd_get_plug_orientation(pd->pd);
 
+		/*
+		 * By default, USB reserves two lanes for Super Speed.
+		 * Which means DP has remaining two lanes to operate on.
+		 * If multi-function is not supported, request USB to
+		 * release the Super Speed lanes so that DP can use
+		 * all four lanes in case DPCD indicates support for
+		 * four lanes.
+		 */
+		if (!pd->dp_usbpd.multi_func)
+			pd->svid_handler.request_usb_ss_lane(pd->pd,
+				&pd->svid_handler);
+
 		if (pd->dp_cb && pd->dp_cb->configure)
 			pd->dp_cb->configure(pd->dev);
 		break;
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 7243fe2..9ddca8c 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -722,6 +722,12 @@
 			(u32 *)&catalog->perf.max_bw_low);
 	debugfs_create_u32("threshold_high", 0600, perf->debugfs_root,
 			(u32 *)&catalog->perf.max_bw_high);
+	debugfs_create_u32("min_core_ib", 0600, perf->debugfs_root,
+			(u32 *)&catalog->perf.min_core_ib);
+	debugfs_create_u32("min_llcc_ib", 0600, perf->debugfs_root,
+			(u32 *)&catalog->perf.min_llcc_ib);
+	debugfs_create_u32("min_dram_ib", 0600, perf->debugfs_root,
+			(u32 *)&catalog->perf.min_dram_ib);
 	debugfs_create_file("perf_mode", 0600, perf->debugfs_root,
 			(u32 *)perf, &sde_core_perf_mode_fops);
 	debugfs_create_u32("bw_vote_mode", 0600, perf->debugfs_root,
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 387f08d..30cf3df 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -1524,7 +1524,6 @@
 static int _sde_crtc_find_plane_fb_modes(struct drm_crtc_state *state,
 		uint32_t *fb_ns,
 		uint32_t *fb_sec,
-		uint32_t *fb_ns_dir,
 		uint32_t *fb_sec_dir)
 {
 	struct drm_plane *plane;
@@ -1540,7 +1539,6 @@
 
 	*fb_ns = 0;
 	*fb_sec = 0;
-	*fb_ns_dir = 0;
 	*fb_sec_dir = 0;
 	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
 		if (IS_ERR_OR_NULL(pstate)) {
@@ -1560,16 +1558,12 @@
 		case SDE_DRM_FB_SEC:
 			(*fb_sec)++;
 			break;
-		case SDE_DRM_FB_NON_SEC_DIR_TRANS:
-			(*fb_ns_dir)++;
-			break;
 		case SDE_DRM_FB_SEC_DIR_TRANS:
 			(*fb_sec_dir)++;
 			break;
 		default:
 			SDE_ERROR("Error: Plane[%d], fb_trans_mode:%d",
-					plane->base.id,
-					mode);
+					plane->base.id, mode);
 			return -EINVAL;
 		}
 	}
@@ -1593,7 +1587,7 @@
 	struct sde_crtc *sde_crtc;
 	struct sde_crtc_state *cstate;
 	struct sde_crtc_smmu_state_data *smmu_state;
-	uint32_t translation_mode = 0;
+	uint32_t translation_mode = 0, secure_level;
 	int ops  = 0;
 	bool post_commit = false;
 
@@ -1605,10 +1599,10 @@
 	sde_crtc = to_sde_crtc(crtc);
 	cstate = to_sde_crtc_state(crtc->state);
 	smmu_state = &sde_crtc->smmu_state;
+	secure_level = sde_crtc_get_secure_level(crtc, crtc->state);
 
-	SDE_DEBUG("crtc%d, secure_level%d\n",
-			crtc->base.id,
-			sde_crtc_get_secure_level(crtc, crtc->state));
+	SDE_DEBUG("crtc%d, secure_level%d old_valid_fb%d\n",
+			crtc->base.id, secure_level, old_valid_fb);
 
 	/**
 	 * SMMU operations need to be delayed in case of
@@ -1632,8 +1626,7 @@
 				PLANE_PROP_FB_TRANSLATION_MODE);
 		if (translation_mode > SDE_DRM_FB_SEC_DIR_TRANS) {
 			SDE_ERROR("crtc%d, invalid translation_mode%d\n",
-					crtc->base.id,
-					translation_mode);
+					crtc->base.id, translation_mode);
 			return -EINVAL;
 		}
 
@@ -1641,14 +1634,15 @@
 		 * we can break if we find sec_fir or non_sec_dir
 		 * plane
 		 */
-		if ((translation_mode == SDE_DRM_FB_NON_SEC_DIR_TRANS) ||
-			(translation_mode == SDE_DRM_FB_SEC_DIR_TRANS))
+		if (translation_mode == SDE_DRM_FB_SEC_DIR_TRANS)
 			break;
 	}
 
 	switch (translation_mode) {
-	case SDE_DRM_FB_NON_SEC_DIR_TRANS:
-		if (smmu_state->state == ATTACHED) {
+	case SDE_DRM_FB_SEC_DIR_TRANS:
+		/* secure display usecase */
+		if ((smmu_state->state == ATTACHED) &&
+				(secure_level == SDE_DRM_SEC_ONLY)) {
 			smmu_state->state = DETACH_ALL_REQ;
 			smmu_state->transition_type = PRE_COMMIT;
 			ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
@@ -1656,10 +1650,8 @@
 				ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE  |
 					SDE_KMS_OPS_CLEANUP_PLANE_FB);
 			}
-		}
-		break;
-	case SDE_DRM_FB_SEC_DIR_TRANS:
-		if (smmu_state->state == ATTACHED) {
+		/* secure camera usecase */
+		} else if (smmu_state->state == ATTACHED) {
 			smmu_state->state = DETACH_SEC_REQ;
 			smmu_state->transition_type = PRE_COMMIT;
 			ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
@@ -1667,14 +1659,18 @@
 		break;
 	case SDE_DRM_FB_SEC:
 	case SDE_DRM_FB_NON_SEC:
-		if (smmu_state->state == DETACHED_SEC) {
+		if ((smmu_state->state == DETACHED_SEC) ||
+			(smmu_state->state == DETACH_SEC_REQ)) {
 			smmu_state->state = ATTACH_SEC_REQ;
 			smmu_state->transition_type = post_commit ?
 				POST_COMMIT : PRE_COMMIT;
 			ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
 			if (translation_mode == SDE_DRM_FB_SEC)
 				ops |= SDE_KMS_OPS_PREPARE_PLANE_FB;
-		} else if (smmu_state->state == DETACHED) {
+			if (old_valid_fb)
+				ops |= SDE_KMS_OPS_WAIT_FOR_TX_DONE;
+		} else if ((smmu_state->state == DETACHED) ||
+				(smmu_state->state == DETACH_ALL_REQ)) {
 			smmu_state->state = ATTACH_ALL_REQ;
 			smmu_state->transition_type = post_commit ?
 				POST_COMMIT : PRE_COMMIT;
@@ -1686,15 +1682,13 @@
 		}
 		break;
 	default:
-		SDE_ERROR("invalid plane fb_mode:%d\n",
-				translation_mode);
+		SDE_ERROR("invalid plane fb_mode:%d\n", translation_mode);
 		ops = 0;
 		return -EINVAL;
 	}
 
 	SDE_DEBUG("SMMU State:%d, type:%d ops:%x\n", smmu_state->state,
-			smmu_state->transition_type,
-			ops);
+			smmu_state->transition_type, ops);
 	return ops;
 }
 
@@ -1722,13 +1716,13 @@
 	 */
 	sec_sid[0] = SEC_SID_MASK_0;
 	sec_sid[1] = SEC_SID_MASK_1;
-	dmac_flush_range(&sec_sid, &sec_sid + num_sids);
+	dmac_flush_range(sec_sid, sec_sid + num_sids);
 
 	SDE_DEBUG("calling scm_call for vmid %d", vmid);
 
 	desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
 	desc.args[0] = MDP_DEVICE_ID;
-	desc.args[1] = SCM_BUFFER_PHYS(&sec_sid);
+	desc.args[1] = SCM_BUFFER_PHYS(sec_sid);
 	desc.args[2] = sizeof(uint32_t) * num_sids;
 	desc.args[3] =  vmid;
 
@@ -1736,8 +1730,7 @@
 				mem_protect_sd_ctrl_id), &desc);
 	if (ret) {
 		SDE_ERROR("Error:scm_call2, vmid (%lld): ret%d\n",
-				desc.args[3],
-				ret);
+				desc.args[3], ret);
 	}
 
 	kfree(sec_sid);
@@ -1780,7 +1773,6 @@
 		/* Bail out */
 		return 0;
 
-
 	/* Secure UI use case enable */
 	switch (smmu_state->state) {
 	case DETACH_ALL_REQ:
@@ -1856,11 +1848,10 @@
 	SDE_DEBUG("crtc: %d, old_state %d new_state %d\n", crtc->base.id,
 			old_smmu_state,
 			smmu_state->state);
-	smmu_state->transition_error = false;
 	smmu_state->transition_type = NONE;
 
 error:
-	smmu_state->transition_error = true;
+	smmu_state->transition_error = ret ? true : false;
 	return ret;
 }
 
@@ -2573,7 +2564,7 @@
 	 * apply color processing properties only if
 	 * smmu state is attached,
 	 */
-	if ((smmu_state->state != DETACHED) ||
+	if ((smmu_state->state != DETACHED) &&
 			(smmu_state->state != DETACH_ALL_REQ))
 		sde_cp_crtc_apply_properties(crtc);
 
@@ -2814,9 +2805,11 @@
 	}
 	sde_crtc->play_count++;
 
-	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE)
-		drm_atomic_crtc_for_each_plane(plane, crtc)
+	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE) {
+		drm_atomic_crtc_for_each_plane(plane, crtc) {
 			sde_plane_kickoff(plane);
+		}
+	}
 
 	for (i = 0; i < sde_crtc->num_mixers; i++) {
 		ctl = sde_crtc->mixers[i].hw_ctl;
@@ -3416,7 +3409,7 @@
 	struct drm_encoder *encoder;
 	struct sde_crtc_state *cstate;
 	uint32_t secure;
-	uint32_t fb_ns = 0, fb_sec = 0, fb_ns_dir = 0, fb_sec_dir = 0;
+	uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0;
 	int encoder_cnt = 0;
 	int rc;
 
@@ -3433,26 +3426,21 @@
 	rc = _sde_crtc_find_plane_fb_modes(state,
 			&fb_ns,
 			&fb_sec,
-			&fb_ns_dir,
 			&fb_sec_dir);
 	if (rc)
 		return rc;
 
 	/**
 	 * validate planes
-	 * fb_ns_dir is for  secure display use case,
-	 * fb_sec_dir is for secure camera preview use case,
+	 * fb_sec_dir is for secure camera preview and secure display  use case,
 	 * fb_sec is for secure video playback,
 	 * fb_ns is for normal non secure use cases.
 	 */
-	if (((secure == SDE_DRM_SEC_ONLY) &&
-				(fb_ns || fb_sec || fb_sec_dir)) ||
-			(fb_sec && fb_sec_dir)) {
+	if ((secure == SDE_DRM_SEC_ONLY) &&
+			(fb_ns || fb_sec || (fb_sec && fb_sec_dir))) {
 		SDE_ERROR(
-			"crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d, NS_Dir%d\n",
-				crtc->base.id,
-				fb_sec, fb_ns, fb_sec_dir,
-				fb_ns_dir);
+		"crtc%d: invalid planes fb_modes Sec:%d, NS:%d, Sec_Dir:%d\n",
+				crtc->base.id, fb_sec, fb_ns, fb_sec_dir);
 		return -EINVAL;
 	}
 
@@ -3460,7 +3448,7 @@
 	 * secure_crtc is not allowed in a shared toppolgy
 	 * across different encoders.
 	 */
-	if (fb_ns_dir || fb_sec_dir) {
+	if (fb_sec_dir) {
 		drm_for_each_encoder(encoder, crtc->dev)
 			if (encoder->crtc ==  crtc)
 				encoder_cnt++;
@@ -3922,6 +3910,15 @@
 	if (catalog->perf.max_bw_high)
 		sde_kms_info_add_keyint(info, "max_bandwidth_high",
 				catalog->perf.max_bw_high * 1000LL);
+	if (catalog->perf.min_core_ib)
+		sde_kms_info_add_keyint(info, "min_core_ib",
+				catalog->perf.min_core_ib * 1000LL);
+	if (catalog->perf.min_llcc_ib)
+		sde_kms_info_add_keyint(info, "min_llcc_ib",
+				catalog->perf.min_llcc_ib * 1000LL);
+	if (catalog->perf.min_dram_ib)
+		sde_kms_info_add_keyint(info, "min_dram_ib",
+				catalog->perf.min_dram_ib * 1000LL);
 	if (sde_kms->perf.max_core_clk_rate)
 		sde_kms_info_add_keyint(info, "max_mdp_clk",
 				sde_kms->perf.max_core_clk_rate);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 3e1ed7b..270e677 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -2224,11 +2224,13 @@
 
 	sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_STOP);
 
-	if (sde_enc->cur_master) {
-		sde_enc->cur_master->connector = NULL;
-		sde_enc->cur_master = NULL;
+	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+		if (sde_enc->phys_encs[i])
+			sde_enc->phys_encs[i]->connector = NULL;
 	}
 
+	sde_enc->cur_master = NULL;
+
 	SDE_DEBUG_ENC(sde_enc, "encoder disabled\n");
 
 	sde_rm_release(&sde_kms->rm, drm_enc);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index ccc4443..d3c2654 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -146,6 +146,9 @@
 enum {
 	PERF_MAX_BW_LOW,
 	PERF_MAX_BW_HIGH,
+	PERF_MIN_CORE_IB,
+	PERF_MIN_LLCC_IB,
+	PERF_MIN_DRAM_IB,
 	PERF_CORE_IB_FF,
 	PERF_CORE_CLK_FF,
 	PERF_COMP_RATIO_RT,
@@ -376,6 +379,9 @@
 static struct sde_prop_type sde_perf_prop[] = {
 	{PERF_MAX_BW_LOW, "qcom,sde-max-bw-low-kbps", false, PROP_TYPE_U32},
 	{PERF_MAX_BW_HIGH, "qcom,sde-max-bw-high-kbps", false, PROP_TYPE_U32},
+	{PERF_MIN_CORE_IB, "qcom,sde-min-core-ib-kbps", false, PROP_TYPE_U32},
+	{PERF_MIN_LLCC_IB, "qcom,sde-min-llcc-ib-kbps", false, PROP_TYPE_U32},
+	{PERF_MIN_DRAM_IB, "qcom,sde-min-dram-ib-kbps", false, PROP_TYPE_U32},
 	{PERF_CORE_IB_FF, "qcom,sde-core-ib-ff", false, PROP_TYPE_STRING},
 	{PERF_CORE_CLK_FF, "qcom,sde-core-clk-ff", false, PROP_TYPE_STRING},
 	{PERF_COMP_RATIO_RT, "qcom,sde-comp-ratio-rt", false,
@@ -2691,6 +2697,18 @@
 			prop_exists[PERF_MAX_BW_HIGH] ?
 			PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_HIGH, 0) :
 			DEFAULT_MAX_BW_HIGH;
+	cfg->perf.min_core_ib =
+			prop_exists[PERF_MIN_CORE_IB] ?
+			PROP_VALUE_ACCESS(prop_value, PERF_MIN_CORE_IB, 0) :
+			DEFAULT_MAX_BW_LOW;
+	cfg->perf.min_llcc_ib =
+			prop_exists[PERF_MIN_LLCC_IB] ?
+			PROP_VALUE_ACCESS(prop_value, PERF_MIN_LLCC_IB, 0) :
+			DEFAULT_MAX_BW_LOW;
+	cfg->perf.min_dram_ib =
+			prop_exists[PERF_MIN_DRAM_IB] ?
+			PROP_VALUE_ACCESS(prop_value, PERF_MIN_DRAM_IB, 0) :
+			DEFAULT_MAX_BW_LOW;
 
 	/*
 	 * The following performance parameters (e.g. core_ib_ff) are
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 48c3db7..d85c8720 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -803,6 +803,10 @@
  * struct sde_perf_cfg - performance control settings
  * @max_bw_low         low threshold of maximum bandwidth (kbps)
  * @max_bw_high        high threshold of maximum bandwidth (kbps)
+ * @min_core_ib        minimum bandwidth for core (kbps)
+ * @min_core_ib        minimum mnoc ib vote in kbps
+ * @min_llcc_ib        minimum llcc ib vote in kbps
+ * @min_dram_ib        minimum dram ib vote in kbps
  * @core_ib_ff         core instantaneous bandwidth fudge factor
  * @core_clk_ff        core clock fudge factor
  * @comp_ratio_rt      string of 0 or more of <fourcc>/<ven>/<mod>/<comp ratio>
@@ -824,6 +828,9 @@
 struct sde_perf_cfg {
 	u32 max_bw_low;
 	u32 max_bw_high;
+	u32 min_core_ib;
+	u32 min_llcc_ib;
+	u32 min_dram_ib;
 	const char *core_ib_ff;
 	const char *core_clk_ff;
 	const char *comp_ratio_rt;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index a4564c1..e7e39d3 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -422,19 +422,19 @@
 	if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
 		return;
 
-	if (rect_mode == SDE_SSPP_RECT_SOLO || rect_mode == SDE_SSPP_RECT_0)
-		secure_bit_mask = (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF :
-			0x5;
-	else
-		secure_bit_mask = 0xA;
-
 	c = &ctx->hw;
 
-	secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
-	if (enable)
+	if (enable) {
+		if ((rect_mode == SDE_SSPP_RECT_SOLO)
+				|| (rect_mode == SDE_SSPP_RECT_0))
+			secure_bit_mask =
+				(rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5;
+		else
+			secure_bit_mask = 0xA;
+
+		secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx);
 		secure |= secure_bit_mask;
-	else
-		secure &= ~secure_bit_mask;
+	}
 
 	SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index a121b2e..10f796f 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -878,7 +878,6 @@
 			return -EINVAL;
 		break;
 	case SDE_DRM_FB_SEC_DIR_TRANS:
-	case SDE_DRM_FB_NON_SEC_DIR_TRANS:
 		*aspace = NULL;
 		break;
 	default:
@@ -2791,6 +2790,18 @@
 	new_rstate = &to_sde_plane_state(new_state)->rot;
 
 	if (pstate->aspace) {
+		/*
+		 * when transitioning from secure to non-secure,
+		 * plane->prepare_fb happens before the commit. In such case,
+		 * return early, as prepare_fb would be handled as part
+		 * of the transition after attaching the domains,
+		 * during the commit
+		 */
+		if (!pstate->aspace->domain_attached) {
+			SDE_DEBUG_PLANE(psde,
+			    "domain not attached, prepare_fb handled later\n");
+			return 0;
+		}
 		ret = msm_framebuffer_prepare(new_rstate->out_fb,
 				pstate->aspace);
 		if (ret) {
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d16e42d..780cefe 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2464,7 +2464,7 @@
 
 	dev_err(device->dev, " hwfault=%8.8X\n", hwfault);
 
-	kgsl_device_snapshot(device, NULL);
+	kgsl_device_snapshot(device, NULL, adreno_gmu_gpu_fault(adreno_dev));
 }
 
 /**
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 36bd656..49dc5ed 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -1329,6 +1329,10 @@
 	smp_wmb();
 }
 
+static inline bool adreno_gmu_gpu_fault(struct adreno_device *adreno_dev)
+{
+	return adreno_gpu_fault(adreno_dev) & ADRENO_GMU_FAULT;
+}
 
 /**
  * adreno_clear_gpu_fault() - Clear the GPU fault register
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 5d7fb21..356d7c2 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -685,7 +685,7 @@
 		struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 
 		dev_err(device->dev, "CP initialization failed to idle\n");
-		kgsl_device_snapshot(device, NULL);
+		kgsl_device_snapshot(device, NULL, false);
 	}
 
 	return ret;
@@ -1823,7 +1823,7 @@
 
 	if (ret) {
 		KGSL_DRV_ERR(device, "microcode bootstrap failed to idle\n");
-		kgsl_device_snapshot(device, NULL);
+		kgsl_device_snapshot(device, NULL, false);
 	}
 
 	/* Clear the chicken bit for speed up on A430 and its derivatives */
diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c
index c807b67..0cf909e 100644
--- a/drivers/gpu/msm/adreno_a4xx.c
+++ b/drivers/gpu/msm/adreno_a4xx.c
@@ -1535,7 +1535,7 @@
 		struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 
 		dev_err(device->dev, "CP initialization failed to idle\n");
-		kgsl_device_snapshot(device, NULL);
+		kgsl_device_snapshot(device, NULL, false);
 	}
 
 	return ret;
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 12824b0..b9df4ec 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -1943,9 +1943,7 @@
 	/* If SPTP_RAC is on, turn off SPTP_RAC HS */
 	a6xx_sptprac_disable(adreno_dev);
 
-	/* Disconnect GPU from BUS. Clear and reconnected after reset */
-	adreno_vbif_clear_pending_transactions(device);
-	/* Unnecessary: a6xx_soft_reset(adreno_dev); */
+	/* Disconnect GPU from BUS is not needed if CX GDSC goes off later */
 
 	/* Check no outstanding RPMh voting */
 	a6xx_complete_rpmh_votes(device);
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 25aeaef..21ecaa1 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2046,7 +2046,7 @@
 	kfree(replay);
 }
 
-static void do_header_and_snapshot(struct kgsl_device *device,
+static void do_header_and_snapshot(struct kgsl_device *device, int fault,
 		struct adreno_ringbuffer *rb, struct kgsl_drawobj_cmd *cmdobj)
 {
 	struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj);
@@ -2054,7 +2054,7 @@
 	/* Always dump the snapshot on a non-drawobj failure */
 	if (cmdobj == NULL) {
 		adreno_fault_header(device, rb, NULL);
-		kgsl_device_snapshot(device, NULL);
+		kgsl_device_snapshot(device, NULL, fault & ADRENO_GMU_FAULT);
 		return;
 	}
 
@@ -2066,7 +2066,7 @@
 	adreno_fault_header(device, rb, cmdobj);
 
 	if (!(drawobj->context->flags & KGSL_CONTEXT_NO_SNAPSHOT))
-		kgsl_device_snapshot(device, drawobj->context);
+		kgsl_device_snapshot(device, NULL, fault & ADRENO_GMU_FAULT);
 }
 
 static int dispatcher_do_fault(struct adreno_device *adreno_dev)
@@ -2192,7 +2192,7 @@
 		adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE,
 			ADRENO_REG_CP_IB1_BASE_HI, &base);
 
-	do_header_and_snapshot(device, hung_rb, cmdobj);
+	do_header_and_snapshot(device, fault, hung_rb, cmdobj);
 
 	/* Turn off the KEEPALIVE vote from the ISR for hard fault */
 	if (gpudev->gpu_keepalive && fault & ADRENO_HARD_FAULT)
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 0882447..2615d44 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -533,7 +533,8 @@
 				drawctxt->internal_timestamp,
 				drawctxt->type, ret);
 		device->force_panic = 1;
-		kgsl_device_snapshot(device, context);
+		kgsl_device_snapshot(device, context,
+				adreno_gmu_gpu_fault(adreno_dev));
 	}
 
 	kgsl_sharedmem_writel(device, &device->memstore,
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 8b87ee2..09c1ae6 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -25,6 +25,7 @@
 #include "adreno_iommu.h"
 #include "adreno_pm4types.h"
 #include "adreno_ringbuffer.h"
+#include "adreno_trace.h"
 
 #include "a3xx_reg.h"
 #include "adreno_a5xx.h"
@@ -37,6 +38,7 @@
 	((_rb)->buffer_desc.gpuaddr + ((_pos) * sizeof(unsigned int)))
 
 static void adreno_get_submit_time(struct adreno_device *adreno_dev,
+		struct adreno_ringbuffer *rb,
 		struct adreno_submit_time *time)
 {
 	unsigned long flags;
@@ -66,6 +68,9 @@
 	} else
 		time->ticks = 0;
 
+	/* Trace the GPU time to create a mapping to ftrace time */
+	trace_adreno_cmdbatch_sync(rb->drawctxt_active, time->ticks);
+
 	/* Get the kernel clock for time since boot */
 	time->ktime = local_clock();
 
@@ -148,7 +153,7 @@
 	struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb);
 
 	if (time != NULL)
-		adreno_get_submit_time(adreno_dev, time);
+		adreno_get_submit_time(adreno_dev, rb, time);
 
 	adreno_ringbuffer_wptr(adreno_dev, rb);
 }
diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h
index 7bc4c93..e33060a 100644
--- a/drivers/gpu/msm/adreno_trace.h
+++ b/drivers/gpu/msm/adreno_trace.h
@@ -148,6 +148,29 @@
 	)
 );
 
+TRACE_EVENT(adreno_cmdbatch_sync,
+	TP_PROTO(struct adreno_context *drawctxt,
+		uint64_t ticks),
+	TP_ARGS(drawctxt, ticks),
+	TP_STRUCT__entry(
+		__field(unsigned int, id)
+		__field(unsigned int, timestamp)
+		__field(uint64_t, ticks)
+		__field(int, prio)
+	),
+	TP_fast_assign(
+		__entry->id = drawctxt->base.id;
+		__entry->timestamp = drawctxt->timestamp;
+		__entry->ticks = ticks;
+		__entry->prio = drawctxt->base.priority;
+	),
+	TP_printk(
+		"ctx=%u ctx_prio=%d ts=%u ticks=%lld",
+			__entry->id, __entry->prio, __entry->timestamp,
+			__entry->ticks
+	)
+);
+
 TRACE_EVENT(adreno_cmdbatch_fault,
 	TP_PROTO(struct kgsl_drawobj_cmd *cmdobj, unsigned int fault),
 	TP_ARGS(cmdobj, fault),
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2cc1869..f8d5f5b 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -493,7 +493,9 @@
  * @work: worker to dump the frozen memory
  * @dump_gate: completion gate signaled by worker when it is finished.
  * @process: the process that caused the hang, if known.
- * @sysfs_read: An atomic for concurrent snapshot reads via syfs.
+ * @sysfs_read: Count of current reads via sysfs
+ * @first_read: True until the snapshot read is started
+ * @gmu_fault: Snapshot collected when GMU fault happened
  */
 struct kgsl_snapshot {
 	uint64_t ib1base;
@@ -514,7 +516,9 @@
 	struct work_struct work;
 	struct completion dump_gate;
 	struct kgsl_process_private *process;
-	atomic_t sysfs_read;
+	unsigned int sysfs_read;
+	bool first_read;
+	bool gmu_fault;
 };
 
 /**
@@ -700,7 +704,7 @@
 
 int kgsl_device_snapshot_init(struct kgsl_device *device);
 void kgsl_device_snapshot(struct kgsl_device *device,
-			struct kgsl_context *context);
+			struct kgsl_context *context, bool gmu_fault);
 void kgsl_device_snapshot_close(struct kgsl_device *device);
 void kgsl_snapshot_save_frozen_objs(struct work_struct *work);
 
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 9b04543..3bd7cf3 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -456,11 +456,12 @@
 			GMU_DCVS_NOHFI, perf_idx, bw_idx);
 
 		if (ret) {
-			dev_err(&gmu->pdev->dev,
+			dev_err_ratelimited(&gmu->pdev->dev,
 				"Failed to set GPU perf idx %d, bw idx %d\n",
 				perf_idx, bw_idx);
 
-			gmu_snapshot(device);
+			adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT);
+			adreno_dispatcher_schedule(device);
 		}
 
 		return ret;
@@ -1341,6 +1342,7 @@
 
 	gmu_disable_clks(gmu);
 	gmu_disable_gdsc(gmu);
+	dev_err(&gmu->pdev->dev, "Suspended GMU\n");
 	return 0;
 }
 
@@ -1349,7 +1351,7 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct gmu_device *gmu = &device->gmu;
 
-	if (!test_and_set_bit(GMU_FAULT, &gmu->flags)) {
+	if (!gmu->fault_count) {
 		/* Mask so there's no interrupt caused by NMI */
 		adreno_write_gmureg(adreno_dev,
 				ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
@@ -1364,7 +1366,7 @@
 		/* Wait for the NMI to be handled */
 		wmb();
 		udelay(100);
-		kgsl_device_snapshot(device, ERR_PTR(-EINVAL));
+		kgsl_device_snapshot(device, ERR_PTR(-EINVAL), true);
 
 		adreno_write_gmureg(adreno_dev,
 				ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
@@ -1372,6 +1374,8 @@
 				ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
 				(unsigned int) ~HFI_IRQ_MASK);
 	}
+
+	gmu->fault_count++;
 }
 
 /* To be called to power on both GPU and GMU */
@@ -1389,32 +1393,29 @@
 		WARN_ON(test_bit(GMU_CLK_ON, &gmu->flags));
 		gmu_enable_gdsc(gmu);
 		gmu_enable_clks(gmu);
+		gmu_irq_enable(device);
 
 		/* Vote for 300MHz DDR for GMU to init */
 		ret = msm_bus_scale_client_update_request(gmu->pcl,
 				pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
-		if (ret) {
+		if (ret)
 			dev_err(&gmu->pdev->dev,
-					"Failed to allocate gmu b/w\n");
-			goto error_clks;
-		}
+				"Failed to allocate gmu b/w: %d\n", ret);
 
 		ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START,
 				GMU_COLD_BOOT, 0);
 		if (ret)
-			goto error_bus;
-
-		gmu_irq_enable(device);
+			goto error_gmu;
 
 		ret = hfi_start(gmu, GMU_COLD_BOOT);
 		if (ret)
-			goto error_gpu;
+			goto error_gmu;
 
 		/* Send default DCVS level */
 		ret = gmu_dcvs_set(gmu, pwr->default_pwrlevel,
 				pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
 		if (ret)
-			goto error_gpu;
+			goto error_gmu;
 
 		msm_bus_scale_client_update_request(gmu->pcl, 0);
 		break;
@@ -1423,49 +1424,49 @@
 		WARN_ON(test_bit(GMU_CLK_ON, &gmu->flags));
 		gmu_enable_gdsc(gmu);
 		gmu_enable_clks(gmu);
+		gmu_irq_enable(device);
 
 		ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START,
 				GMU_WARM_BOOT, 0);
 		if (ret)
-			goto error_clks;
-
-		gmu_irq_enable(device);
+			goto error_gmu;
 
 		ret = hfi_start(gmu, GMU_WARM_BOOT);
 		if (ret)
-			goto error_gpu;
+			goto error_gmu;
 
 		ret = gmu_dcvs_set(gmu, gmu->wakeup_pwrlevel,
 				pwr->pwrlevels[gmu->wakeup_pwrlevel].bus_freq);
 		if (ret)
-			goto error_gpu;
+			goto error_gmu;
 
 		gmu->wakeup_pwrlevel = pwr->default_pwrlevel;
 		break;
 
 	case KGSL_STATE_RESET:
-		if (test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv)) {
+		if (test_bit(ADRENO_DEVICE_HARD_RESET, &adreno_dev->priv) ||
+			test_bit(GMU_FAULT, &gmu->flags)) {
 			gmu_suspend(device);
 			gmu_enable_gdsc(gmu);
 			gmu_enable_clks(gmu);
+			gmu_irq_enable(device);
 
 			ret = gpudev->rpmh_gpu_pwrctrl(
 				adreno_dev, GMU_FW_START, GMU_RESET, 0);
 			if (ret)
-				goto error_clks;
+				goto error_gmu;
 
-			gmu_irq_enable(device);
 
 			ret = hfi_start(gmu, GMU_COLD_BOOT);
 			if (ret)
-				goto error_gpu;
+				goto error_gmu;
 
 			/* Send DCVS level prior to reset*/
 			ret = gmu_dcvs_set(gmu, pwr->active_pwrlevel,
 					pwr->pwrlevels[pwr->active_pwrlevel]
 					.bus_freq);
 			if (ret)
-				goto error_gpu;
+				goto error_gmu;
 
 			ret = gpudev->oob_set(adreno_dev,
 				OOB_CPINIT_SET_MASK,
@@ -1485,20 +1486,8 @@
 
 	return ret;
 
-error_gpu:
+error_gmu:
 	gmu_snapshot(device);
-	hfi_stop(gmu);
-	gmu_irq_disable(device);
-	if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
-		gpudev->oob_clear(adreno_dev,
-				OOB_BOOT_SLUMBER_CLEAR_MASK);
-	gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
-error_bus:
-	msm_bus_scale_client_update_request(gmu->pcl, 0);
-error_clks:
-	gmu_snapshot(device);
-	gmu_disable_clks(gmu);
-	gmu_disable_gdsc(gmu);
 	return ret;
 }
 
@@ -1535,18 +1524,30 @@
 	if (!idle || (gpudev->wait_for_gmu_idle &&
 			gpudev->wait_for_gmu_idle(adreno_dev))) {
 		dev_err(&gmu->pdev->dev, "Stopping GMU before it is idle\n");
+		idle = false;
+		set_bit(GMU_FAULT, &gmu->flags);
+	} else {
+		idle = true;
 	}
 
-	/* Pending message in all queues are abandoned */
-	hfi_stop(gmu);
-	clear_bit(GMU_HFI_ON, &gmu->flags);
-	gmu_irq_disable(device);
+	if (idle) {
+		/* Pending message in all queues are abandoned */
+		hfi_stop(gmu);
+		clear_bit(GMU_HFI_ON, &gmu->flags);
+		gmu_irq_disable(device);
 
-	gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
-	gmu_disable_clks(gmu);
-	gmu_disable_gdsc(gmu);
-
-	/* TODO: Vote CX, MX retention off */
+		gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
+		gmu_disable_clks(gmu);
+		gmu_disable_gdsc(gmu);
+	} else {
+		/*
+		 * The power controller will change state to SLUMBER anyway
+		 * Set GMU_FAULT flag to indicate to power contrller
+		 * that hang recovery is needed to power on GPU
+		 */
+		set_bit(GMU_FAULT, &gmu->flags);
+		gmu_snapshot(device);
+	}
 
 	msm_bus_scale_client_update_request(gmu->pcl, 0);
 }
diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h
index 63ca028..ff65f66 100644
--- a/drivers/gpu/msm/kgsl_gmu.h
+++ b/drivers/gpu/msm/kgsl_gmu.h
@@ -193,6 +193,7 @@
  * @pcl: GPU BW scaling client
  * @ccl: CNOC BW scaling client
  * @idle_level: Minimal GPU idle power level
+ * @fault_count: GMU fault count
  */
 struct gmu_device {
 	unsigned int ver;
@@ -226,6 +227,7 @@
 	unsigned int pcl;
 	unsigned int ccl;
 	unsigned int idle_level;
+	unsigned int fault_count;
 };
 
 bool kgsl_gmu_isenabled(struct kgsl_device *device);
diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c
index 685ce3e..c31a85b 100644
--- a/drivers/gpu/msm/kgsl_pool.c
+++ b/drivers/gpu/msm/kgsl_pool.c
@@ -65,19 +65,26 @@
 
 /* Map the page into kernel and zero it out */
 static void
-_kgsl_pool_zero_page(struct page *p)
+_kgsl_pool_zero_page(struct page *p, unsigned int pool_order)
 {
-	void *addr = kmap_atomic(p);
+	int i;
 
-	memset(addr, 0, PAGE_SIZE);
-	dmac_flush_range(addr, addr + PAGE_SIZE);
-	kunmap_atomic(addr);
+	for (i = 0; i < (1 << pool_order); i++) {
+		struct page *page = nth_page(p, i);
+		void *addr = kmap_atomic(page);
+
+		memset(addr, 0, PAGE_SIZE);
+		dmac_flush_range(addr, addr + PAGE_SIZE);
+		kunmap_atomic(addr);
+	}
 }
 
 /* Add a page to specified pool */
 static void
 _kgsl_pool_add_page(struct kgsl_page_pool *pool, struct page *p)
 {
+	_kgsl_pool_zero_page(p, pool->pool_order);
+
 	spin_lock(&pool->list_lock);
 	list_add_tail(&p->lru, &pool->page_list);
 	pool->page_count++;
@@ -322,6 +329,7 @@
 			} else
 				return -ENOMEM;
 		}
+		_kgsl_pool_zero_page(page, order);
 		goto done;
 	}
 
@@ -341,6 +349,7 @@
 			page = alloc_pages(gfp_mask, order);
 			if (page == NULL)
 				return -ENOMEM;
+			_kgsl_pool_zero_page(page, order);
 			goto done;
 		}
 	}
@@ -370,12 +379,13 @@
 			} else
 				return -ENOMEM;
 		}
+
+		_kgsl_pool_zero_page(page, order);
 	}
 
 done:
 	for (j = 0; j < (*page_size >> PAGE_SHIFT); j++) {
 		p = nth_page(page, j);
-		_kgsl_pool_zero_page(p);
 		pages[pcount] = p;
 		pcount++;
 	}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 6e55395..007121c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2629,6 +2629,7 @@
 _aware(struct kgsl_device *device)
 {
 	int status = 0;
+	struct gmu_device *gmu = &device->gmu;
 
 	switch (device->state) {
 	case KGSL_STATE_RESET:
@@ -2648,15 +2649,42 @@
 		kgsl_pwrscale_midframe_timer_cancel(device);
 		break;
 	case KGSL_STATE_SLUMBER:
+		/* if GMU already in FAULT */
+		if (kgsl_gmu_isenabled(device) &&
+			test_bit(GMU_FAULT, &gmu->flags)) {
+			status = -EINVAL;
+			break;
+		}
+
 		status = kgsl_pwrctrl_enable(device);
 		break;
 	default:
 		status = -EINVAL;
 	}
-	if (status)
+
+	if (status) {
+		if (kgsl_gmu_isenabled(device)) {
+			/* GMU hang recovery */
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_RESET);
+			set_bit(GMU_FAULT, &gmu->flags);
+			status = kgsl_pwrctrl_enable(device);
+			if (status) {
+				/*
+				 * Cannot recover GMU failure
+				 * GPU will not be powered on
+				 */
+				WARN_ONCE(1, "Failed to recover GMU\n");
+			}
+
+			clear_bit(GMU_FAULT, &gmu->flags);
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_AWARE);
+			return status;
+		}
+
 		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
-	else
+	} else {
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_AWARE);
+	}
 	return status;
 }
 
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index e704db7..f9494a4 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -573,16 +573,34 @@
 	snapshot->size += header->size;
 }
 
+static void kgsl_free_snapshot(struct kgsl_snapshot *snapshot)
+{
+	struct kgsl_snapshot_object *obj, *tmp;
+
+	wait_for_completion(&snapshot->dump_gate);
+
+	list_for_each_entry_safe(obj, tmp,
+				&snapshot->obj_list, node)
+		kgsl_snapshot_put_object(obj);
+
+	if (snapshot->mempool)
+		vfree(snapshot->mempool);
+
+	kfree(snapshot);
+	KGSL_CORE_ERR("snapshot: objects released\n");
+}
+
 /**
  * kgsl_snapshot() - construct a device snapshot
  * @device: device to snapshot
  * @context: the context that is hung, might be NULL if unknown.
+ * @gmu_fault: whether this snapshot is triggered by a GMU fault.
  *
  * Given a device, construct a binary snapshot dump of the current device state
  * and store it in the device snapshot memory.
  */
 void kgsl_device_snapshot(struct kgsl_device *device,
-		struct kgsl_context *context)
+		struct kgsl_context *context, bool gmu_fault)
 {
 	struct kgsl_snapshot_header *header = device->snapshot_memory.ptr;
 	struct kgsl_snapshot *snapshot;
@@ -603,11 +621,20 @@
 	device->snapshot_faultcount++;
 
 	/*
-	 * The first hang is always the one we are interested in. Don't capture
-	 * a new snapshot instance if the old one hasn't been grabbed yet
+	 * Overwrite a non-GMU fault snapshot if a GMU fault occurs.
 	 */
-	if (device->snapshot != NULL)
-		return;
+	if (device->snapshot != NULL) {
+		if (!gmu_fault || device->snapshot->gmu_fault)
+			return;
+
+		/*
+		 * If another thread is currently reading it, that thread
+		 * will free it, otherwise free it now.
+		 */
+		if (!device->snapshot->sysfs_read)
+			kgsl_free_snapshot(device->snapshot);
+		device->snapshot = NULL;
+	}
 
 	/* Allocate memory for the snapshot instance */
 	snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
@@ -622,7 +649,9 @@
 	snapshot->start = device->snapshot_memory.ptr;
 	snapshot->ptr = device->snapshot_memory.ptr;
 	snapshot->remain = device->snapshot_memory.size;
-	atomic_set(&snapshot->sysfs_read, 0);
+	snapshot->gmu_fault = gmu_fault;
+	snapshot->first_read = true;
+	snapshot->sysfs_read = 0;
 
 	header = (struct kgsl_snapshot_header *) snapshot->ptr;
 
@@ -711,6 +740,30 @@
 #define kobj_to_device(a) \
 container_of(a, struct kgsl_device, snapshot_kobj)
 
+static int snapshot_release(struct kgsl_device *device,
+	struct kgsl_snapshot *snapshot)
+{
+	bool snapshot_free = false;
+	int ret = 0;
+
+	mutex_lock(&device->mutex);
+	snapshot->sysfs_read--;
+
+	/*
+	 * If someone's replaced the snapshot, return an error and free
+	 * the snapshot if this is the last thread to read it.
+	 */
+	if (device->snapshot != snapshot) {
+		ret = -EIO;
+		if (!snapshot->sysfs_read)
+			snapshot_free = true;
+	}
+	mutex_unlock(&device->mutex);
+	if (snapshot_free)
+		kgsl_free_snapshot(snapshot);
+	return ret;
+}
+
 /* Dump the sysfs binary data to the user */
 static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
 	struct bin_attribute *attr, char *buf, loff_t off,
@@ -718,20 +771,35 @@
 {
 	struct kgsl_device *device = kobj_to_device(kobj);
 	struct kgsl_snapshot *snapshot;
-	struct kgsl_snapshot_object *obj, *tmp;
 	struct kgsl_snapshot_section_header head;
 	struct snapshot_obj_itr itr;
-	int ret;
+	int ret = 0;
 
 	if (device == NULL)
 		return 0;
 
 	mutex_lock(&device->mutex);
 	snapshot = device->snapshot;
-	if (snapshot != NULL)
-		atomic_inc(&snapshot->sysfs_read);
+	if (snapshot != NULL) {
+		/*
+		 * If we're reading at a non-zero offset from a new snapshot,
+		 * that means we want to read from the previous snapshot (which
+		 * was overwritten), so return an error
+		 */
+		if (snapshot->first_read) {
+			if (off)
+				ret = -EIO;
+			else
+				snapshot->first_read = false;
+		}
+		if (!ret)
+			snapshot->sysfs_read++;
+	}
 	mutex_unlock(&device->mutex);
 
+	if (ret)
+		return ret;
+
 	/* Return nothing if we haven't taken a snapshot yet */
 	if (snapshot == NULL)
 		return 0;
@@ -742,7 +810,7 @@
 	 */
 	ret = wait_for_completion_interruptible(&snapshot->dump_gate);
 	if (ret) {
-		atomic_dec(&snapshot->sysfs_read);
+		snapshot_release(device, snapshot);
 		return ret;
 	}
 
@@ -779,29 +847,21 @@
 		bool snapshot_free = false;
 
 		mutex_lock(&device->mutex);
-		if (atomic_dec_and_test(&snapshot->sysfs_read)) {
-			device->snapshot = NULL;
+		if (--snapshot->sysfs_read == 0) {
+			if (device->snapshot == snapshot)
+				device->snapshot = NULL;
 			snapshot_free = true;
 		}
 		mutex_unlock(&device->mutex);
 
-		if (snapshot_free) {
-			list_for_each_entry_safe(obj, tmp,
-						&snapshot->obj_list, node)
-				kgsl_snapshot_put_object(obj);
-
-			if (snapshot->mempool)
-				vfree(snapshot->mempool);
-
-			kfree(snapshot);
-			KGSL_CORE_ERR("snapshot: objects released\n");
-		}
+		if (snapshot_free)
+			kgsl_free_snapshot(snapshot);
 		return 0;
 	}
 
 done:
-	atomic_dec(&snapshot->sysfs_read);
-	return itr.write;
+	ret = snapshot_release(device, snapshot);
+	return (ret < 0) ? ret : itr.write;
 }
 
 /* Show the total number of hangs since device boot */
@@ -872,9 +932,11 @@
 /* Show the timestamp of the last collected snapshot */
 static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
 {
-	unsigned long timestamp =
-		device->snapshot ? device->snapshot->timestamp : 0;
+	unsigned long timestamp;
 
+	mutex_lock(&device->mutex);
+	timestamp = device->snapshot ? device->snapshot->timestamp : 0;
+	mutex_unlock(&device->mutex);
 	return snprintf(buf, PAGE_SIZE, "%lu\n", timestamp);
 }
 
diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c
index b055ff6..357bfb2 100644
--- a/drivers/iio/adc/qcom-rradc.c
+++ b/drivers/iio/adc/qcom-rradc.c
@@ -180,6 +180,9 @@
 #define FG_ADC_RR_VOLT_INPUT_FACTOR		8
 #define FG_ADC_RR_CURR_INPUT_FACTOR		2000
 #define FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL	1886
+#define FG_ADC_RR_CURR_USBIN_660_FACTOR_MIL	9
+#define FG_ADC_RR_CURR_USBIN_660_UV_VAL	579500
+
 #define FG_ADC_SCALE_MILLI_FACTOR		1000
 #define FG_ADC_KELVINMIL_CELSIUSMIL		273150
 
@@ -192,6 +195,9 @@
 #define FG_RR_CONV_CONTINUOUS_TIME_MIN_US	50000
 #define FG_RR_CONV_CONTINUOUS_TIME_MAX_US	51000
 #define FG_RR_CONV_MAX_RETRY_CNT		50
+#define FG_RR_TP_REV_VERSION1		21
+#define FG_RR_TP_REV_VERSION2		29
+#define FG_RR_TP_REV_VERSION3		32
 
 /*
  * The channel number is not a physical index in hardware,
@@ -228,6 +234,7 @@
 	struct rradc_chan_prop		*chan_props;
 	struct device_node		*revid_dev_node;
 	struct pmic_revid_data		*pmic_fab_id;
+	int volt;
 };
 
 struct rradc_channels {
@@ -353,7 +360,7 @@
 	return 0;
 }
 
-static int rradc_post_process_curr(struct rradc_chip *chip,
+static int rradc_post_process_usbin_curr(struct rradc_chip *chip,
 			struct rradc_chan_prop *prop, u16 adc_code,
 			int *result_ua)
 {
@@ -361,11 +368,33 @@
 
 	if (!prop)
 		return -EINVAL;
-
-	if (prop->channel == RR_ADC_USBIN_I)
-		scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL;
-	else
-		scale = FG_ADC_RR_CURR_INPUT_FACTOR;
+	if (chip->revid_dev_node) {
+		switch (chip->pmic_fab_id->pmic_subtype) {
+		case PM660_SUBTYPE:
+			if (((chip->pmic_fab_id->tp_rev
+				>= FG_RR_TP_REV_VERSION1)
+			&& (chip->pmic_fab_id->tp_rev
+				<= FG_RR_TP_REV_VERSION2))
+			|| (chip->pmic_fab_id->tp_rev
+				>= FG_RR_TP_REV_VERSION3)) {
+				chip->volt = div64_s64(chip->volt, 1000);
+				chip->volt = chip->volt *
+					FG_ADC_RR_CURR_USBIN_660_FACTOR_MIL;
+				chip->volt = FG_ADC_RR_CURR_USBIN_660_UV_VAL -
+					(chip->volt);
+				chip->volt = div64_s64(1000000000, chip->volt);
+				scale = chip->volt;
+			} else
+				scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL;
+			break;
+		case PMI8998_SUBTYPE:
+			scale = FG_ADC_RR_CURR_USBIN_INPUT_FACTOR_MIL;
+			break;
+		default:
+			pr_err("No PMIC subtype found\n");
+			return -EINVAL;
+		}
+	}
 
 	/* scale * V/A; 2.5V ADC full scale */
 	ua = ((int64_t)adc_code * scale);
@@ -376,6 +405,24 @@
 	return 0;
 }
 
+static int rradc_post_process_dcin_curr(struct rradc_chip *chip,
+			struct rradc_chan_prop *prop, u16 adc_code,
+			int *result_ua)
+{
+	int64_t ua = 0;
+
+	if (!prop)
+		return -EINVAL;
+
+	/* 0.5 V/A; 2.5V ADC full scale */
+	ua = ((int64_t)adc_code * FG_ADC_RR_CURR_INPUT_FACTOR);
+	ua *= (FG_ADC_RR_FS_VOLTAGE_MV * FG_ADC_SCALE_MILLI_FACTOR);
+	ua = div64_s64(ua, (FG_MAX_ADC_READINGS * 1000));
+	*result_ua = ua;
+
+	return 0;
+}
+
 static int rradc_post_process_die_temp(struct rradc_chip *chip,
 			struct rradc_chan_prop *prop, u16 adc_code,
 			int *result_millidegc)
@@ -591,13 +638,13 @@
 			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),
 			FG_ADC_RR_SKIN_TEMP_LSB, FG_ADC_RR_SKIN_TEMP_MSB,
 			FG_ADC_RR_AUX_THERM_STS)
-	RR_ADC_CHAN_CURRENT("usbin_i", &rradc_post_process_curr,
+	RR_ADC_CHAN_CURRENT("usbin_i", &rradc_post_process_usbin_curr,
 			FG_ADC_RR_USB_IN_I_LSB, FG_ADC_RR_USB_IN_I_MSB,
 			FG_ADC_RR_USB_IN_I_STS)
 	RR_ADC_CHAN_VOLT("usbin_v", &rradc_post_process_volt,
 			FG_ADC_RR_USB_IN_V_LSB, FG_ADC_RR_USB_IN_V_MSB,
 			FG_ADC_RR_USB_IN_V_STS)
-	RR_ADC_CHAN_CURRENT("dcin_i", &rradc_post_process_curr,
+	RR_ADC_CHAN_CURRENT("dcin_i", &rradc_post_process_dcin_curr,
 			FG_ADC_RR_DC_IN_I_LSB, FG_ADC_RR_DC_IN_I_MSB,
 			FG_ADC_RR_DC_IN_I_STS)
 	RR_ADC_CHAN_VOLT("dcin_v", &rradc_post_process_volt,
@@ -955,6 +1002,21 @@
 
 	switch (mask) {
 	case IIO_CHAN_INFO_PROCESSED:
+		if (((chip->pmic_fab_id->tp_rev
+				>= FG_RR_TP_REV_VERSION1)
+		&& (chip->pmic_fab_id->tp_rev
+				<= FG_RR_TP_REV_VERSION2))
+		|| (chip->pmic_fab_id->tp_rev
+				>= FG_RR_TP_REV_VERSION3)) {
+			if (chan->address == RR_ADC_USBIN_I) {
+				prop = &chip->chan_props[RR_ADC_USBIN_V];
+				rc = rradc_do_conversion(chip, prop, &adc_code);
+				if (rc)
+					break;
+				prop->scale(chip, prop, adc_code, &chip->volt);
+			}
+		}
+
 		prop = &chip->chan_props[chan->address];
 		rc = rradc_do_conversion(chip, prop, &adc_code);
 		if (rc)
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 7a6f50b..66d1499 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -92,6 +92,7 @@
 	struct kobject *sysfs_kobject;
 	s16 ROI[MAX_ROI_SIZE];
 	s16 accelBuffer[MAX_ACCEL_SIZE];
+	u32 display_status;
 };
 
 static struct hbtp_data *hbtp;
@@ -1425,10 +1426,11 @@
 	if (ret) {
 		pr_err("hbtp: ret error: %zd\n", ret);
 		mutex_unlock(&hbtp->mutex);
-		return ret;
+		return 0;
 	}
-	if (!hbtp || !hbtp->input_dev) {
-		pr_err("hbtp: hbtp or hbtp->input_dev not ready!\n");
+	hbtp->display_status = status;
+	if (!hbtp->input_dev) {
+		pr_err("hbtp: hbtp->input_dev not ready!\n");
 		mutex_unlock(&hbtp->mutex);
 		return ret;
 	}
@@ -1445,8 +1447,20 @@
 	return count;
 }
 
+static ssize_t hbtp_display_pwr_show(struct kobject *kobj,
+		struct kobj_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+
+	mutex_lock(&hbtp->mutex);
+	ret = snprintf(buf, PAGE_SIZE, "%u\n", hbtp->display_status);
+	mutex_unlock(&hbtp->mutex);
+	return ret;
+}
+
 static struct kobj_attribute hbtp_display_attribute =
-		__ATTR(display_pwr, 0660, NULL, hbtp_display_pwr_store);
+		__ATTR(display_pwr, 0660, hbtp_display_pwr_show,
+			hbtp_display_pwr_store);
 
 static int __init hbtp_init(void)
 {
@@ -1463,6 +1477,7 @@
 
 	mutex_init(&hbtp->mutex);
 	mutex_init(&hbtp->sensormutex);
+	hbtp->display_status = 1;
 
 	error = misc_register(&hbtp_input_misc);
 	if (error) {
@@ -1545,6 +1560,8 @@
 	sysfs_remove_bin_file(sensor_kobject, &vibdata_attr);
 	sysfs_remove_bin_file(sensor_kobject, &capdata_attr);
 	kobject_put(sensor_kobject);
+	sysfs_remove_file(hbtp->sysfs_kobject, &hbtp_display_attribute.attr);
+	kobject_put(hbtp->sysfs_kobject);
 	misc_deregister(&hbtp_input_misc);
 	if (hbtp->input_dev)
 		input_unregister_device(hbtp->input_dev);
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index a2c5579..9c0dde4 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -427,6 +427,7 @@
 #define ARM_SMMU_OPT_DYNAMIC		(1 << 3)
 #define ARM_SMMU_OPT_3LVL_TABLES	(1 << 4)
 #define ARM_SMMU_OPT_NO_ASID_RETENTION	(1 << 5)
+#define ARM_SMMU_OPT_DISABLE_ATOS	(1 << 6)
 	u32				options;
 	enum arm_smmu_arch_version	version;
 	enum arm_smmu_implementation	model;
@@ -547,6 +548,7 @@
 	{ ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" },
 	{ ARM_SMMU_OPT_3LVL_TABLES, "qcom,use-3-lvl-tables" },
 	{ ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" },
+	{ ARM_SMMU_OPT_DISABLE_ATOS, "qcom,disable-atos" },
 	{ 0, NULL},
 };
 
@@ -2490,6 +2492,10 @@
 	phys_addr_t ret = 0;
 	unsigned long flags;
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+
+	if (smmu->options & ARM_SMMU_OPT_DISABLE_ATOS)
+		return 0;
 
 	if (smmu_domain->smmu->arch_ops &&
 	    smmu_domain->smmu->arch_ops->iova_to_phys_hard) {
@@ -3265,11 +3271,6 @@
 	u32 sctlr, sctlr_orig, fsr;
 	void __iomem *cb_base;
 
-	if (smmu->model == QCOM_SMMUV2) {
-		dev_err(smmu->dev, "ATOS support is disabled\n");
-		return 0;
-	}
-
 	ret = arm_smmu_power_on(smmu_domain->smmu->pwr);
 	if (ret)
 		return ret;
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index d92a352..da4d283 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -202,39 +202,58 @@
 	}
 }
 
-static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size,
-		dma_addr_t dma_limit)
+static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
+		size_t size, dma_addr_t dma_limit, struct device *dev)
 {
 	struct iova_domain *iovad = cookie_iovad(domain);
 	unsigned long shift = iova_shift(iovad);
-	unsigned long length = iova_align(iovad, size) >> shift;
+	unsigned long iova_len = size >> shift;
+	unsigned long iova = 0;
+	dma_addr_t limit;
+
+	/*
+	 * Freeing non-power-of-two-sized allocations back into the IOVA caches
+	 * will come back to bite us badly, so we have to waste a bit of space
+	 * rounding up anything cacheable to make sure that can't happen. The
+	 * order of the unadjusted size will still match upon freeing.
+	 */
+	if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1)))
+		iova_len = roundup_pow_of_two(iova_len);
 
 	if (domain->geometry.force_aperture)
 		dma_limit = min(dma_limit, domain->geometry.aperture_end);
+
 	/*
-	 * Enforce size-alignment to be safe - there could perhaps be an
-	 * attribute to control this per-device, or at least per-domain...
+	 * Ensure iova is within range specified in iommu_dma_init_domain().
+	 * This also prevents unnecessary work iterating through the entire
+	 * rb_tree.
 	 */
-	return alloc_iova(iovad, length, dma_limit >> shift, true);
+	limit = min_t(dma_addr_t, dma_limit >> shift, iovad->dma_32bit_pfn);
+	iova = alloc_iova_fast(iovad, iova_len, limit);
+
+	return (dma_addr_t)iova << shift;
 }
 
-/* The IOVA allocator knows what we mapped, so just unmap whatever that was */
-static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr)
+static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
+		dma_addr_t iova, size_t size)
+{
+	struct iova_domain *iovad = &cookie->iovad;
+	unsigned long shift = iova_shift(iovad);
+
+	free_iova_fast(iovad, iova >> shift, size >> shift);
+}
+
+static void __iommu_dma_unmap(struct iommu_domain *domain, dma_addr_t dma_addr,
+		size_t size)
 {
 	struct iova_domain *iovad = cookie_iovad(domain);
-	unsigned long shift = iova_shift(iovad);
-	unsigned long pfn = dma_addr >> shift;
-	struct iova *iova = find_iova(iovad, pfn);
-	size_t size;
+	size_t iova_off = iova_offset(iovad, dma_addr);
 
-	if (WARN_ON(!iova))
-		return;
+	dma_addr -= iova_off;
+	size = iova_align(iovad, size + iova_off);
 
-	size = iova_size(iova) << shift;
-	size -= iommu_unmap(domain, pfn << shift, size);
-	/* ...and if we can't, then something is horribly, horribly wrong */
-	WARN_ON(size > 0);
-	__free_iova(iovad, iova);
+	WARN_ON(iommu_unmap(domain, dma_addr, size) != size);
+	iommu_dma_free_iova(domain->iova_cookie, dma_addr, size);
 }
 
 static void __iommu_dma_free_pages(struct page **pages, int count)
@@ -316,7 +335,7 @@
 void iommu_dma_free(struct device *dev, struct page **pages, size_t size,
 		dma_addr_t *handle)
 {
-	__iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle);
+	__iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle, size);
 	__iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
 	*handle = DMA_ERROR_CODE;
 }
@@ -344,11 +363,11 @@
 		void (*flush_page)(struct device *, const void *, phys_addr_t))
 {
 	struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
-	struct iova_domain *iovad = cookie_iovad(domain);
-	struct iova *iova;
+	struct iommu_dma_cookie *cookie = domain->iova_cookie;
+	struct iova_domain *iovad = &cookie->iovad;
 	struct page **pages;
 	struct sg_table sgt;
-	dma_addr_t dma_addr;
+	dma_addr_t iova;
 	unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;
 
 	*handle = DMA_ERROR_CODE;
@@ -368,11 +387,11 @@
 	if (!pages)
 		return NULL;
 
-	iova = __alloc_iova(domain, size, dev->coherent_dma_mask);
+	size = iova_align(iovad, size);
+	iova = iommu_dma_alloc_iova(domain, size, dev->coherent_dma_mask, dev);
 	if (!iova)
 		goto out_free_pages;
 
-	size = iova_align(iovad, size);
 	if (sg_alloc_table_from_pages(&sgt, pages, count, 0, size, GFP_KERNEL))
 		goto out_free_iova;
 
@@ -388,19 +407,18 @@
 		sg_miter_stop(&miter);
 	}
 
-	dma_addr = iova_dma_addr(iovad, iova);
-	if (iommu_map_sg(domain, dma_addr, sgt.sgl, sgt.orig_nents, prot)
+	if (iommu_map_sg(domain, iova, sgt.sgl, sgt.orig_nents, prot)
 			< size)
 		goto out_free_sg;
 
-	*handle = dma_addr;
+	*handle = iova;
 	sg_free_table(&sgt);
 	return pages;
 
 out_free_sg:
 	sg_free_table(&sgt);
 out_free_iova:
-	__free_iova(iovad, iova);
+	iommu_dma_free_iova(cookie, iova, size);
 out_free_pages:
 	__iommu_dma_free_pages(pages, count);
 	return NULL;
@@ -434,22 +452,22 @@
 static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
 		size_t size, int prot)
 {
-	dma_addr_t dma_addr;
 	struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
-	struct iova_domain *iovad = cookie_iovad(domain);
+	struct iommu_dma_cookie *cookie = domain->iova_cookie;
+	struct iova_domain *iovad = &cookie->iovad;
 	size_t iova_off = iova_offset(iovad, phys);
-	size_t len = iova_align(iovad, size + iova_off);
-	struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev));
+	dma_addr_t iova;
 
+	size = iova_align(iovad, size + iova_off);
+	iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
 	if (!iova)
 		return DMA_ERROR_CODE;
 
-	dma_addr = iova_dma_addr(iovad, iova);
-	if (iommu_map(domain, dma_addr, phys - iova_off, len, prot)) {
-		__free_iova(iovad, iova);
+	if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
+		iommu_dma_free_iova(cookie, iova, size);
 		return DMA_ERROR_CODE;
 	}
-	return dma_addr + iova_off;
+	return iova + iova_off;
 }
 
 dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
@@ -461,7 +479,7 @@
 void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
 		enum dma_data_direction dir, unsigned long attrs)
 {
-	__iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle);
+	__iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size);
 }
 
 /*
@@ -550,10 +568,10 @@
 		int nents, int prot)
 {
 	struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
-	struct iova_domain *iovad = cookie_iovad(domain);
-	struct iova *iova;
+	struct iommu_dma_cookie *cookie = domain->iova_cookie;
+	struct iova_domain *iovad = &cookie->iovad;
 	struct scatterlist *s, *prev = NULL;
-	dma_addr_t dma_addr;
+	dma_addr_t iova;
 	size_t iova_len = 0;
 	unsigned long mask = dma_get_seg_boundary(dev);
 	int i;
@@ -597,7 +615,7 @@
 		prev = s;
 	}
 
-	iova = __alloc_iova(domain, iova_len, dma_get_mask(dev));
+	iova = iommu_dma_alloc_iova(domain, iova_len, dma_get_mask(dev), dev);
 	if (!iova)
 		goto out_restore_sg;
 
@@ -605,14 +623,13 @@
 	 * We'll leave any physical concatenation to the IOMMU driver's
 	 * implementation - it knows better than we do.
 	 */
-	dma_addr = iova_dma_addr(iovad, iova);
-	if (iommu_map_sg(domain, dma_addr, sg, nents, prot) < iova_len)
+	if (iommu_map_sg(domain, iova, sg, nents, prot) < iova_len)
 		goto out_free_iova;
 
-	return __finalise_sg(dev, sg, nents, dma_addr);
+	return __finalise_sg(dev, sg, nents, iova);
 
 out_free_iova:
-	__free_iova(iovad, iova);
+	iommu_dma_free_iova(cookie, iova, iova_len);
 out_restore_sg:
 	__invalidate_sg(sg, nents);
 	return 0;
@@ -621,11 +638,21 @@
 void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
 		enum dma_data_direction dir, unsigned long attrs)
 {
+	dma_addr_t start, end;
+	struct scatterlist *tmp;
+	int i;
 	/*
 	 * The scatterlist segments are mapped into a single
 	 * contiguous IOVA allocation, so this is incredibly easy.
 	 */
-	__iommu_dma_unmap(iommu_get_domain_for_dev(dev), sg_dma_address(sg));
+	start = sg_dma_address(sg);
+	for_each_sg(sg_next(sg), tmp, nents - 1, i) {
+		if (sg_dma_len(tmp) == 0)
+			break;
+		sg = tmp;
+	}
+	end = sg_dma_address(sg) + sg_dma_len(sg);
+	__iommu_dma_unmap(iommu_get_domain_for_dev(dev), start, end - start);
 }
 
 dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
@@ -638,7 +665,7 @@
 void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
 		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
-	__iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle);
+	__iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle, size);
 }
 
 int iommu_dma_supported(struct device *dev, u64 mask)
@@ -662,7 +689,7 @@
 	struct iommu_dma_cookie *cookie = domain->iova_cookie;
 	struct iommu_dma_msi_page *msi_page;
 	struct iova_domain *iovad = &cookie->iovad;
-	struct iova *iova;
+	dma_addr_t iova;
 	int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
 
 	msi_addr &= ~(phys_addr_t)iova_mask(iovad);
@@ -674,12 +701,13 @@
 	if (!msi_page)
 		return NULL;
 
-	iova = __alloc_iova(domain, iovad->granule, dma_get_mask(dev));
+	iova = iommu_dma_alloc_iova(domain, iovad->granule, dma_get_mask(dev),
+				    dev);
 	if (!iova)
 		goto out_free_page;
 
 	msi_page->phys = msi_addr;
-	msi_page->iova = iova_dma_addr(iovad, iova);
+	msi_page->iova = iova;
 	if (iommu_map(domain, msi_page->iova, msi_addr, iovad->granule, prot))
 		goto out_free_iova;
 
@@ -688,7 +716,7 @@
 	return msi_page;
 
 out_free_iova:
-	__free_iova(iovad, iova);
+	iommu_dma_free_iova(cookie, iova, iovad->granule);
 out_free_page:
 	kfree(msi_page);
 	return NULL;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index 03c5eb3..b015452 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -71,6 +71,16 @@
 	PACKER_FMT_MAX                         = 0xF,
 };
 
+enum cam_vfe_bus_comp_grp_id {
+	CAM_VFE_BUS_COMP_GROUP_NONE = -EINVAL,
+	CAM_VFE_BUS_COMP_GROUP_ID_0 = 0x0,
+	CAM_VFE_BUS_COMP_GROUP_ID_1 = 0x1,
+	CAM_VFE_BUS_COMP_GROUP_ID_2 = 0x2,
+	CAM_VFE_BUS_COMP_GROUP_ID_3 = 0x3,
+	CAM_VFE_BUS_COMP_GROUP_ID_4 = 0x4,
+	CAM_VFE_BUS_COMP_GROUP_ID_5 = 0x5,
+};
+
 struct cam_vfe_bus_ver2_common_data {
 	uint32_t                                    core_index;
 	void __iomem                               *mem_base;
@@ -136,6 +146,9 @@
 	uint32_t                         intra_client_mask;
 	uint32_t                         composite_mask;
 
+	uint32_t                         acquire_dev_cnt;
+	uint32_t                         irq_trigger_cnt;
+
 	void                            *ctx;
 };
 
@@ -187,6 +200,28 @@
 	return 0;
 }
 
+static enum cam_vfe_bus_comp_grp_id
+	cam_vfe_bus_comp_grp_id_convert(uint32_t comp_grp)
+{
+	switch (comp_grp) {
+	case CAM_ISP_RES_COMP_GROUP_ID_0:
+		return CAM_VFE_BUS_COMP_GROUP_ID_0;
+	case CAM_ISP_RES_COMP_GROUP_ID_1:
+		return CAM_VFE_BUS_COMP_GROUP_ID_1;
+	case CAM_ISP_RES_COMP_GROUP_ID_2:
+		return CAM_VFE_BUS_COMP_GROUP_ID_2;
+	case CAM_ISP_RES_COMP_GROUP_ID_3:
+		return CAM_VFE_BUS_COMP_GROUP_ID_3;
+	case CAM_ISP_RES_COMP_GROUP_ID_4:
+		return CAM_VFE_BUS_COMP_GROUP_ID_4;
+	case CAM_ISP_RES_COMP_GROUP_ID_5:
+		return CAM_VFE_BUS_COMP_GROUP_ID_5;
+	case CAM_ISP_RES_COMP_GROUP_NONE:
+	default:
+		return CAM_VFE_BUS_COMP_GROUP_NONE;
+	}
+}
+
 static int cam_vfe_bus_put_evt_payload(void     *core_info,
 	struct cam_vfe_bus_irq_evt_payload     **evt_payload)
 {
@@ -1188,12 +1223,18 @@
 	struct cam_isp_resource_node       **comp_grp)
 {
 	int rc = 0;
+	uint32_t bus_comp_grp_id;
 	struct cam_isp_resource_node           *comp_grp_local = NULL;
 	struct cam_vfe_bus_ver2_comp_grp_data  *rsrc_data = NULL;
 
-	/* Check if matching comp_grp already acquired */
-	cam_vfe_bus_match_comp_grp(ver2_bus_priv, &comp_grp_local,
-		out_port_info->comp_grp_id, unique_id);
+	bus_comp_grp_id = cam_vfe_bus_comp_grp_id_convert(
+		out_port_info->comp_grp_id);
+	/* Perform match only if there is valid comp grp request */
+	if (out_port_info->comp_grp_id != CAM_ISP_RES_COMP_GROUP_NONE) {
+		/* Check if matching comp_grp already acquired */
+		cam_vfe_bus_match_comp_grp(ver2_bus_priv, &comp_grp_local,
+			bus_comp_grp_id, unique_id);
+	}
 
 	if (!comp_grp_local) {
 		/* First find a free group */
@@ -1228,7 +1269,7 @@
 		rsrc_data->is_master = is_master;
 		rsrc_data->composite_mask = 0;
 		rsrc_data->unique_id = unique_id;
-		rsrc_data->comp_grp_local_idx = out_port_info->comp_grp_id;
+		rsrc_data->comp_grp_local_idx = bus_comp_grp_id;
 
 		list_add_tail(&comp_grp_local->list,
 			&ver2_bus_priv->used_comp_grp);
@@ -1246,6 +1287,7 @@
 	}
 
 	rsrc_data->ctx = ctx;
+	rsrc_data->acquire_dev_cnt++;
 	*comp_grp = comp_grp_local;
 
 	return rc;
@@ -1260,15 +1302,21 @@
 	int match_found = 0;
 
 	if (!in_comp_grp) {
-		CAM_ERR(CAM_ISP, "Invalid Params Comp Grp %pK", in_rsrc_data);
+		CAM_ERR(CAM_ISP, "Invalid Params Comp Grp %pK", in_comp_grp);
 		return -EINVAL;
 	}
 
 	if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) {
-		/* Already Released. Do Nothing */
+		CAM_ERR(CAM_ISP, "Already released Comp Grp");
 		return 0;
 	}
 
+	if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) {
+		CAM_ERR(CAM_ISP, "Invalid State %d",
+			in_comp_grp->res_state);
+		return -EBUSY;
+	}
+
 	in_rsrc_data = in_comp_grp->res_priv;
 
 	list_for_each_entry(comp_grp, &ver2_bus_priv->used_comp_grp, list) {
@@ -1284,23 +1332,31 @@
 		return -ENODEV;
 	}
 
+	in_rsrc_data->acquire_dev_cnt--;
+	if (in_rsrc_data->acquire_dev_cnt == 0) {
+		list_del(&comp_grp->list);
 
-	list_del(&comp_grp->list);
-	if (in_rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
-		in_rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
-		list_add_tail(&comp_grp->list,
-			&ver2_bus_priv->free_dual_comp_grp);
-	else if (in_rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0
-		&& in_rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5)
-		list_add_tail(&comp_grp->list, &ver2_bus_priv->free_comp_grp);
+		in_rsrc_data->unique_id = 0;
+		in_rsrc_data->comp_grp_local_idx = CAM_VFE_BUS_COMP_GROUP_NONE;
+		in_rsrc_data->composite_mask = 0;
+		in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
 
-	in_rsrc_data->unique_id = 0;
-	in_rsrc_data->comp_grp_local_idx = 0;
-	in_rsrc_data->composite_mask = 0;
-	in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX;
+		comp_grp->tasklet_info = NULL;
+		comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
 
-	comp_grp->tasklet_info = NULL;
-	comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
+		if (in_rsrc_data->comp_grp_type >=
+			CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 &&
+			in_rsrc_data->comp_grp_type <=
+			CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5)
+			list_add_tail(&comp_grp->list,
+				&ver2_bus_priv->free_dual_comp_grp);
+		else if (in_rsrc_data->comp_grp_type >=
+			CAM_VFE_BUS_VER2_COMP_GRP_0 &&
+			in_rsrc_data->comp_grp_type <=
+			CAM_VFE_BUS_VER2_COMP_GRP_5)
+			list_add_tail(&comp_grp->list,
+				&ver2_bus_priv->free_comp_grp);
+	}
 
 	return 0;
 }
@@ -1491,8 +1547,13 @@
 
 		/* Regular Composite SUCCESS */
 		if (status_reg & BIT(comp_grp_id + 5)) {
-			cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0] &=
-				~BIT(comp_grp_id + 5);
+			rsrc_data->irq_trigger_cnt++;
+			if (rsrc_data->irq_trigger_cnt ==
+				rsrc_data->acquire_dev_cnt) {
+				cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0] &=
+					~BIT(comp_grp_id + 5);
+				rsrc_data->irq_trigger_cnt = 0;
+			}
 			rc = CAM_VFE_IRQ_STATUS_SUCCESS;
 		}
 
@@ -1530,8 +1591,13 @@
 
 		/* DUAL Composite SUCCESS */
 		if (status_reg & BIT(comp_grp_id)) {
-			cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2] &=
-				~BIT(comp_grp_id + 5);
+			rsrc_data->irq_trigger_cnt++;
+			if (rsrc_data->irq_trigger_cnt ==
+				rsrc_data->acquire_dev_cnt) {
+				cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2] &=
+					~BIT(comp_grp_id + 5);
+				rsrc_data->irq_trigger_cnt = 0;
+			}
 			rc = CAM_VFE_IRQ_STATUS_SUCCESS;
 		}
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
index b66480c..94a591c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/Makefile
@@ -6,3 +6,4 @@
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois/
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/Makefile b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/Makefile
new file mode 100644
index 0000000..ec1d2fd
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/Makefile
@@ -0,0 +1,9 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois_dev.o cam_ois_core.o cam_ois_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
new file mode 100644
index 0000000..72cabf1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -0,0 +1,594 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <cam_sensor_cmn_header.h>
+#include "cam_ois_core.h"
+#include "cam_ois_soc.h"
+#include "cam_sensor_util.h"
+#include "cam_debug_util.h"
+
+/**
+ * cam_ois_get_dev_handle - get device handle
+ * @o_ctrl:     ctrl structure
+ * @arg:        Camera control command argument
+ *
+ * Returns success or failure
+ */
+static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl,
+	void *arg)
+{
+	struct cam_sensor_acquire_dev    ois_acq_dev;
+	struct cam_create_dev_hdl        bridge_params;
+	struct cam_control              *cmd = (struct cam_control *)arg;
+
+	if (o_ctrl->bridge_intf.device_hdl != -1) {
+		CAM_ERR(CAM_OIS, "Device is already acquired");
+		return -EFAULT;
+	}
+	if (copy_from_user(&ois_acq_dev, (void __user *) cmd->handle,
+		sizeof(ois_acq_dev)))
+		return -EFAULT;
+
+	bridge_params.session_hdl = ois_acq_dev.session_handle;
+	bridge_params.ops = &o_ctrl->bridge_intf.ops;
+	bridge_params.v4l2_sub_dev_flag = 0;
+	bridge_params.media_entity_flag = 0;
+	bridge_params.priv = o_ctrl;
+
+	ois_acq_dev.device_handle =
+		cam_create_device_hdl(&bridge_params);
+	o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle;
+	o_ctrl->bridge_intf.session_hdl = ois_acq_dev.session_handle;
+
+	CAM_DBG(CAM_OIS, "Device Handle: %d", ois_acq_dev.device_handle);
+	if (copy_to_user((void __user *) cmd->handle, &ois_acq_dev,
+		sizeof(struct cam_sensor_acquire_dev))) {
+		CAM_ERR(CAM_OIS, "ACQUIRE_DEV: copy to user failed");
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int cam_ois_vreg_control(struct cam_ois_ctrl_t *o_ctrl,
+	int config)
+{
+	int rc = 0, cnt;
+	struct cam_hw_soc_info  *soc_info;
+
+	soc_info = &o_ctrl->soc_info;
+	cnt = soc_info->num_rgltr;
+
+	if (!cnt)
+		return 0;
+
+	if (cnt >= CAM_SOC_MAX_REGULATOR) {
+		CAM_ERR(CAM_OIS, "Regulators more than supported %d", cnt);
+		return -EINVAL;
+	}
+
+	if (config)
+		rc = cam_soc_util_enable_platform_resource(soc_info, false, 0,
+			false);
+	else
+		rc = cam_soc_util_disable_platform_resource(soc_info, false,
+			false);
+
+	return rc;
+}
+
+static int cam_ois_power_up(struct cam_ois_ctrl_t *o_ctrl)
+{
+	int rc = 0;
+	struct cam_hw_soc_info  *soc_info =
+		&o_ctrl->soc_info;
+	struct msm_camera_gpio_num_info *gpio_num_info = NULL;
+
+	rc = cam_ois_vreg_control(o_ctrl, 1);
+	if (rc < 0) {
+		CAM_ERR(CAM_OIS, "OIS Reg Failed %d", rc);
+		return rc;
+	}
+
+	gpio_num_info = o_ctrl->gpio_num_info;
+
+	if (soc_info->gpio_data &&
+		gpio_num_info &&
+		gpio_num_info->valid[SENSOR_VAF] == 1) {
+		rc = cam_soc_util_request_platform_resource(&o_ctrl->soc_info,
+			NULL, NULL);
+		rc = cam_soc_util_enable_platform_resource(&o_ctrl->soc_info,
+			false, 0, false);
+		if (rc < 0) {
+			CAM_ERR(CAM_OIS, "Failed in req gpio: %d", rc);
+			return rc;
+		}
+
+		gpio_set_value_cansleep(
+			gpio_num_info->gpio_num[SENSOR_VAF],
+			1);
+	}
+
+	/* VREG needs some delay to power up */
+	usleep_range(2000, 2050);
+
+	return rc;
+}
+
+static int cam_ois_power_down(struct cam_ois_ctrl_t *o_ctrl)
+{
+	int32_t rc = 0;
+	struct cam_hw_soc_info *soc_info =
+		&o_ctrl->soc_info;
+	struct msm_camera_gpio_num_info *gpio_num_info = NULL;
+
+	rc = cam_ois_vreg_control(o_ctrl, 0);
+	if (rc < 0) {
+		CAM_ERR(CAM_OIS, "Failed %d");
+		return rc;
+	}
+
+	gpio_num_info = o_ctrl->gpio_num_info;
+
+	if (soc_info->gpio_data &&
+		gpio_num_info &&
+		gpio_num_info->valid[SENSOR_VAF] == 1) {
+
+		gpio_set_value_cansleep(
+			gpio_num_info->gpio_num[SENSOR_VAF],
+			GPIOF_OUT_INIT_LOW);
+
+		rc = cam_soc_util_release_platform_resource(&o_ctrl->soc_info);
+		rc |= cam_soc_util_disable_platform_resource(&o_ctrl->soc_info,
+					0, 0);
+		if (rc < 0)
+			CAM_ERR(CAM_OIS,
+				"Failed to disable platform resources: %d", rc);
+	}
+
+	return rc;
+}
+
+static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl,
+	struct i2c_settings_array *i2c_set)
+{
+	struct i2c_settings_list *i2c_list;
+	int32_t rc = 0;
+	uint32_t i, size;
+
+	if (o_ctrl == NULL || i2c_set == NULL) {
+		CAM_ERR(CAM_OIS, "Invalid Args");
+		return -EINVAL;
+	}
+
+	if (i2c_set->is_settings_valid != 1) {
+		CAM_ERR(CAM_OIS, " Invalid settings");
+		return -EINVAL;
+	}
+
+	list_for_each_entry(i2c_list,
+		&(i2c_set->list_head), list) {
+		if (i2c_list->op_code ==  CAM_SENSOR_I2C_WRITE_RANDOM) {
+			rc = camera_io_dev_write(&(o_ctrl->io_master_info),
+				&(i2c_list->i2c_settings));
+			if (rc < 0) {
+				CAM_ERR(CAM_OIS,
+					"Failed in Applying i2c wrt settings");
+				return rc;
+			}
+		} else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) {
+			size = i2c_list->i2c_settings.size;
+			for (i = 0; i < size; i++) {
+				rc = camera_io_dev_poll(
+					&(o_ctrl->io_master_info),
+					i2c_list->i2c_settings.
+						reg_setting[i].reg_addr,
+					i2c_list->i2c_settings.
+						reg_setting[i].reg_data,
+					i2c_list->i2c_settings.
+						reg_setting[i].data_mask,
+					i2c_list->i2c_settings.addr_type,
+					i2c_list->i2c_settings.data_type,
+					i2c_list->i2c_settings.
+						reg_setting[i].delay);
+				if (rc < 0) {
+					CAM_ERR(CAM_OIS,
+						"i2c poll apply setting Fail");
+					return rc;
+				}
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl,
+	uint32_t *cmd_buf)
+{
+	int32_t rc = 0;
+	struct cam_cmd_ois_info *ois_info;
+
+	if (!o_ctrl || !cmd_buf) {
+		CAM_ERR(CAM_OIS, "Invalid Args");
+		return -EINVAL;
+	}
+
+	ois_info = (struct cam_cmd_ois_info *)cmd_buf;
+	if (o_ctrl->io_master_info.master_type == CCI_MASTER) {
+		o_ctrl->io_master_info.cci_client->i2c_freq_mode =
+			ois_info->i2c_freq_mode;
+		o_ctrl->io_master_info.cci_client->sid =
+			ois_info->slave_addr >> 1;
+		o_ctrl->ois_fw_flag = ois_info->ois_fw_flag;
+		o_ctrl->is_ois_calib = ois_info->is_ois_calib;
+		memcpy(o_ctrl->ois_name, ois_info->ois_name, 32);
+		o_ctrl->io_master_info.cci_client->retries = 3;
+		o_ctrl->io_master_info.cci_client->id_map = 0;
+		memcpy(&(o_ctrl->opcode), &(ois_info->opcode),
+			sizeof(struct cam_ois_opcode));
+		CAM_DBG(CAM_OIS, "Slave addr: 0x%x Freq Mode: %d",
+			ois_info->slave_addr, ois_info->i2c_freq_mode);
+	} else if (o_ctrl->io_master_info.master_type == I2C_MASTER) {
+		o_ctrl->io_master_info.client->addr = ois_info->slave_addr;
+		CAM_DBG(CAM_OIS, "Slave addr: 0x%x", ois_info->slave_addr);
+	} else {
+		CAM_ERR(CAM_OIS, "Invalid Master type : %d",
+			o_ctrl->io_master_info.master_type);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl)
+{
+	uint16_t                           total_bytes = 0;
+	uint8_t                           *ptr = NULL;
+	int32_t                            rc = 0, cnt;
+	const struct firmware             *fw = NULL;
+	const char                        *fw_name_prog = NULL;
+	const char                        *fw_name_coeff = NULL;
+	char                               name_prog[32] = {0};
+	char                               name_coeff[32] = {0};
+	struct device                     *dev = &(o_ctrl->pdev->dev);
+	struct cam_sensor_i2c_reg_setting  i2c_reg_setting;
+
+	if (!o_ctrl) {
+		CAM_ERR(CAM_OIS, "Invalid Args");
+		return -EINVAL;
+	}
+
+	snprintf(name_coeff, 32, "%s.coeff", o_ctrl->ois_name);
+
+	snprintf(name_prog, 32, "%s.prog", o_ctrl->ois_name);
+
+	/* cast pointer as const pointer*/
+	fw_name_prog = name_prog;
+	fw_name_coeff = name_coeff;
+
+	/* Load FW */
+	rc = request_firmware(&fw, fw_name_prog, dev);
+	if (rc) {
+		CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_prog);
+		return rc;
+	}
+
+	total_bytes = fw->size;
+	i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
+	i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
+	i2c_reg_setting.size = total_bytes;
+	i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)
+		kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes,
+		GFP_KERNEL);
+	if (!i2c_reg_setting.reg_setting) {
+		CAM_ERR(CAM_OIS, "Failed in allocating i2c_array");
+		release_firmware(fw);
+		return -ENOMEM;
+	}
+
+	for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes;
+		cnt++, ptr++) {
+		i2c_reg_setting.reg_setting[cnt].reg_addr =
+			o_ctrl->opcode.prog;
+		i2c_reg_setting.reg_setting[cnt].reg_data = *ptr;
+		i2c_reg_setting.reg_setting[cnt].delay = 0;
+		i2c_reg_setting.reg_setting[cnt].data_mask = 0;
+	}
+
+	rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
+		&i2c_reg_setting, 1);
+	if (rc < 0) {
+		CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
+		goto release_firmware;
+	}
+	kfree(i2c_reg_setting.reg_setting);
+	release_firmware(fw);
+
+	rc = request_firmware(&fw, fw_name_coeff, dev);
+	if (rc) {
+		CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_coeff);
+		return rc;
+	}
+
+	total_bytes = fw->size;
+	i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
+	i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
+	i2c_reg_setting.size = total_bytes;
+	i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)
+		kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes,
+		GFP_KERNEL);
+	if (!i2c_reg_setting.reg_setting) {
+		CAM_ERR(CAM_OIS, "Failed in allocating i2c_array");
+		release_firmware(fw);
+		return -ENOMEM;
+	}
+
+	for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes;
+		cnt++, ptr++) {
+		i2c_reg_setting.reg_setting[cnt].reg_addr =
+			o_ctrl->opcode.coeff;
+		i2c_reg_setting.reg_setting[cnt].reg_data = *ptr;
+		i2c_reg_setting.reg_setting[cnt].delay = 0;
+		i2c_reg_setting.reg_setting[cnt].data_mask = 0;
+	}
+
+	rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
+		&i2c_reg_setting, 1);
+	if (rc < 0)
+		CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
+
+release_firmware:
+	kfree(i2c_reg_setting.reg_setting);
+	release_firmware(fw);
+
+	return rc;
+}
+
+/**
+ * cam_ois_pkt_parse - Parse csl packet
+ * @o_ctrl:     ctrl structure
+ * @arg:        Camera control command argument
+ *
+ * Returns success or failure
+ */
+static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
+{
+	int32_t                         rc = 0;
+	uint64_t                        generic_ptr;
+	struct cam_control             *ioctl_ctrl = NULL;
+	struct cam_config_dev_cmd       dev_config;
+	struct i2c_settings_array      *i2c_reg_settings = NULL;
+	struct cam_cmd_buf_desc        *cmd_desc = NULL;
+	uint64_t                        generic_pkt_addr;
+	size_t                          pkt_len;
+	struct cam_packet              *csl_packet = NULL;
+	size_t                          len_of_buff = 0;
+	uint32_t                       *offset = NULL, *cmd_buf;
+
+	ioctl_ctrl = (struct cam_control *)arg;
+	if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle,
+		sizeof(dev_config)))
+		return -EFAULT;
+	rc = cam_mem_get_cpu_buf(dev_config.packet_handle,
+		(uint64_t *)&generic_pkt_addr, &pkt_len);
+	if (rc) {
+		CAM_ERR(CAM_OIS,
+			"error in converting command Handle Error: %d", rc);
+		return rc;
+	}
+
+	if (dev_config.offset > pkt_len) {
+		CAM_ERR(CAM_OIS,
+			"offset is out of bound: off: %lld len: %zu",
+			dev_config.offset, pkt_len);
+		return -EINVAL;
+	}
+
+	csl_packet = (struct cam_packet *)
+		(generic_pkt_addr + dev_config.offset);
+	switch (csl_packet->header.op_code & 0xFFFFFF) {
+	case CAM_OIS_PACKET_OPCODE_INIT:
+		offset = (uint32_t *)&csl_packet->payload;
+		offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
+		cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+
+		if ((csl_packet->num_cmd_buf < 2) &&
+			(csl_packet->num_cmd_buf > 3)) {
+			CAM_ERR(CAM_OIS, "wrong cmd Buffer count: %d",
+				csl_packet->num_cmd_buf);
+			return -EINVAL;
+		}
+
+		rc = cam_mem_get_cpu_buf(cmd_desc[0].mem_handle,
+			(uint64_t *)&generic_ptr, &len_of_buff);
+		if (rc < 0) {
+			CAM_ERR(CAM_OIS, "Failed to get cpu buf");
+			return rc;
+		}
+
+		cmd_buf = (uint32_t *)generic_ptr;
+		cmd_buf += cmd_desc->offset / sizeof(uint32_t);
+		rc = cam_ois_slaveInfo_pkt_parser(o_ctrl, cmd_buf);
+		if (rc < 0) {
+			CAM_ERR(CAM_OIS, "Failed in parsing the pkt");
+			return rc;
+		}
+
+		cmd_buf += (sizeof(struct cam_cmd_i2c_info)/sizeof(uint32_t));
+
+		i2c_reg_settings = &(o_ctrl->i2c_init_data);
+		i2c_reg_settings->is_settings_valid = 1;
+		i2c_reg_settings->request_id = 0;
+		rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+			&cmd_desc[1], 1);
+		if (rc < 0) {
+			CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d",
+				rc);
+			return rc;
+		}
+
+		if (o_ctrl->is_ois_calib) {
+			i2c_reg_settings = &(o_ctrl->i2c_calib_data);
+			i2c_reg_settings->is_settings_valid = 1;
+			i2c_reg_settings->request_id = 0;
+			rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+				&cmd_desc[2], 1);
+			if (rc < 0) {
+				CAM_ERR(CAM_OIS,
+					"OIS pkt parsing failed: %d", rc);
+				return rc;
+			}
+		}
+		break;
+	case CAM_OIS_PACKET_OPCODE_OIS_CONTROL:
+		offset = (uint32_t *)&csl_packet->payload;
+		offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
+		cmd_desc = (struct cam_cmd_buf_desc *)(offset);
+		i2c_reg_settings = &(o_ctrl->i2c_mode_data);
+		i2c_reg_settings->is_settings_valid = 1;
+		i2c_reg_settings->request_id = 0;
+		rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings,
+			cmd_desc, 1);
+		if (rc < 0) {
+			CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc);
+			return rc;
+		}
+
+		rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings);
+		if (rc < 0)
+			CAM_ERR(CAM_OIS, "Cannot apply mode settings");
+		break;
+	default:
+		break;
+	}
+	return rc;
+}
+
+/**
+ * cam_ois_driver_cmd - Handle ois cmds
+ * @e_ctrl:     ctrl structure
+ * @arg:        Camera control command argument
+ *
+ * Returns success or failure
+ */
+int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg)
+{
+	int                            rc = 0;
+	struct cam_ois_query_cap_t     ois_cap = {0};
+	struct cam_control            *cmd = (struct cam_control *)arg;
+
+	if (!o_ctrl) {
+		CAM_ERR(CAM_OIS, "e_ctrl is NULL");
+		return -EINVAL;
+	}
+
+	mutex_lock(&(o_ctrl->ois_mutex));
+	switch (cmd->op_code) {
+	case CAM_QUERY_CAP:
+		ois_cap.slot_info = o_ctrl->subdev_id;
+
+		if (copy_to_user((void __user *) cmd->handle,
+			&ois_cap,
+			sizeof(struct cam_ois_query_cap_t))) {
+			CAM_ERR(CAM_OIS, "Failed Copy to User");
+			return -EFAULT;
+			goto release_mutex;
+		}
+		CAM_DBG(CAM_OIS, "ois_cap: ID: %d", ois_cap.slot_info);
+		break;
+	case CAM_ACQUIRE_DEV:
+		rc = cam_ois_get_dev_handle(o_ctrl, arg);
+		if (rc) {
+			CAM_ERR(CAM_OIS, "Failed to acquire dev");
+			goto release_mutex;
+		}
+		break;
+	case CAM_START_DEV:
+		rc = cam_ois_power_up(o_ctrl);
+		if (rc) {
+			CAM_ERR(CAM_OIS, " OIS Power up failed");
+			goto release_mutex;
+		}
+		rc = camera_io_init(&o_ctrl->io_master_info);
+		if (rc) {
+			CAM_ERR(CAM_OIS, "cci_init failed");
+			goto pwr_dwn;
+		}
+
+		if (o_ctrl->ois_fw_flag) {
+			rc = cam_ois_fw_download(o_ctrl);
+			if (rc) {
+				CAM_ERR(CAM_OIS, "Failed OIS FW Download");
+				goto pwr_dwn;
+			}
+		}
+
+		rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data);
+		if (rc < 0) {
+			CAM_ERR(CAM_OIS, "Cannot apply Init settings");
+			goto pwr_dwn;
+		}
+
+		if (o_ctrl->is_ois_calib) {
+			rc = cam_ois_apply_settings(o_ctrl,
+				&o_ctrl->i2c_calib_data);
+			if (rc) {
+				CAM_ERR(CAM_OIS, "Cannot apply calib data");
+				goto pwr_dwn;
+			}
+		}
+		break;
+	case CAM_CONFIG_DEV:
+		rc = cam_ois_pkt_parse(o_ctrl, arg);
+		if (rc) {
+			CAM_ERR(CAM_OIS, "Failed in ois pkt Parsing");
+			goto release_mutex;
+		}
+		break;
+	case CAM_RELEASE_DEV:
+		if (o_ctrl->bridge_intf.device_hdl == -1) {
+			CAM_ERR(CAM_OIS, "link hdl: %d device hdl: %d",
+				o_ctrl->bridge_intf.device_hdl,
+				o_ctrl->bridge_intf.link_hdl);
+			rc = -EINVAL;
+			goto release_mutex;
+		}
+		rc = cam_destroy_device_hdl(o_ctrl->bridge_intf.device_hdl);
+		if (rc < 0)
+			CAM_ERR(CAM_OIS, "destroying the device hdl");
+		o_ctrl->bridge_intf.device_hdl = -1;
+		o_ctrl->bridge_intf.link_hdl = -1;
+		o_ctrl->bridge_intf.session_hdl = -1;
+		break;
+	case CAM_STOP_DEV:
+		rc = camera_io_release(&o_ctrl->io_master_info);
+		if (rc < 0)
+			CAM_ERR(CAM_OIS, "Failed in releasing CCI");
+		rc = cam_ois_power_down(o_ctrl);
+		if (rc < 0) {
+			CAM_ERR(CAM_OIS, "OIS Power down failed");
+			goto release_mutex;
+		}
+		break;
+	default:
+		CAM_ERR(CAM_OIS, "invalid opcode");
+		goto release_mutex;
+	}
+pwr_dwn:
+	cam_ois_power_down(o_ctrl);
+release_mutex:
+	mutex_unlock(&(o_ctrl->ois_mutex));
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h
new file mode 100644
index 0000000..13da82a
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_OIS_CORE_H_
+#define _CAM_OIS_CORE_H_
+
+#include "cam_ois_dev.h"
+
+int cam_ois_driver_cmd(struct cam_ois_ctrl_t *e_ctrl, void *arg);
+
+#endif
+/* _CAM_OIS_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
new file mode 100644
index 0000000..aeab388
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_ois_dev.h"
+#include "cam_req_mgr_dev.h"
+#include "cam_ois_soc.h"
+#include "cam_ois_core.h"
+#include "cam_debug_util.h"
+
+static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	int                       rc     = 0;
+	struct cam_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd);
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_ois_driver_cmd(o_ctrl, arg);
+		break;
+	default:
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+
+	return rc;
+}
+
+static int32_t cam_ois_update_i2c_info(struct cam_ois_ctrl_t *o_ctrl,
+	struct cam_ois_i2c_info_t *i2c_info)
+{
+	struct cam_sensor_cci_client        *cci_client = NULL;
+
+	if (o_ctrl->io_master_info.master_type == CCI_MASTER) {
+		cci_client = o_ctrl->io_master_info.cci_client;
+		if (!cci_client) {
+			CAM_ERR(CAM_OIS, "failed: cci_client %pK",
+				cci_client);
+			return -EINVAL;
+		}
+		cci_client->cci_i2c_master = o_ctrl->cci_i2c_master;
+		cci_client->sid = (i2c_info->slave_addr) >> 1;
+		cci_client->retries = 3;
+		cci_client->id_map = 0;
+		cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_ois_init_subdev_do_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, unsigned long arg)
+{
+	struct cam_control cmd_data;
+	int32_t rc = 0;
+
+	if (copy_from_user(&cmd_data, (void __user *)arg,
+		sizeof(cmd_data))) {
+		CAM_ERR(CAM_OIS,
+			"Failed to copy from user_ptr=%pK size=%zu",
+			(void __user *)arg, sizeof(cmd_data));
+		return -EFAULT;
+	}
+
+	switch (cmd) {
+	case VIDIOC_CAM_CONTROL:
+		rc = cam_ois_subdev_ioctl(sd, cmd, &cmd_data);
+		if (rc) {
+			CAM_ERR(CAM_OIS,
+				"Failed in ois suddev handling rc %d",
+				rc);
+			return rc;
+		}
+		break;
+	default:
+		CAM_ERR(CAM_OIS, "Invalid compat ioctl: %d", cmd);
+		rc = -EINVAL;
+	}
+
+	if (!rc) {
+		if (copy_to_user((void __user *)arg, &cmd_data,
+			sizeof(cmd_data))) {
+			CAM_ERR(CAM_OIS,
+				"Failed to copy from user_ptr=%pK size=%zu",
+				(void __user *)arg, sizeof(cmd_data));
+			rc = -EFAULT;
+		}
+	}
+	return rc;
+}
+#endif
+
+static const struct v4l2_subdev_internal_ops cam_ois_internal_ops;
+
+static struct v4l2_subdev_core_ops cam_ois_subdev_core_ops = {
+	.ioctl = cam_ois_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = cam_ois_init_subdev_do_ioctl,
+#endif
+};
+
+static struct v4l2_subdev_ops cam_ois_subdev_ops = {
+	.core = &cam_ois_subdev_core_ops,
+};
+
+static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl)
+{
+	int rc = 0;
+
+	o_ctrl->v4l2_dev_str.internal_ops = &cam_ois_internal_ops;
+	o_ctrl->v4l2_dev_str.ops = &cam_ois_subdev_ops;
+	strlcpy(o_ctrl->device_name, CAM_OIS_NAME,
+		sizeof(o_ctrl->device_name));
+	o_ctrl->v4l2_dev_str.name = o_ctrl->device_name;
+	o_ctrl->v4l2_dev_str.sd_flags =
+		(V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS);
+	o_ctrl->v4l2_dev_str.ent_function = CAM_OIS_DEVICE_TYPE;
+	o_ctrl->v4l2_dev_str.token = o_ctrl;
+
+	rc = cam_register_subdev(&(o_ctrl->v4l2_dev_str));
+	if (rc)
+		CAM_ERR(CAM_OIS, "fail to create subdev");
+
+	return rc;
+}
+
+static int cam_ois_i2c_driver_probe(struct i2c_client *client,
+	 const struct i2c_device_id *id)
+{
+	int                          rc = 0;
+	struct cam_ois_ctrl_t       *o_ctrl = NULL;
+	struct cam_ois_soc_private  *soc_private = NULL;
+
+	if (client == NULL || id == NULL) {
+		CAM_ERR(CAM_OIS, "Invalid Args client: %pK id: %pK",
+			client, id);
+		return -EINVAL;
+	}
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		CAM_ERR(CAM_OIS, "i2c_check_functionality failed");
+		goto probe_failure;
+	}
+
+	o_ctrl = kzalloc(sizeof(*o_ctrl), GFP_KERNEL);
+	if (!o_ctrl) {
+		CAM_ERR(CAM_OIS, "kzalloc failed");
+		rc = -ENOMEM;
+		goto probe_failure;
+	}
+
+	i2c_set_clientdata(client, o_ctrl);
+
+	o_ctrl->soc_info.dev = &client->dev;
+	o_ctrl->soc_info.dev_name = client->name;
+	o_ctrl->ois_device_type = MSM_CAMERA_I2C_DEVICE;
+	o_ctrl->io_master_info.master_type = I2C_MASTER;
+	o_ctrl->io_master_info.client = client;
+
+	soc_private = kzalloc(sizeof(struct cam_ois_soc_private),
+		GFP_KERNEL);
+	if (!soc_private) {
+		rc = -ENOMEM;
+		goto octrl_free;
+	}
+
+	o_ctrl->soc_info.soc_private = soc_private;
+	rc = cam_ois_driver_soc_init(o_ctrl);
+	if (rc) {
+		CAM_ERR(CAM_OIS, "failed: cam_sensor_parse_dt rc %d", rc);
+		goto octrl_free;
+	}
+
+	rc = cam_ois_init_subdev_param(o_ctrl);
+	if (rc)
+		goto octrl_free;
+
+	return rc;
+
+octrl_free:
+	kfree(o_ctrl);
+probe_failure:
+	return rc;
+}
+
+static int cam_ois_i2c_driver_remove(struct i2c_client *client)
+{
+	struct cam_ois_ctrl_t       *o_ctrl = i2c_get_clientdata(client);
+
+	if (!o_ctrl) {
+		CAM_ERR(CAM_OIS, "ois device is NULL");
+		return -EINVAL;
+	}
+
+	kfree(o_ctrl->soc_info.soc_private);
+	kfree(o_ctrl);
+
+	return 0;
+}
+
+static int32_t cam_ois_platform_driver_probe(
+	struct platform_device *pdev)
+{
+	int32_t                         rc = 0;
+	struct cam_ois_ctrl_t          *o_ctrl = NULL;
+	struct cam_ois_soc_private     *soc_private = NULL;
+
+	o_ctrl = kzalloc(sizeof(struct cam_ois_ctrl_t), GFP_KERNEL);
+	if (!o_ctrl)
+		return -ENOMEM;
+
+	o_ctrl->soc_info.pdev = pdev;
+	o_ctrl->soc_info.dev = &pdev->dev;
+	o_ctrl->soc_info.dev_name = pdev->name;
+
+	o_ctrl->ois_device_type = MSM_CAMERA_PLATFORM_DEVICE;
+
+	o_ctrl->io_master_info.master_type = CCI_MASTER;
+	o_ctrl->io_master_info.cci_client = kzalloc(
+		sizeof(struct cam_sensor_cci_client), GFP_KERNEL);
+	if (!o_ctrl->io_master_info.cci_client)
+		goto free_o_ctrl;
+
+	soc_private = kzalloc(sizeof(struct cam_ois_soc_private),
+		GFP_KERNEL);
+	if (!soc_private) {
+		rc = -ENOMEM;
+		goto free_cci_client;
+	}
+	o_ctrl->soc_info.soc_private = soc_private;
+
+	INIT_LIST_HEAD(&(o_ctrl->i2c_init_data.list_head));
+	INIT_LIST_HEAD(&(o_ctrl->i2c_calib_data.list_head));
+	INIT_LIST_HEAD(&(o_ctrl->i2c_mode_data.list_head));
+	mutex_init(&(o_ctrl->ois_mutex));
+	rc = cam_ois_driver_soc_init(o_ctrl);
+	if (rc) {
+		CAM_ERR(CAM_OIS, "failed: soc init rc %d", rc);
+		goto free_soc;
+	}
+
+	rc = cam_ois_init_subdev_param(o_ctrl);
+	if (rc)
+		goto free_soc;
+
+	rc = cam_ois_update_i2c_info(o_ctrl, &soc_private->i2c_info);
+	if (rc) {
+		CAM_ERR(CAM_OIS, "failed: to update i2c info rc %d", rc);
+		goto unreg_subdev;
+	}
+	o_ctrl->bridge_intf.device_hdl = -1;
+
+	platform_set_drvdata(pdev, o_ctrl);
+	v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, o_ctrl);
+
+	return rc;
+unreg_subdev:
+	cam_unregister_subdev(&(o_ctrl->v4l2_dev_str));
+free_soc:
+	kfree(soc_private);
+free_cci_client:
+	kfree(o_ctrl->io_master_info.cci_client);
+free_o_ctrl:
+	kfree(o_ctrl);
+	return rc;
+}
+
+static int cam_ois_platform_driver_remove(struct platform_device *pdev)
+{
+	struct cam_ois_ctrl_t  *o_ctrl;
+
+	o_ctrl = platform_get_drvdata(pdev);
+	if (!o_ctrl) {
+		CAM_ERR(CAM_OIS, "ois device is NULL");
+		return -EINVAL;
+	}
+
+	kfree(o_ctrl->soc_info.soc_private);
+	kfree(o_ctrl->io_master_info.cci_client);
+	kfree(o_ctrl);
+	return 0;
+}
+
+static const struct of_device_id cam_ois_dt_match[] = {
+	{ .compatible = "qcom,ois" },
+	{ }
+};
+
+
+MODULE_DEVICE_TABLE(of, cam_ois_dt_match);
+
+static struct platform_driver cam_ois_platform_driver = {
+	.driver = {
+		.name = "qcom,ois",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_ois_dt_match,
+	},
+	.probe = cam_ois_platform_driver_probe,
+	.remove = cam_ois_platform_driver_remove,
+};
+static const struct i2c_device_id cam_ois_i2c_id[] = {
+	{ "msm_ois", (kernel_ulong_t)NULL},
+	{ }
+};
+
+static struct i2c_driver cam_ois_i2c_driver = {
+	.id_table = cam_ois_i2c_id,
+	.probe  = cam_ois_i2c_driver_probe,
+	.remove = cam_ois_i2c_driver_remove,
+	.driver = {
+		.name = "msm_ois",
+	},
+};
+
+static struct cam_ois_registered_driver_t registered_driver = {
+	0, 0};
+
+static int __init cam_ois_driver_init(void)
+{
+	int rc = 0;
+
+	rc = platform_driver_register(&cam_ois_platform_driver);
+	if (rc) {
+		CAM_ERR(CAM_OIS, "platform_driver_register failed rc = %d",
+			rc);
+		return rc;
+	}
+
+	registered_driver.platform_driver = 1;
+
+	rc = i2c_add_driver(&cam_ois_i2c_driver);
+	if (rc) {
+		CAM_ERR(CAM_OIS, "i2c_add_driver failed rc = %d", rc);
+		return rc;
+	}
+
+	registered_driver.i2c_driver = 1;
+	return rc;
+}
+
+static void __exit cam_ois_driver_exit(void)
+{
+	if (registered_driver.platform_driver)
+		platform_driver_unregister(&cam_ois_platform_driver);
+
+	if (registered_driver.i2c_driver)
+		i2c_del_driver(&cam_ois_i2c_driver);
+}
+
+module_init(cam_ois_driver_init);
+module_exit(cam_ois_driver_exit);
+MODULE_DESCRIPTION("CAM OIS driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h
new file mode 100644
index 0000000..95ebed1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_OIS_DEV_H_
+#define _CAM_OIS_DEV_H_
+
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/cam_sensor.h>
+#include <cam_sensor_i2c.h>
+#include <cam_sensor_spi.h>
+#include <cam_sensor_io.h>
+#include <cam_cci_dev.h>
+#include <cam_req_mgr_util.h>
+#include <cam_req_mgr_interface.h>
+#include <cam_mem_mgr.h>
+#include <cam_subdev.h>
+#include "cam_soc_util.h"
+
+#define DEFINE_MSM_MUTEX(mutexname) \
+	static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
+
+/**
+ * struct cam_ois_registered_driver_t - registered driver info
+ * @platform_driver      :   flag indicates if platform driver is registered
+ * @i2c_driver           :   flag indicates if i2c driver is registered
+ *
+ */
+struct cam_ois_registered_driver_t {
+	bool platform_driver;
+	bool i2c_driver;
+};
+
+/**
+ * struct cam_ois_i2c_info_t - I2C info
+ * @slave_addr      :   slave address
+ * @i2c_freq_mode   :   i2c frequency mode
+ *
+ */
+struct cam_ois_i2c_info_t {
+	uint16_t slave_addr;
+	uint8_t i2c_freq_mode;
+};
+
+/**
+ * struct cam_ois_soc_private - ois soc private data structure
+ * @ois_name        :   ois name
+ * @i2c_info        :   i2c info structure
+ * @power_info      :   ois power info
+ *
+ */
+struct cam_ois_soc_private {
+	const char *ois_name;
+	struct cam_ois_i2c_info_t i2c_info;
+	struct cam_sensor_power_ctrl_t power_info;
+};
+
+/**
+ * struct cam_ois_intf_params - bridge interface params
+ * @device_hdl   : Device Handle
+ * @session_hdl  : Session Handle
+ * @ops          : KMD operations
+ * @crm_cb       : Callback API pointers
+ */
+struct cam_ois_intf_params {
+	int32_t device_hdl;
+	int32_t session_hdl;
+	int32_t link_hdl;
+	struct cam_req_mgr_kmd_ops ops;
+	struct cam_req_mgr_crm_cb *crm_cb;
+};
+
+/**
+ * struct cam_ois_ctrl_t - OIS ctrl private data
+ * @pdev            :   platform device
+ * @ois_mutex       :   ois mutex
+ * @soc_info        :   ois soc related info
+ * @io_master_info  :   Information about the communication master
+ * @gpio_num_info   :   gpio info
+ * @cci_i2c_master  :   I2C structure
+ * @v4l2_dev_str    :   V4L2 device structure
+ * @bridge_intf     :   bridge interface params
+ * @i2c_init_data   :   ois i2c init settings
+ * @i2c_mode_data   :   ois i2c mode settings
+ * @i2c_calib_data  :   ois i2c calib settings
+ * @ois_device_type :   ois device type
+ * @subdev_id       :   subdev id
+ * @ois_name        :   ois name
+ * @ois_fw_flag     :   flag for firmware download
+ * @is_ois_calib    :   flag for Calibration data
+ * @opcode          :   ois opcode
+ * @device_name     :   Device name
+ *
+ */
+struct cam_ois_ctrl_t {
+	struct platform_device *pdev;
+	struct mutex ois_mutex;
+	struct cam_hw_soc_info soc_info;
+	struct camera_io_master io_master_info;
+	struct msm_camera_gpio_num_info *gpio_num_info;
+	enum cci_i2c_master_t cci_i2c_master;
+	struct cam_subdev v4l2_dev_str;
+	struct cam_ois_intf_params bridge_intf;
+	struct i2c_settings_array i2c_init_data;
+	struct i2c_settings_array i2c_calib_data;
+	struct i2c_settings_array i2c_mode_data;
+	enum msm_camera_device_type_t ois_device_type;
+	uint32_t subdev_id;
+	char device_name[20];
+	char ois_name[32];
+	uint8_t ois_fw_flag;
+	uint8_t is_ois_calib;
+	struct cam_ois_opcode opcode;
+};
+
+#endif /*_CAM_OIS_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.c
new file mode 100644
index 0000000..916e699
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <cam_sensor_cmn_header.h>
+#include <cam_sensor_util.h>
+#include <cam_sensor_io.h>
+#include <cam_req_mgr_util.h>
+
+#include "cam_ois_soc.h"
+#include "cam_debug_util.h"
+
+/**
+ * @e_ctrl: ctrl structure
+ *
+ * Parses ois dt
+ */
+static int cam_ois_get_dt_data(struct cam_ois_ctrl_t *o_ctrl)
+{
+	int                             rc = 0;
+	struct cam_hw_soc_info         *soc_info = &o_ctrl->soc_info;
+	struct cam_ois_soc_private     *soc_private =
+		(struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private;
+	struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info;
+	struct device_node             *of_node = NULL;
+
+	of_node = soc_info->dev->of_node;
+
+	if (!of_node) {
+		CAM_ERR(CAM_OIS, "of_node is NULL, device type %d",
+			o_ctrl->ois_device_type);
+		return -EINVAL;
+	}
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc < 0) {
+		CAM_ERR(CAM_OIS, "cam_soc_util_get_dt_properties rc %d",
+			rc);
+		return rc;
+	}
+
+	if (!soc_info->gpio_data) {
+		CAM_INFO(CAM_OIS, "No GPIO found");
+		return 0;
+	}
+
+	if (!soc_info->gpio_data->cam_gpio_common_tbl_size) {
+		CAM_INFO(CAM_OIS, "No GPIO found");
+		return -EINVAL;
+	}
+
+	rc = cam_sensor_util_init_gpio_pin_tbl(soc_info,
+		&power_info->gpio_num_info);
+	if ((rc < 0) || (!power_info->gpio_num_info)) {
+		CAM_ERR(CAM_OIS, "No/Error OIS GPIOs");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+/**
+ * @o_ctrl: ctrl structure
+ *
+ * This function is called from cam_ois_platform/i2c_driver_probe, it parses
+ * the ois dt node.
+ */
+int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl)
+{
+	int                             rc = 0;
+	struct cam_hw_soc_info         *soc_info = &o_ctrl->soc_info;
+	struct device_node             *of_node = NULL;
+
+	if (!soc_info->dev) {
+		CAM_ERR(CAM_OIS, "soc_info is not initialized");
+		return -EINVAL;
+	}
+
+	of_node = soc_info->dev->of_node;
+	if (!of_node) {
+		CAM_ERR(CAM_OIS, "dev.of_node NULL");
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(of_node, "cell-index",
+		&o_ctrl->subdev_id);
+	if (rc < 0) {
+		CAM_ERR(CAM_OIS, "failed rc %d", rc);
+		return rc;
+	}
+
+	if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+		rc = of_property_read_u32(of_node, "cci-master",
+			&o_ctrl->cci_i2c_master);
+		if (rc < 0) {
+			CAM_DBG(CAM_OIS, "failed rc %d", rc);
+			return rc;
+		}
+	}
+
+	rc = cam_ois_get_dt_data(o_ctrl);
+	if (rc < 0)
+		CAM_DBG(CAM_OIS, "failed: ois get dt data rc %d", rc);
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.h
new file mode 100644
index 0000000..af04134
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_soc.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CAM_OIS_SOC_H_
+#define _CAM_OIS_SOC_H_
+
+#include "cam_ois_dev.h"
+
+int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl);
+
+#endif/* _CAM_OIS_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
index 6ebd58b..97b4c01 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -33,6 +33,7 @@
 #define CAM_CSIPHY_NAME    "cam-csiphy"
 #define CAM_FLASH_NAME     "cam-flash"
 #define CAM_EEPROM_NAME    "cam-eeprom"
+#define CAM_OIS_NAME       "cam-ois"
 
 #define MAX_SYSTEM_PIPELINE_DELAY 2
 
@@ -165,6 +166,11 @@
 	CAM_EEPROM_PACKET_OPCODE_INIT
 };
 
+enum cam_ois_packet_opcodes {
+	CAM_OIS_PACKET_OPCODE_INIT,
+	CAM_OIS_PACKET_OPCODE_OIS_CONTROL
+};
+
 enum msm_bus_perf_setting {
 	S_INIT,
 	S_PREVIEW,
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
index 21f90ca..f451155 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
@@ -83,6 +83,9 @@
 	case CAM_HFI:
 		name = "CAM-HFI";
 		break;
+	case CAM_OIS:
+		name = "CAM-OIS";
+		break;
 	default:
 		name = "CAM";
 		break;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
index 7275d56..40dbe00 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
@@ -33,6 +33,7 @@
 #define CAM_UTIL       (1 << 17)
 #define CAM_HFI        (1 << 18)
 #define CAM_CTXT       (1 << 19)
+#define CAM_OIS        (1 << 20)
 
 #define STR_BUFFER_MAX_LENGTH  1024
 
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index f16c1ba..39793b6 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -523,13 +523,17 @@
 	int level;
 	struct mpq_demux *mpq_demux = fp->private_data;
 
-	if (count >= 16)
+	if (count == 0 || count >= 16)
 		return -EINVAL;
 
-	ret_count = simple_write_to_buffer(user_str, 16, position, user_buffer,
+	memset(user_str, '\0', sizeof(user_str));
+
+	ret_count = simple_write_to_buffer(user_str, 15, position, user_buffer,
 		count);
 	if (ret_count < 0)
 		return ret_count;
+	else if (ret_count == 0)
+		return -EINVAL;
 
 	ret = kstrtoint(user_str, 0, &level);
 	if (ret)
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index b1438d5..47e8d5f 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -157,6 +157,7 @@
 	struct reg_bus_client *reg_bus_clt;
 	bool domain_attached;
 	int domain;
+	u32 sid;
 };
 
 /*
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 0704602..a7717f2 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -45,18 +45,12 @@
 /* Rotator device id to be used in SCM call */
 #define SDE_ROTATOR_DEVICE	21
 
-#ifndef VMID_CP_CAMERA_PREVIEW
-#define VMID_CP_CAMERA_PREVIEW	VMID_INVAL
-#endif
-
-/* SCM call function id to be used for switching between secure and non
+/*
+ * SCM call function id to be used for switching between secure and non
  * secure context
  */
 #define MEM_PROTECT_SD_CTRL_SWITCH 0x18
 
-/* Rotator secure SID */
-#define SDE_ROTATOR_SECURE_SID  0xe01
-
 /* waiting for hw time out, 3 vsync for 30fps*/
 #define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100
 
@@ -601,7 +595,7 @@
 
 	if (test_bit(SDE_CAPS_SEC_ATTACH_DETACH_SMMU,
 		mdata->sde_caps_map)) {
-		sid_info = SDE_ROTATOR_SECURE_SID;
+		sid_info = mdata->sde_smmu[SDE_IOMMU_DOMAIN_ROT_SECURE].sid;
 		desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
 		desc.args[0] = SDE_ROTATOR_DEVICE;
 		desc.args[1] = SCM_BUFFER_PHYS(&sid_info);
@@ -631,9 +625,12 @@
 				return -EINVAL;
 			}
 
-			SDEROT_DBG("scm_call(1) ret=%d, resp=%x",
+			SDEROT_DBG(
+			  "scm(1) sid0x%x dev0x%llx vmid0x%llx ret%d resp%x\n",
+				sid_info, desc.args[0], desc.args[3],
 				ret, resp);
-			SDEROT_EVTLOG(1);
+			SDEROT_EVTLOG(1, sid_info, desc.args[0], desc.args[3],
+					ret, resp);
 		} else if (mdata->sec_cam_en && !enable) {
 			/*
 			 * Disable secure camera operation
@@ -648,12 +645,16 @@
 				MEM_PROTECT_SD_CTRL_SWITCH), &desc);
 			resp = desc.ret[0];
 
-			SDEROT_DBG("scm_call(0): ret=%d, resp=%x",
+			SDEROT_DBG(
+			  "scm(0) sid0x%x dev0x%llx vmid0x%llx ret%d resp%d\n",
+				sid_info, desc.args[0], desc.args[3],
 				ret, resp);
 
 			/* force smmu to reattach */
 			sde_smmu_secure_ctrl(1);
-			SDEROT_EVTLOG(0);
+
+			SDEROT_EVTLOG(0, sid_info, desc.args[0], desc.args[3],
+					ret, resp);
 		}
 	} else {
 		return 0;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
index 9e47187..cc1407a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
@@ -517,6 +517,7 @@
 	const struct of_device_id *match;
 	struct sde_module_power *mp;
 	char name[MAX_CLIENT_NAME_LEN];
+	u32 sid = 0;
 
 	if (!mdata) {
 		SDEROT_INFO(
@@ -538,6 +539,11 @@
 
 	if (of_find_property(pdev->dev.of_node, "iommus", NULL)) {
 		dev = &pdev->dev;
+		rc = of_property_read_u32_index(pdev->dev.of_node, "iommus",
+			1, &sid);
+		if (rc)
+			SDEROT_DBG("SID not defined for domain:%d",
+					smmu_domain.domain);
 	} else {
 		SDEROT_ERR("Invalid SMMU ctx for domain:%d\n",
 				smmu_domain.domain);
@@ -546,6 +552,7 @@
 
 	sde_smmu = &mdata->sde_smmu[smmu_domain.domain];
 	sde_smmu->domain = smmu_domain.domain;
+	sde_smmu->sid = sid;
 	mp = &sde_smmu->mp;
 	memset(mp, 0, sizeof(struct sde_module_power));
 
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index a531cb4..a378b8c 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -403,6 +403,7 @@
 		return ret;
 
 	mmc_card_set_present(card);
+	device_enable_async_suspend(&card->dev);
 
 	return 0;
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 409718b..c41f580 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1357,10 +1357,6 @@
 	int err;
 	u8 val;
 
-	/* Reduce frequency to HS */
-	max_dtr = card->ext_csd.hs_max_dtr;
-	mmc_set_clock(host, max_dtr);
-
 	/* Switch HS400 to HS DDR */
 	val = EXT_CSD_TIMING_HS;
 	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
@@ -1371,6 +1367,10 @@
 
 	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
 
+	/* Reduce frequency to HS */
+	max_dtr = card->ext_csd.hs_max_dtr;
+	mmc_set_clock(host, max_dtr);
+
 	err = mmc_switch_status(card, false);
 	if (err)
 		goto out_err;
@@ -2159,11 +2159,11 @@
 	}
 
 	card->clk_scaling_lowest = host->f_min;
-	if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS400) ||
-			(card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS200))
+	if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
+			(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200))
 		card->clk_scaling_highest = card->ext_csd.hs200_max_dtr;
-	else if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS) ||
-			(card->mmc_avail_type | EXT_CSD_CARD_TYPE_DDR_52))
+	else if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) ||
+			(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
 		card->clk_scaling_highest = card->ext_csd.hs_max_dtr;
 	else
 		card->clk_scaling_highest = card->csd.max_dtr;
diff --git a/drivers/mmc/host/sdhci-msm-ice.c b/drivers/mmc/host/sdhci-msm-ice.c
index d624b48..2cb13bd 100644
--- a/drivers/mmc/host/sdhci-msm-ice.c
+++ b/drivers/mmc/host/sdhci-msm-ice.c
@@ -312,6 +312,42 @@
 	return 0;
 }
 
+int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+			struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_msm_host *msm_host = pltfm_host->priv;
+	int err = 0;
+	short key_index;
+	sector_t lba = 0;
+	unsigned int bypass = SDHCI_MSM_ICE_ENABLE_BYPASS;
+	struct request *req;
+
+	if (msm_host->ice.state != SDHCI_MSM_ICE_STATE_ACTIVE) {
+		pr_err("%s: ice is in invalid state %d\n",
+			mmc_hostname(host->mmc), msm_host->ice.state);
+		return -EINVAL;
+	}
+
+	WARN_ON(!mrq);
+	if (!mrq)
+		return -EINVAL;
+	req = mrq->req;
+	if (req) {
+		lba = req->__sector;
+		err = sdhci_msm_ice_get_cfg(msm_host, req, &bypass, &key_index);
+		if (err)
+			return err;
+		pr_debug("%s: %s: slot %d bypass %d key_index %d\n",
+				mmc_hostname(host->mmc),
+				(rq_data_dir(req) == WRITE) ? "WRITE" : "READ",
+				slot, bypass, key_index);
+	}
+
+	sdhci_msm_ice_update_cfg(host, lba, slot, bypass, key_index);
+	return 0;
+}
+
 int sdhci_msm_ice_reset(struct sdhci_host *host)
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
diff --git a/drivers/mmc/host/sdhci-msm-ice.h b/drivers/mmc/host/sdhci-msm-ice.h
index 23922cf..4c813a0 100644
--- a/drivers/mmc/host/sdhci-msm-ice.h
+++ b/drivers/mmc/host/sdhci-msm-ice.h
@@ -99,6 +99,8 @@
 void sdhci_msm_ice_cfg_reset(struct sdhci_host *host, u32 slot);
 int sdhci_msm_ice_cfg(struct sdhci_host *host, struct mmc_request *mrq,
 			u32 slot);
+int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+			struct mmc_request *mrq, u32 slot, u64 *ice_ctx);
 int sdhci_msm_ice_reset(struct sdhci_host *host);
 int sdhci_msm_ice_resume(struct sdhci_host *host);
 int sdhci_msm_ice_suspend(struct sdhci_host *host);
@@ -130,6 +132,11 @@
 {
 	return 0;
 }
+static inline int sdhci_msm_ice_cmdq_cfg(struct sdhci_host *host,
+		struct mmc_request *mrq, u32 slot, u64 *ice_ctx)
+{
+	return 0;
+}
 inline int sdhci_msm_ice_reset(struct sdhci_host *host)
 {
 	return 0;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 1e25b31..f1364a1 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -146,6 +146,7 @@
 #define CORE_START_CDC_TRAFFIC		(1 << 6)
 
 #define CORE_PWRSAVE_DLL	(1 << 3)
+#define CORE_FIFO_ALT_EN	(1 << 10)
 #define CORE_CMDEN_HS400_INPUT_MASK_CNT (1 << 13)
 
 #define CORE_DDR_CAL_EN		(1 << 0)
@@ -1143,6 +1144,7 @@
 	bool drv_type_changed = false;
 	struct mmc_card *card = host->mmc->card;
 	int sts_retry;
+	u8 last_good_phase = 0;
 
 	/*
 	 * Tuning is required for SDR104, HS200 and HS400 cards and
@@ -1228,6 +1230,22 @@
 		mmc_wait_for_req(mmc, &mrq);
 
 		if (card && (cmd.error || data.error)) {
+			/*
+			 * Set the dll to last known good phase while sending
+			 * status command to ensure that status command won't
+			 * fail due to bad phase.
+			 */
+			if (tuned_phase_cnt)
+				last_good_phase =
+					tuned_phases[tuned_phase_cnt-1];
+			else if (msm_host->saved_tuning_phase !=
+					INVALID_TUNING_PHASE)
+				last_good_phase = msm_host->saved_tuning_phase;
+
+			rc = msm_config_cm_dll_phase(host, last_good_phase);
+			if (rc)
+				goto kfree;
+
 			sts_cmd.opcode = MMC_SEND_STATUS;
 			sts_cmd.arg = card->rca << 16;
 			sts_cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -4097,6 +4115,8 @@
 
 static struct sdhci_ops sdhci_msm_ops = {
 	.crypto_engine_cfg = sdhci_msm_ice_cfg,
+	.crypto_engine_cmdq_cfg = sdhci_msm_ice_cmdq_cfg,
+	.crypto_cfg_reset = sdhci_msm_ice_cfg_reset,
 	.crypto_engine_reset = sdhci_msm_ice_reset,
 	.set_uhs_signaling = sdhci_msm_set_uhs_signaling,
 	.check_power_status = sdhci_msm_check_power_status,
@@ -4196,7 +4216,7 @@
 	 * starts coming.
 	 */
 	if ((major == 1) && ((minor == 0x42) || (minor == 0x46) ||
-				(minor == 0x49)))
+				(minor == 0x49) || (minor >= 0x6b)))
 		msm_host->use_14lpp_dll = true;
 
 	/* Fake 3.0V support for SDIO devices which requires such voltage */
@@ -4221,8 +4241,10 @@
 	/* keep track of the value in SDHCI_CAPABILITIES */
 	msm_host->caps_0 = caps;
 
-	if ((major == 1) && (minor >= 0x6b))
+	if ((major == 1) && (minor >= 0x6b)) {
 		msm_host->ice_hci_support = true;
+		host->cdr_support = true;
+	}
 }
 
 #ifdef CONFIG_MMC_CQ_HCI
@@ -4518,6 +4540,14 @@
 	writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
 	host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC);
 
+	/*
+	 * Ensure SDHCI FIFO is enabled by disabling alternative FIFO
+	 */
+	writel_relaxed((readl_relaxed(host->ioaddr +
+			msm_host_offset->CORE_VENDOR_SPEC3) &
+			~CORE_FIFO_ALT_EN), host->ioaddr +
+			msm_host_offset->CORE_VENDOR_SPEC3);
+
 	if (!msm_host->mci_removed) {
 		/* Set HC_MODE_EN bit in HC_MODE register */
 		writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
@@ -5050,7 +5080,7 @@
 }
 
 static const struct dev_pm_ops sdhci_msm_pmops = {
-	SET_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
+	SET_LATE_SYSTEM_SLEEP_PM_OPS(sdhci_msm_suspend, sdhci_msm_resume)
 	SET_RUNTIME_PM_OPS(sdhci_msm_runtime_suspend, sdhci_msm_runtime_resume,
 			   NULL)
 	.suspend_noirq = sdhci_msm_suspend_noirq,
@@ -5074,6 +5104,7 @@
 	.driver		= {
 		.name	= "sdhci_msm",
 		.owner	= THIS_MODULE,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
 		.of_match_table = sdhci_msm_dt_match,
 		.pm	= SDHCI_MSM_PMOPS,
 	},
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 68e49bb..bf32a87 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3088,12 +3088,6 @@
 		 * above in sdhci_cmd_irq().
 		 */
 		if (data_cmd && (data_cmd->flags & MMC_RSP_BUSY)) {
-			if (intmask & SDHCI_INT_DATA_TIMEOUT) {
-				host->data_cmd = NULL;
-				data_cmd->error = -ETIMEDOUT;
-				sdhci_finish_mrq(host, data_cmd->mrq);
-				return;
-			}
 			if (intmask & SDHCI_INT_DATA_END) {
 				host->data_cmd = NULL;
 				/*
@@ -3108,8 +3102,21 @@
 				return;
 			}
 			if (host->quirks2 &
-				SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD)
+				SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD) {
+				pr_err_ratelimited("%s: %s: ignoring interrupt: 0x%08x due to DATATOUT_FOR_R1B quirk\n",
+						mmc_hostname(host->mmc),
+						__func__, intmask);
+				MMC_TRACE(host->mmc,
+					"%s: Quirk ignoring intr: 0x%08x\n",
+						__func__, intmask);
 				return;
+			}
+			if (intmask & SDHCI_INT_DATA_TIMEOUT) {
+				host->data_cmd = NULL;
+				data_cmd->error = -ETIMEDOUT;
+				sdhci_finish_mrq(host, data_cmd->mrq);
+				return;
+			}
 		}
 
 		/*
@@ -3689,7 +3696,7 @@
 			ctrl |= SDHCI_CTRL_ADMA32;
 		sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 	}
-	if (host->ops->toggle_cdr)
+	if (host->ops->toggle_cdr && !host->cdr_support)
 		host->ops->toggle_cdr(host, false);
 }
 
@@ -3771,11 +3778,31 @@
 		struct mmc_request *mrq, u32 slot)
 {
 	struct sdhci_host *host = mmc_priv(mmc);
+	int err = 0;
 
 	if (!host->is_crypto_en)
 		return 0;
 
-	return sdhci_crypto_cfg(host, mrq, slot);
+	if (host->crypto_reset_reqd && host->ops->crypto_engine_reset) {
+		err = host->ops->crypto_engine_reset(host);
+		if (err) {
+			pr_err("%s: crypto reset failed\n",
+					mmc_hostname(host->mmc));
+			goto out;
+		}
+		host->crypto_reset_reqd = false;
+	}
+
+	if (host->ops->crypto_engine_cmdq_cfg) {
+		err = host->ops->crypto_engine_cmdq_cfg(host, mrq, slot, NULL);
+		if (err) {
+			pr_err("%s: failed to configure crypto\n",
+					mmc_hostname(host->mmc));
+			goto out;
+		}
+	}
+out:
+	return err;
 }
 
 static void sdhci_cmdq_crypto_cfg_reset(struct mmc_host *mmc, unsigned int slot)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 04e806c..a463e45 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -518,7 +518,7 @@
  * Some controllers may use PIO mode to workaround HW issues in ADMA for
  * eMMC tuning commands.
  */
-#define SDHCI_QUIRK2_USE_PIO_FOR_EMMC_TUNING (1 << 23)
+#define SDHCI_QUIRK2_USE_PIO_FOR_EMMC_TUNING (1 << 29)
 
 
 	int irq;		/* Device IRQ */
@@ -569,6 +569,7 @@
 	bool bus_on;		/* Bus power prevents runtime suspend */
 	bool preset_enabled;	/* Preset is enabled */
 	bool pending_reset;	/* Cmd/data reset is pending */
+	bool cdr_support;
 
 	struct mmc_request *mrqs_done[SDHCI_MAX_MRQS];	/* Requests done */
 	struct mmc_request *mrq;	/* Current request */
@@ -670,6 +671,8 @@
 	int	(*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
 	int	(*crypto_engine_cfg)(struct sdhci_host *host,
 				struct mmc_request *mrq, u32 slot);
+	int	(*crypto_engine_cmdq_cfg)(struct sdhci_host *host,
+			struct mmc_request *mrq, u32 slot, u64 *ice_ctx);
 	int	(*crypto_engine_reset)(struct sdhci_host *host);
 	void	(*crypto_cfg_reset)(struct sdhci_host *host, unsigned int slot);
 	void	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index 0e66348..2ab6c59 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -60,3 +60,15 @@
 	---help---
 	  Say Y here to enable wil6210 driver support for MSM
 	  platform specific features
+
+config WIL6210_DEBUGFS
+	bool "wil6210 debugfs support"
+	depends on WIL6210
+	depends on DEBUG_FS
+	default y
+	---help---
+	  Say Y here to enable wil6210 debugfs support, using the
+	  kernel debugfs infrastructure. Select this
+	  option if you are interested in debugging the driver.
+
+	  If unsure, say Y to make it easier to debug problems.
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 4874c5b..94df1de 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -4,7 +4,7 @@
 wil6210-y += netdev.o
 wil6210-y += cfg80211.o
 wil6210-y += pcie_bus.o
-wil6210-y += debugfs.o
+wil6210-$(CONFIG_WIL6210_DEBUGFS) += debugfs.o
 wil6210-y += sysfs.o
 wil6210-y += wmi.o
 wil6210-y += interrupt.o
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 7a0b226..9552d2a 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -454,6 +454,34 @@
 	return rc;
 }
 
+static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
+					 struct wireless_dev *wdev)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+	wil_dbg_misc(wil, "start_p2p_device: entered\n");
+	wil->p2p.p2p_dev_started = 1;
+	return 0;
+}
+
+static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
+					 struct wireless_dev *wdev)
+{
+	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+	struct wil_p2p_info *p2p = &wil->p2p;
+
+	if (!p2p->p2p_dev_started)
+		return;
+
+	wil_dbg_misc(wil, "stop_p2p_device: entered\n");
+	mutex_lock(&wil->mutex);
+	mutex_lock(&wil->p2p_wdev_mutex);
+	wil_p2p_stop_radio_operations(wil);
+	p2p->p2p_dev_started = 0;
+	mutex_unlock(&wil->p2p_wdev_mutex);
+	mutex_unlock(&wil->mutex);
+}
+
 static struct wireless_dev *
 wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
 		       unsigned char name_assign_type,
@@ -502,6 +530,7 @@
 		return -EINVAL;
 	}
 
+	wil_cfg80211_stop_p2p_device(wiphy, wdev);
 	wil_p2p_wdev_free(wil);
 
 	return 0;
@@ -886,7 +915,7 @@
 		wil->bss = bss;
 		/* Connect can take lots of time */
 		mod_timer(&wil->connect_timer,
-			  jiffies + msecs_to_jiffies(2000));
+			  jiffies + msecs_to_jiffies(5000));
 	} else {
 		clear_bit(wil_status_fwconnecting, wil->status);
 	}
@@ -1736,34 +1765,6 @@
 	return 0;
 }
 
-static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
-					 struct wireless_dev *wdev)
-{
-	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-
-	wil_dbg_misc(wil, "start_p2p_device: entered\n");
-	wil->p2p.p2p_dev_started = 1;
-	return 0;
-}
-
-static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
-					 struct wireless_dev *wdev)
-{
-	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
-	struct wil_p2p_info *p2p = &wil->p2p;
-
-	if (!p2p->p2p_dev_started)
-		return;
-
-	wil_dbg_misc(wil, "stop_p2p_device: entered\n");
-	mutex_lock(&wil->mutex);
-	mutex_lock(&wil->p2p_wdev_mutex);
-	wil_p2p_stop_radio_operations(wil);
-	p2p->p2p_dev_started = 0;
-	mutex_unlock(&wil->p2p_wdev_mutex);
-	mutex_unlock(&wil->mutex);
-}
-
 static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy,
 				       struct net_device *dev,
 				       bool enabled, int timeout)
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index cad8a95c4..59def4f 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -244,7 +244,7 @@
 	wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr);
 
 	if (unlikely(!isr)) {
-		wil_err(wil, "spurious IRQ: RX\n");
+		wil_err_ratelimited(wil, "spurious IRQ: RX\n");
 		return IRQ_NONE;
 	}
 
@@ -269,11 +269,12 @@
 				need_unmask = false;
 				napi_schedule(&wil->napi_rx);
 			} else {
-				wil_err(wil,
+				wil_err_ratelimited(
+					wil,
 					"Got Rx interrupt while stopping interface\n");
 			}
 		} else {
-			wil_err(wil, "Got Rx interrupt while in reset\n");
+			wil_err_ratelimited(wil, "Got Rx interrupt while in reset\n");
 		}
 	}
 
@@ -302,7 +303,7 @@
 	wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr);
 
 	if (unlikely(!isr)) {
-		wil_err(wil, "spurious IRQ: TX\n");
+		wil_err_ratelimited(wil, "spurious IRQ: TX\n");
 		return IRQ_NONE;
 	}
 
@@ -318,12 +319,13 @@
 			need_unmask = false;
 			napi_schedule(&wil->napi_tx);
 		} else {
-			wil_err(wil, "Got Tx interrupt while in reset\n");
+			wil_err_ratelimited(wil, "Got Tx interrupt while in reset\n");
 		}
 	}
 
 	if (unlikely(isr))
-		wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
+		wil_err_ratelimited(wil, "un-handled TX ISR bits 0x%08x\n",
+				    isr);
 
 	/* Tx IRQ will be enabled when NAPI processing finished */
 
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index d90fe1c..b91298d 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -934,6 +934,29 @@
 	return rc;
 }
 
+static void wil_pre_fw_config(struct wil6210_priv *wil)
+{
+	/* Mark FW as loaded from host */
+	wil_s(wil, RGF_USER_USAGE_6, 1);
+
+	/* clear any interrupts which on-card-firmware
+	 * may have set
+	 */
+	wil6210_clear_irq(wil);
+	/* CAF_ICR - clear and mask */
+	/* it is W1C, clear by writing back same value */
+	wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
+	wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
+	/* clear PAL_UNIT_ICR (potential D0->D3 leftover) */
+	wil_s(wil, RGF_PAL_UNIT_ICR + offsetof(struct RGF_ICR, ICR), 0);
+
+	if (wil->fw_calib_result > 0) {
+		__le32 val = cpu_to_le32(wil->fw_calib_result |
+						(CALIB_RESULT_SIGNATURE << 8));
+		wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val);
+	}
+}
+
 /*
  * We reset all the structures, and we reset the UMAC.
  * After calling this routine, you're expected to reload
@@ -1031,24 +1054,7 @@
 		if (rc)
 			return rc;
 
-		/* Mark FW as loaded from host */
-		wil_s(wil, RGF_USER_USAGE_6, 1);
-
-		/* clear any interrupts which on-card-firmware
-		 * may have set
-		 */
-		wil6210_clear_irq(wil);
-		/* CAF_ICR - clear and mask */
-		/* it is W1C, clear by writing back same value */
-		wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
-		wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
-
-		if (wil->fw_calib_result > 0) {
-			__le32 val = cpu_to_le32(wil->fw_calib_result |
-						 (CALIB_RESULT_SIGNATURE << 8));
-			wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val);
-		}
-
+		wil_pre_fw_config(wil);
 		wil_release_cpu(wil);
 	}
 
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index b4ca4e3..d5b8ea6 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -272,6 +272,7 @@
 	#define BIT_DMA_PSEUDO_CAUSE_MISC	BIT(2)
 
 #define RGF_HP_CTRL			(0x88265c)
+#define RGF_PAL_UNIT_ICR		(0x88266c) /* struct RGF_ICR */
 #define RGF_PCIE_LOS_COUNTER_CTL	(0x882dc4)
 
 /* MAC timer, usec, for packet lifetime */
@@ -951,8 +952,13 @@
 			 struct cfg80211_mgmt_tx_params *params,
 			 u64 *cookie);
 
+#if defined(CONFIG_WIL6210_DEBUGFS)
 int wil6210_debugfs_init(struct wil6210_priv *wil);
 void wil6210_debugfs_remove(struct wil6210_priv *wil);
+#else
+static inline int wil6210_debugfs_init(struct wil6210_priv *wil) { return 0; }
+static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {}
+#endif
 int wil6210_sysfs_init(struct wil6210_priv *wil);
 void wil6210_sysfs_remove(struct wil6210_priv *wil);
 int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 1b426d7..5263ee7 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -36,6 +36,11 @@
 #define WMI_PROX_RANGE_NUM		(3)
 #define WMI_MAX_LOSS_DMG_BEACONS	(20)
 #define MAX_NUM_OF_SECTORS		(128)
+#define WMI_SCHED_MAX_ALLOCS_PER_CMD	(4)
+#define WMI_RF_DTYPE_LENGTH		(3)
+#define WMI_RF_ETYPE_LENGTH		(3)
+#define WMI_RF_RX2TX_LENGTH		(3)
+#define WMI_RF_ETYPE_VAL_PER_RANGE	(5)
 
 /* Mailbox interface
  * used for commands and events
@@ -52,15 +57,20 @@
  * the host
  */
 enum wmi_fw_capability {
-	WMI_FW_CAPABILITY_FTM			= 0,
-	WMI_FW_CAPABILITY_PS_CONFIG		= 1,
-	WMI_FW_CAPABILITY_RF_SECTORS		= 2,
-	WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT	= 3,
-	WMI_FW_CAPABILITY_DISABLE_AP_SME	= 4,
-	WMI_FW_CAPABILITY_WMI_ONLY		= 5,
-	WMI_FW_CAPABILITY_THERMAL_THROTTLING	= 7,
-	WMI_FW_CAPABILITY_D3_SUSPEND		= 8,
-	WMI_FW_CAPABILITY_RSSI_REPORTING	= 12,
+	WMI_FW_CAPABILITY_FTM				= 0,
+	WMI_FW_CAPABILITY_PS_CONFIG			= 1,
+	WMI_FW_CAPABILITY_RF_SECTORS			= 2,
+	WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT		= 3,
+	WMI_FW_CAPABILITY_DISABLE_AP_SME		= 4,
+	WMI_FW_CAPABILITY_WMI_ONLY			= 5,
+	WMI_FW_CAPABILITY_THERMAL_THROTTLING		= 7,
+	WMI_FW_CAPABILITY_D3_SUSPEND			= 8,
+	WMI_FW_CAPABILITY_LONG_RANGE			= 9,
+	WMI_FW_CAPABILITY_FIXED_SCHEDULING		= 10,
+	WMI_FW_CAPABILITY_MULTI_DIRECTED_OMNIS		= 11,
+	WMI_FW_CAPABILITY_RSSI_REPORTING		= 12,
+	WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE		= 13,
+	WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP	= 14,
 	WMI_FW_CAPABILITY_MAX,
 };
 
@@ -80,6 +90,7 @@
 	WMI_START_SCAN_CMDID				= 0x07,
 	WMI_SET_BSS_FILTER_CMDID			= 0x09,
 	WMI_SET_PROBED_SSID_CMDID			= 0x0A,
+	/* deprecated */
 	WMI_SET_LISTEN_INT_CMDID			= 0x0B,
 	WMI_BCON_CTRL_CMDID				= 0x0F,
 	WMI_ADD_CIPHER_KEY_CMDID			= 0x16,
@@ -94,26 +105,28 @@
 	WMI_ECHO_CMDID					= 0x803,
 	WMI_DEEP_ECHO_CMDID				= 0x804,
 	WMI_CONFIG_MAC_CMDID				= 0x805,
+	/* deprecated */
 	WMI_CONFIG_PHY_DEBUG_CMDID			= 0x806,
 	WMI_ADD_DEBUG_TX_PCKT_CMDID			= 0x808,
 	WMI_PHY_GET_STATISTICS_CMDID			= 0x809,
+	/* deprecated */
 	WMI_FS_TUNE_CMDID				= 0x80A,
+	/* deprecated */
 	WMI_CORR_MEASURE_CMDID				= 0x80B,
 	WMI_READ_RSSI_CMDID				= 0x80C,
 	WMI_TEMP_SENSE_CMDID				= 0x80E,
 	WMI_DC_CALIB_CMDID				= 0x80F,
+	/* deprecated */
 	WMI_SEND_TONE_CMDID				= 0x810,
+	/* deprecated */
 	WMI_IQ_TX_CALIB_CMDID				= 0x811,
+	/* deprecated */
 	WMI_IQ_RX_CALIB_CMDID				= 0x812,
-	WMI_SET_UCODE_IDLE_CMDID			= 0x813,
 	WMI_SET_WORK_MODE_CMDID				= 0x815,
 	WMI_LO_LEAKAGE_CALIB_CMDID			= 0x816,
-	WMI_MARLON_R_READ_CMDID				= 0x818,
-	WMI_MARLON_R_WRITE_CMDID			= 0x819,
-	WMI_MARLON_R_TXRX_SEL_CMDID			= 0x81A,
-	MAC_IO_STATIC_PARAMS_CMDID			= 0x81B,
-	MAC_IO_DYNAMIC_PARAMS_CMDID			= 0x81C,
+	WMI_LO_POWER_CALIB_FROM_OTP_CMDID		= 0x817,
 	WMI_SILENT_RSSI_CALIB_CMDID			= 0x81D,
+	/* deprecated */
 	WMI_RF_RX_TEST_CMDID				= 0x81E,
 	WMI_CFG_RX_CHAIN_CMDID				= 0x820,
 	WMI_VRING_CFG_CMDID				= 0x821,
@@ -127,11 +140,6 @@
 	WMI_SET_PCP_CHANNEL_CMDID			= 0x829,
 	WMI_GET_PCP_CHANNEL_CMDID			= 0x82A,
 	WMI_SW_TX_REQ_CMDID				= 0x82B,
-	WMI_READ_MAC_RXQ_CMDID				= 0x830,
-	WMI_READ_MAC_TXQ_CMDID				= 0x831,
-	WMI_WRITE_MAC_RXQ_CMDID				= 0x832,
-	WMI_WRITE_MAC_TXQ_CMDID				= 0x833,
-	WMI_WRITE_MAC_XQ_FIELD_CMDID			= 0x834,
 	WMI_MLME_PUSH_CMDID				= 0x835,
 	WMI_BEAMFORMING_MGMT_CMDID			= 0x836,
 	WMI_BF_TXSS_MGMT_CMDID				= 0x837,
@@ -145,9 +153,13 @@
 	WMI_MAINTAIN_RESUME_CMDID			= 0x851,
 	WMI_RS_MGMT_CMDID				= 0x852,
 	WMI_RF_MGMT_CMDID				= 0x853,
-	WMI_OTP_READ_CMDID				= 0x856,
-	WMI_OTP_WRITE_CMDID				= 0x857,
+	WMI_RF_XPM_READ_CMDID				= 0x856,
+	WMI_RF_XPM_WRITE_CMDID				= 0x857,
 	WMI_LED_CFG_CMDID				= 0x858,
+	WMI_SET_CONNECT_SNR_THR_CMDID			= 0x85B,
+	WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID		= 0x85C,
+	WMI_RF_PWR_ON_DELAY_CMDID			= 0x85D,
+	WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID		= 0x85E,
 	/* Performance monitoring commands */
 	WMI_BF_CTRL_CMDID				= 0x862,
 	WMI_NOTIFY_REQ_CMDID				= 0x863,
@@ -155,7 +167,6 @@
 	WMI_GET_RF_STATUS_CMDID				= 0x866,
 	WMI_GET_BASEBAND_TYPE_CMDID			= 0x867,
 	WMI_UNIT_TEST_CMDID				= 0x900,
-	WMI_HICCUP_CMDID				= 0x901,
 	WMI_FLASH_READ_CMDID				= 0x902,
 	WMI_FLASH_WRITE_CMDID				= 0x903,
 	/* Power management */
@@ -175,16 +186,6 @@
 	WMI_GET_PCP_FACTOR_CMDID			= 0x91B,
 	/* Power Save Configuration Commands */
 	WMI_PS_DEV_PROFILE_CFG_CMDID			= 0x91C,
-	/* Not supported yet */
-	WMI_PS_DEV_CFG_CMDID				= 0x91D,
-	/* Not supported yet */
-	WMI_PS_DEV_CFG_READ_CMDID			= 0x91E,
-	/* Per MAC Power Save Configuration commands
-	 * Not supported yet
-	 */
-	WMI_PS_MID_CFG_CMDID				= 0x91F,
-	/* Not supported yet */
-	WMI_PS_MID_CFG_READ_CMDID			= 0x920,
 	WMI_RS_CFG_CMDID				= 0x921,
 	WMI_GET_DETAILED_RS_RES_CMDID			= 0x922,
 	WMI_AOA_MEAS_CMDID				= 0x923,
@@ -195,13 +196,16 @@
 	WMI_DEL_STA_CMDID				= 0x936,
 	WMI_SET_THERMAL_THROTTLING_CFG_CMDID		= 0x940,
 	WMI_GET_THERMAL_THROTTLING_CFG_CMDID		= 0x941,
+	/* Read Power Save profile type */
+	WMI_PS_DEV_PROFILE_CFG_READ_CMDID		= 0x942,
 	WMI_TOF_SESSION_START_CMDID			= 0x991,
 	WMI_TOF_GET_CAPABILITIES_CMDID			= 0x992,
 	WMI_TOF_SET_LCR_CMDID				= 0x993,
 	WMI_TOF_SET_LCI_CMDID				= 0x994,
-	WMI_TOF_CHANNEL_INFO_CMDID			= 0x995,
+	WMI_TOF_CFG_RESPONDER_CMDID			= 0x996,
 	WMI_TOF_SET_TX_RX_OFFSET_CMDID			= 0x997,
 	WMI_TOF_GET_TX_RX_OFFSET_CMDID			= 0x998,
+	WMI_TOF_CHANNEL_INFO_CMDID			= 0x999,
 	WMI_GET_RF_SECTOR_PARAMS_CMDID			= 0x9A0,
 	WMI_SET_RF_SECTOR_PARAMS_CMDID			= 0x9A1,
 	WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID		= 0x9A2,
@@ -210,12 +214,20 @@
 	WMI_PRIO_TX_SECTORS_ORDER_CMDID			= 0x9A5,
 	WMI_PRIO_TX_SECTORS_NUMBER_CMDID		= 0x9A6,
 	WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID	= 0x9A7,
+	WMI_SCHEDULING_SCHEME_CMDID			= 0xA01,
+	WMI_FIXED_SCHEDULING_CONFIG_CMDID		= 0xA02,
+	WMI_ENABLE_FIXED_SCHEDULING_CMDID		= 0xA03,
+	WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID	= 0xA04,
+	WMI_SET_LONG_RANGE_CONFIG_CMDID			= 0xA05,
 	WMI_SET_MAC_ADDRESS_CMDID			= 0xF003,
 	WMI_ABORT_SCAN_CMDID				= 0xF007,
 	WMI_SET_PROMISCUOUS_MODE_CMDID			= 0xF041,
+	/* deprecated */
 	WMI_GET_PMK_CMDID				= 0xF048,
 	WMI_SET_PASSPHRASE_CMDID			= 0xF049,
+	/* deprecated */
 	WMI_SEND_ASSOC_RES_CMDID			= 0xF04A,
+	/* deprecated */
 	WMI_SET_ASSOC_REQ_RELAY_CMDID			= 0xF04B,
 	WMI_MAC_ADDR_REQ_CMDID				= 0xF04D,
 	WMI_FW_VER_CMDID				= 0xF04E,
@@ -441,11 +453,6 @@
 	__le32 rf_mgmt_type;
 } __packed;
 
-/* WMI_RF_RX_TEST_CMDID */
-struct wmi_rf_rx_test_cmd {
-	__le32 sector;
-} __packed;
-
 /* WMI_CORR_MEASURE_CMDID */
 struct wmi_corr_measure_cmd {
 	__le32 freq_mhz;
@@ -658,6 +665,20 @@
 	struct wmi_bcast_vring_cfg vring_cfg;
 } __packed;
 
+/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */
+struct wmi_lo_power_calib_from_otp_cmd {
+	/* index to read from OTP. zero based */
+	u8 index;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */
+struct wmi_lo_power_calib_from_otp_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
 /* WMI_VRING_BA_EN_CMDID */
 struct wmi_vring_ba_en_cmd {
 	u8 ringid;
@@ -693,6 +714,24 @@
 	WMI_SNIFFER_ON	= 0x01,
 };
 
+/* WMI_SILENT_RSSI_TABLE */
+enum wmi_silent_rssi_table {
+	RF_TEMPERATURE_CALIB_DEFAULT_DB		= 0x00,
+	RF_TEMPERATURE_CALIB_HIGH_POWER_DB	= 0x01,
+};
+
+/* WMI_SILENT_RSSI_STATUS */
+enum wmi_silent_rssi_status {
+	SILENT_RSSI_SUCCESS	= 0x00,
+	SILENT_RSSI_FAILURE	= 0x01,
+};
+
+/* WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID */
+struct wmi_set_active_silent_rssi_table_cmd {
+	/* enum wmi_silent_rssi_table */
+	__le32 table;
+} __packed;
+
 enum wmi_sniffer_cfg_phy_info_mode {
 	WMI_SNIFFER_PHY_INFO_DISABLED	= 0x00,
 	WMI_SNIFFER_PHY_INFO_ENABLED	= 0x01,
@@ -836,18 +875,85 @@
 	__le32 value;
 } __packed;
 
-/* WMI_OTP_READ_CMDID */
-struct wmi_otp_read_cmd {
-	__le32 addr;
-	__le32 size;
-	__le32 values;
+/* WMI_RF_PWR_ON_DELAY_CMDID
+ * set FW time parameters used through RF resetting
+ *  RF reset consists of bringing its power down for a period of time, then
+ * bringing the power up
+ * Returned event: WMI_RF_PWR_ON_DELAY_RSP_EVENTID
+ */
+struct wmi_rf_pwr_on_delay_cmd {
+	/* time in usec the FW waits after bringing the RF PWR down,
+	 * set 0 for default
+	 */
+	__le16 down_delay_usec;
+	/* time in usec the FW waits after bringing the RF PWR up,
+	 * set 0 for default
+	 */
+	__le16 up_delay_usec;
 } __packed;
 
-/* WMI_OTP_WRITE_CMDID */
-struct wmi_otp_write_cmd {
-	__le32 addr;
-	__le32 size;
-	__le32 values;
+/* \WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID
+ * This API controls the Tx and Rx gain over temperature.
+ * It controls the Tx D-type, Rx D-type and Rx E-type amplifiers.
+ * It also controls the Tx gain index, by controlling the Rx to Tx gain index
+ * offset.
+ * The control is divided by 3 temperature values to 4 temperature ranges.
+ * Each parameter uses its own temperature values.
+ * Returned event: WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID
+ */
+struct wmi_set_high_power_table_params_cmd {
+	/* Temperature range for Tx D-type parameters */
+	u8 tx_dtype_temp[WMI_RF_DTYPE_LENGTH];
+	u8 reserved0;
+	/* Tx D-type values to be used for each temperature range */
+	__le32 tx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1];
+	/* Temperature range for Rx D-type parameters */
+	u8 rx_dtype_temp[WMI_RF_DTYPE_LENGTH];
+	u8 reserved1;
+	/* Rx D-type values to be used for each temperature range */
+	__le32 rx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1];
+	/* Temperature range for Rx E-type parameters */
+	u8 rx_etype_temp[WMI_RF_ETYPE_LENGTH];
+	u8 reserved2;
+	/* Rx E-type values to be used for each temperature range.
+	 * The last 4 values of any range are the first 4 values of the next
+	 * range and so on
+	 */
+	__le32 rx_etype_conf[WMI_RF_ETYPE_VAL_PER_RANGE + WMI_RF_ETYPE_LENGTH];
+	/* Temperature range for rx_2_tx_offs parameters */
+	u8 rx_2_tx_temp[WMI_RF_RX2TX_LENGTH];
+	u8 reserved3;
+	/* Rx to Tx gain index offset */
+	s8 rx_2_tx_offs[WMI_RF_RX2TX_LENGTH + 1];
+} __packed;
+
+/* CMD: WMI_RF_XPM_READ_CMDID */
+struct wmi_rf_xpm_read_cmd {
+	u8 rf_id;
+	u8 reserved[3];
+	/* XPM bit start address in range [0,8191]bits - rounded by FW to
+	 * multiple of 8bits
+	 */
+	__le32 xpm_bit_address;
+	__le32 num_bytes;
+} __packed;
+
+/* CMD: WMI_RF_XPM_WRITE_CMDID */
+struct wmi_rf_xpm_write_cmd {
+	u8 rf_id;
+	u8 reserved0[3];
+	/* XPM bit start address in range [0,8191]bits - rounded by FW to
+	 * multiple of 8bits
+	 */
+	__le32 xpm_bit_address;
+	__le32 num_bytes;
+	/* boolean flag indicating whether FW should verify the write
+	 * operation
+	 */
+	u8 verify;
+	u8 reserved1[3];
+	/* actual size=num_bytes */
+	u8 data_bytes[0];
 } __packed;
 
 /* WMI_TEMP_SENSE_CMDID
@@ -990,19 +1096,26 @@
 	 */
 	__le16 burst_period;
 	u8 dst_mac[WMI_MAC_LEN];
-	__le16 reserved;
+	u8 reserved;
+	u8 num_burst_per_aoa_meas;
 } __packed;
 
 /* WMI_TOF_SESSION_START_CMDID */
 struct wmi_tof_session_start_cmd {
 	__le32 session_id;
-	u8 num_of_aoa_measures;
+	u8 reserved1;
 	u8 aoa_type;
 	__le16 num_of_dest;
 	u8 reserved[4];
 	struct wmi_ftm_dest_info ftm_dest_info[0];
 } __packed;
 
+/* WMI_TOF_CFG_RESPONDER_CMDID */
+struct wmi_tof_cfg_responder_cmd {
+	u8 enable;
+	u8 reserved[3];
+} __packed;
+
 enum wmi_tof_channel_info_report_type {
 	WMI_TOF_CHANNEL_INFO_TYPE_CIR			= 0x1,
 	WMI_TOF_CHANNEL_INFO_TYPE_RSSI			= 0x2,
@@ -1023,7 +1136,99 @@
 	__le32 tx_offset;
 	/* RX delay offset */
 	__le32 rx_offset;
-	__le32 reserved[2];
+	/* Mask to define which RFs to configure. 0 means all RFs */
+	__le32 rf_mask;
+	/* Offset to strongest tap of CIR */
+	__le32 precursor;
+} __packed;
+
+/* WMI_TOF_GET_TX_RX_OFFSET_CMDID */
+struct wmi_tof_get_tx_rx_offset_cmd {
+	/* rf index to read offsets from */
+	u8 rf_index;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */
+struct wmi_map_mcs_to_schd_params {
+	u8 mcs;
+	/* time in usec from start slot to start tx flow - default 15 */
+	u8 time_in_usec_before_initiate_tx;
+	/* RD enable - if yes consider RD according to STA mcs */
+	u8 rd_enabled;
+	u8 reserved;
+	/* time in usec from start slot to stop vring */
+	__le16 time_in_usec_to_stop_vring;
+	/* timeout to force flush from start of slot */
+	__le16 flush_to_in_usec;
+	/* per mcs the mac buffer limit size in bytes */
+	__le32 mac_buff_size_in_bytes;
+} __packed;
+
+/* WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID */
+struct wmi_fixed_scheduling_config_complete_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
+#define WMI_NUM_MCS	(13)
+
+/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */
+struct wmi_fixed_scheduling_config_cmd {
+	/* defaults in the SAS table */
+	struct wmi_map_mcs_to_schd_params mcs_to_schd_params_map[WMI_NUM_MCS];
+	/* default 150 uSec */
+	__le16 max_sta_rd_ppdu_duration_in_usec;
+	/* default 300 uSec */
+	__le16 max_sta_grant_ppdu_duration_in_usec;
+	/* default 1000 uSec */
+	__le16 assoc_slot_duration_in_usec;
+	/* default 360 uSec */
+	__le16 virtual_slot_duration_in_usec;
+	/* each this field value slots start with grant frame to the station
+	 * - default 2
+	 */
+	u8 number_of_ap_slots_for_initiate_grant;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_ENABLE_FIXED_SCHEDULING_CMDID */
+struct wmi_enable_fixed_scheduling_cmd {
+	__le32 reserved;
+} __packed;
+
+/* WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID */
+struct wmi_enable_fixed_scheduling_complete_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID */
+struct wmi_set_multi_directed_omnis_config_cmd {
+	/* number of directed omnis at destination AP */
+	u8 dest_ap_num_directed_omnis;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID */
+struct wmi_set_multi_directed_omnis_config_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_SET_LONG_RANGE_CONFIG_CMDID */
+struct wmi_set_long_range_config_cmd {
+	__le32 reserved;
+} __packed;
+
+/* WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID */
+struct wmi_set_long_range_config_complete_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
 } __packed;
 
 /* WMI Events
@@ -1039,19 +1244,22 @@
 	WMI_FW_READY_EVENTID				= 0x1801,
 	WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID		= 0x200,
 	WMI_ECHO_RSP_EVENTID				= 0x1803,
+	/* deprecated */
 	WMI_FS_TUNE_DONE_EVENTID			= 0x180A,
+	/* deprecated */
 	WMI_CORR_MEASURE_EVENTID			= 0x180B,
 	WMI_READ_RSSI_EVENTID				= 0x180C,
 	WMI_TEMP_SENSE_DONE_EVENTID			= 0x180E,
 	WMI_DC_CALIB_DONE_EVENTID			= 0x180F,
+	/* deprecated */
 	WMI_IQ_TX_CALIB_DONE_EVENTID			= 0x1811,
+	/* deprecated */
 	WMI_IQ_RX_CALIB_DONE_EVENTID			= 0x1812,
 	WMI_SET_WORK_MODE_DONE_EVENTID			= 0x1815,
 	WMI_LO_LEAKAGE_CALIB_DONE_EVENTID		= 0x1816,
-	WMI_MARLON_R_READ_DONE_EVENTID			= 0x1818,
-	WMI_MARLON_R_WRITE_DONE_EVENTID			= 0x1819,
-	WMI_MARLON_R_TXRX_SEL_DONE_EVENTID		= 0x181A,
+	WMI_LO_POWER_CALIB_FROM_OTP_EVENTID		= 0x1817,
 	WMI_SILENT_RSSI_CALIB_DONE_EVENTID		= 0x181D,
+	/* deprecated */
 	WMI_RF_RX_TEST_DONE_EVENTID			= 0x181E,
 	WMI_CFG_RX_CHAIN_DONE_EVENTID			= 0x1820,
 	WMI_VRING_CFG_DONE_EVENTID			= 0x1821,
@@ -1062,11 +1270,6 @@
 	WMI_GET_SSID_EVENTID				= 0x1828,
 	WMI_GET_PCP_CHANNEL_EVENTID			= 0x182A,
 	WMI_SW_TX_COMPLETE_EVENTID			= 0x182B,
-	WMI_READ_MAC_RXQ_EVENTID			= 0x1830,
-	WMI_READ_MAC_TXQ_EVENTID			= 0x1831,
-	WMI_WRITE_MAC_RXQ_EVENTID			= 0x1832,
-	WMI_WRITE_MAC_TXQ_EVENTID			= 0x1833,
-	WMI_WRITE_MAC_XQ_FIELD_EVENTID			= 0x1834,
 	WMI_BEAMFORMING_MGMT_DONE_EVENTID		= 0x1836,
 	WMI_BF_TXSS_MGMT_DONE_EVENTID			= 0x1837,
 	WMI_BF_RXSS_MGMT_DONE_EVENTID			= 0x1839,
@@ -1077,8 +1280,12 @@
 	WMI_TX_MGMT_PACKET_EVENTID			= 0x1841,
 	WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID	= 0x1842,
 	WMI_LINK_MAINTAIN_CFG_READ_DONE_EVENTID		= 0x1843,
-	WMI_OTP_READ_RESULT_EVENTID			= 0x1856,
+	WMI_RF_XPM_READ_RESULT_EVENTID			= 0x1856,
+	WMI_RF_XPM_WRITE_RESULT_EVENTID			= 0x1857,
 	WMI_LED_CFG_DONE_EVENTID			= 0x1858,
+	WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID		= 0x185C,
+	WMI_RF_PWR_ON_DELAY_RSP_EVENTID			= 0x185D,
+	WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID		= 0x185E,
 	/* Performance monitoring events */
 	WMI_DATA_PORT_OPEN_EVENTID			= 0x1860,
 	WMI_WBE_LINK_DOWN_EVENTID			= 0x1861,
@@ -1107,14 +1314,6 @@
 	WMI_PCP_FACTOR_EVENTID				= 0x191A,
 	/* Power Save Configuration Events */
 	WMI_PS_DEV_PROFILE_CFG_EVENTID			= 0x191C,
-	/* Not supported yet */
-	WMI_PS_DEV_CFG_EVENTID				= 0x191D,
-	/* Not supported yet */
-	WMI_PS_DEV_CFG_READ_EVENTID			= 0x191E,
-	/* Not supported yet */
-	WMI_PS_MID_CFG_EVENTID				= 0x191F,
-	/* Not supported yet */
-	WMI_PS_MID_CFG_READ_EVENTID			= 0x1920,
 	WMI_RS_CFG_DONE_EVENTID				= 0x1921,
 	WMI_GET_DETAILED_RS_RES_EVENTID			= 0x1922,
 	WMI_AOA_MEAS_EVENTID				= 0x1923,
@@ -1123,14 +1322,17 @@
 	WMI_GET_MGMT_RETRY_LIMIT_EVENTID		= 0x1931,
 	WMI_SET_THERMAL_THROTTLING_CFG_EVENTID		= 0x1940,
 	WMI_GET_THERMAL_THROTTLING_CFG_EVENTID		= 0x1941,
+	/* return the Power Save profile */
+	WMI_PS_DEV_PROFILE_CFG_READ_EVENTID		= 0x1942,
 	WMI_TOF_SESSION_END_EVENTID			= 0x1991,
 	WMI_TOF_GET_CAPABILITIES_EVENTID		= 0x1992,
 	WMI_TOF_SET_LCR_EVENTID				= 0x1993,
 	WMI_TOF_SET_LCI_EVENTID				= 0x1994,
 	WMI_TOF_FTM_PER_DEST_RES_EVENTID		= 0x1995,
-	WMI_TOF_CHANNEL_INFO_EVENTID			= 0x1996,
+	WMI_TOF_CFG_RESPONDER_EVENTID			= 0x1996,
 	WMI_TOF_SET_TX_RX_OFFSET_EVENTID		= 0x1997,
 	WMI_TOF_GET_TX_RX_OFFSET_EVENTID		= 0x1998,
+	WMI_TOF_CHANNEL_INFO_EVENTID			= 0x1999,
 	WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID		= 0x19A0,
 	WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID		= 0x19A1,
 	WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID	= 0x19A2,
@@ -1139,12 +1341,18 @@
 	WMI_PRIO_TX_SECTORS_ORDER_EVENTID		= 0x19A5,
 	WMI_PRIO_TX_SECTORS_NUMBER_EVENTID		= 0x19A6,
 	WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID	= 0x19A7,
+	WMI_SCHEDULING_SCHEME_EVENTID			= 0x1A01,
+	WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID	= 0x1A02,
+	WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID	= 0x1A03,
+	WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID	= 0x1A04,
+	WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID	= 0x1A05,
 	WMI_SET_CHANNEL_EVENTID				= 0x9000,
 	WMI_ASSOC_REQ_EVENTID				= 0x9001,
 	WMI_EAPOL_RX_EVENTID				= 0x9002,
 	WMI_MAC_ADDR_RESP_EVENTID			= 0x9003,
 	WMI_FW_VER_EVENTID				= 0x9004,
 	WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID		= 0x9005,
+	WMI_COMMAND_NOT_SUPPORTED_EVENTID		= 0xFFFF,
 };
 
 /* Events data structures */
@@ -1201,7 +1409,7 @@
 	__le32 bl_minor;
 	__le32 bl_subminor;
 	__le32 bl_build;
-	/* The number of entries in the FW capabilies array */
+	/* The number of entries in the FW capabilities array */
 	u8 fw_capabilities_len;
 	u8 reserved[3];
 	/* FW capabilities info
@@ -1246,7 +1454,9 @@
 	__le32 board_file_platform_type;
 	/* board file version */
 	__le32 board_file_version;
-	__le32 reserved[2];
+	/* enabled XIFs bit vector */
+	__le32 enabled_xif_vector;
+	__le32 reserved;
 } __packed;
 
 /* WMI_GET_BASEBAND_TYPE_EVENTID */
@@ -1300,6 +1510,7 @@
 	/* enum wmi_phy_capability */
 	u8 phy_capability;
 	u8 numof_additional_mids;
+	/* rfc read calibration result. 5..15 */
 	u8 rfc_read_calib_result;
 	u8 reserved[3];
 } __packed;
@@ -1580,7 +1791,7 @@
 	u8 reserved[3];
 } __packed;
 
-/* WMI_CORR_MEASURE_EVENTID */
+/* WMI_CORR_MEASURE_EVENTID - deprecated */
 struct wmi_corr_measure_event {
 	/* signed */
 	__le32 i;
@@ -1612,25 +1823,29 @@
 	__le16 stype;
 	__le16 status;
 	__le32 len;
-	/* Not resolved when == 0xFFFFFFFF  ==> Broadcast to all MIDS */
+	/* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */
 	u8 qid;
-	/* Not resolved when == 0xFFFFFFFF  ==> Broadcast to all MIDS */
+	/* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */
 	u8 mid;
 	u8 cid;
 	/* From Radio MNGR */
 	u8 channel;
 } __packed;
 
-/* wmi_otp_read_write_cmd */
-struct wmi_otp_read_write_cmd {
-	__le32 addr;
-	__le32 size;
-	u8 values[0];
+/* EVENT: WMI_RF_XPM_READ_RESULT_EVENTID */
+struct wmi_rf_xpm_read_result_event {
+	/* enum wmi_fw_status_e - success=0 or fail=1 */
+	u8 status;
+	u8 reserved[3];
+	/* requested num_bytes of data */
+	u8 data_bytes[0];
 } __packed;
 
-/* WMI_OTP_READ_RESULT_EVENTID */
-struct wmi_otp_read_result_event {
-	u8 payload[0];
+/* EVENT: WMI_RF_XPM_WRITE_RESULT_EVENTID */
+struct wmi_rf_xpm_write_result_event {
+	/* enum wmi_fw_status_e - success=0 or fail=1 */
+	u8 status;
+	u8 reserved[3];
 } __packed;
 
 /* WMI_TX_MGMT_PACKET_EVENTID */
@@ -1649,6 +1864,20 @@
 	__le32 echoed_value;
 } __packed;
 
+/* WMI_RF_PWR_ON_DELAY_RSP_EVENTID */
+struct wmi_rf_pwr_on_delay_rsp_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID */
+struct wmi_set_high_power_table_params_event {
+	/* wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
 /* WMI_TEMP_SENSE_DONE_EVENTID
  *
  * Measure MAC and radio temperatures
@@ -1726,14 +1955,22 @@
 	u8 reserved;
 } __packed;
 
+/* \WMI_SET_CONNECT_SNR_THR_CMDID */
+struct wmi_set_connect_snr_thr_cmd {
+	u8 enable;
+	u8 reserved;
+	/* 1/4 Db units */
+	__le16 omni_snr_thr;
+	/* 1/4 Db units */
+	__le16 direct_snr_thr;
+} __packed;
+
 /* WMI_LED_CFG_DONE_EVENTID */
 struct wmi_led_cfg_done_event {
 	/* led config status */
 	__le32 status;
 } __packed;
 
-#define WMI_NUM_MCS	(13)
-
 /* Rate search parameters configuration per connection */
 struct wmi_rs_cfg {
 	/* The maximal allowed PER for each MCS
@@ -1758,6 +1995,98 @@
 	__le32 mcs_en_vec;
 } __packed;
 
+/* Slot types */
+enum wmi_sched_scheme_slot_type {
+	WMI_SCHED_SLOT_SP		= 0x0,
+	WMI_SCHED_SLOT_CBAP		= 0x1,
+	WMI_SCHED_SLOT_IDLE		= 0x2,
+	WMI_SCHED_SLOT_ANNOUNCE_NO_ACK	= 0x3,
+	WMI_SCHED_SLOT_DISCOVERY	= 0x4,
+};
+
+enum wmi_sched_scheme_slot_flags {
+	WMI_SCHED_SCHEME_SLOT_PERIODIC	= 0x1,
+};
+
+struct wmi_sched_scheme_slot {
+	/* in microsecond */
+	__le32 tbtt_offset;
+	/* wmi_sched_scheme_slot_flags */
+	u8 flags;
+	/* wmi_sched_scheme_slot_type */
+	u8 type;
+	/* in microsecond */
+	__le16 duration;
+	/* frame_exchange_sequence_duration */
+	__le16 tx_op;
+	/* time in microseconds between two consecutive slots
+	 * relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set
+	 */
+	__le16 period;
+	/* relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set
+	 * number of times to repeat allocation
+	 */
+	u8 num_of_blocks;
+	/* relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set
+	 * every idle_period allocation will be idle
+	 */
+	u8 idle_period;
+	u8 src_aid;
+	u8 dest_aid;
+	__le32 reserved;
+} __packed;
+
+enum wmi_sched_scheme_flags {
+	/* should not be set when clearing scheduling scheme */
+	WMI_SCHED_SCHEME_ENABLE		= 0x01,
+	WMI_SCHED_PROTECTED_SP		= 0x02,
+	/* should be set only on first WMI fragment of scheme */
+	WMI_SCHED_FIRST			= 0x04,
+	/* should be set only on last WMI fragment of scheme */
+	WMI_SCHED_LAST			= 0x08,
+	WMI_SCHED_IMMEDIATE_START	= 0x10,
+};
+
+enum wmi_sched_scheme_advertisment {
+	/* ESE is not advertised at all, STA has to be configured with WMI
+	 * also
+	 */
+	WMI_ADVERTISE_ESE_DISABLED		= 0x0,
+	WMI_ADVERTISE_ESE_IN_BEACON		= 0x1,
+	WMI_ADVERTISE_ESE_IN_ANNOUNCE_FRAME	= 0x2,
+};
+
+/* WMI_SCHEDULING_SCHEME_CMD */
+struct wmi_scheduling_scheme_cmd {
+	u8 serial_num;
+	/* wmi_sched_scheme_advertisment */
+	u8 ese_advertisment;
+	/* wmi_sched_scheme_flags */
+	__le16 flags;
+	u8 num_allocs;
+	u8 reserved[3];
+	__le64 start_tbtt;
+	/* allocations list */
+	struct wmi_sched_scheme_slot allocs[WMI_SCHED_MAX_ALLOCS_PER_CMD];
+} __packed;
+
+enum wmi_sched_scheme_failure_type {
+	WMI_SCHED_SCHEME_FAILURE_NO_ERROR		= 0x00,
+	WMI_SCHED_SCHEME_FAILURE_OLD_START_TSF_ERR	= 0x01,
+};
+
+/* WMI_SCHEDULING_SCHEME_EVENTID */
+struct wmi_scheduling_scheme_event {
+	/* wmi_fw_status_e */
+	u8 status;
+	/* serial number given in command */
+	u8 serial_num;
+	/* wmi_sched_scheme_failure_type */
+	u8 failure_type;
+	/* alignment to 32b */
+	u8 reserved[1];
+} __packed;
+
 /* WMI_RS_CFG_CMDID */
 struct wmi_rs_cfg_cmd {
 	/* connection id */
@@ -1975,6 +2304,19 @@
 	WMI_PS_PROFILE_TYPE_LOW_LATENCY_PS	= 0x03,
 };
 
+/* WMI_PS_DEV_PROFILE_CFG_READ_CMDID */
+struct wmi_ps_dev_profile_cfg_read_cmd {
+	/* reserved */
+	__le32 reserved;
+} __packed;
+
+/* WMI_PS_DEV_PROFILE_CFG_READ_EVENTID */
+struct wmi_ps_dev_profile_cfg_read_event {
+	/* wmi_ps_profile_type_e */
+	u8 ps_profile;
+	u8 reserved[3];
+} __packed;
+
 /* WMI_PS_DEV_PROFILE_CFG_CMDID
  *
  * Power save profile to be used by the device
@@ -2023,157 +2365,6 @@
 	WMI_PS_D3_RESP_POLICY_APPROVED	= 0x02,
 };
 
-/* Device common power save configurations */
-struct wmi_ps_dev_cfg {
-	/* lowest level of PS allowed while unassociated, enum wmi_ps_level_e
-	 */
-	u8 ps_unassoc_min_level;
-	/* lowest deep sleep clock level while nonassoc, enum
-	 * wmi_ps_deep_sleep_clk_level_e
-	 */
-	u8 ps_unassoc_deep_sleep_min_level;
-	/* lowest level of PS allowed while associated, enum wmi_ps_level_e */
-	u8 ps_assoc_min_level;
-	/* lowest deep sleep clock level while assoc, enum
-	 * wmi_ps_deep_sleep_clk_level_e
-	 */
-	u8 ps_assoc_deep_sleep_min_level;
-	/* enum wmi_ps_deep_sleep_clk_level_e */
-	u8 ps_assoc_low_latency_ds_min_level;
-	/* enum wmi_ps_d3_resp_policy_e */
-	u8 ps_D3_response_policy;
-	/* BOOL */
-	u8 ps_D3_pm_pme_enabled;
-	/* BOOL */
-	u8 ps_halp_enable;
-	u8 ps_deep_sleep_enter_thresh_msec;
-	/* BOOL */
-	u8 ps_voltage_scaling_en;
-} __packed;
-
-/* WMI_PS_DEV_CFG_CMDID
- *
- * Configure common Power Save parameters of the device and all MIDs.
- *
- * Returned event:
- * - WMI_PS_DEV_CFG_EVENTID
- */
-struct wmi_ps_dev_cfg_cmd {
-	/* Device Power Save configuration to be applied */
-	struct wmi_ps_dev_cfg ps_dev_cfg;
-	/* alignment to 32b */
-	u8 reserved[2];
-} __packed;
-
-/* WMI_PS_DEV_CFG_EVENTID */
-struct wmi_ps_dev_cfg_event {
-	/* wmi_ps_cfg_cmd_status_e */
-	__le32 status;
-} __packed;
-
-/* WMI_PS_DEV_CFG_READ_CMDID
- *
- * request to retrieve  device Power Save configuration
- * (WMI_PS_DEV_CFG_CMD params)
- *
- * Returned event:
- * - WMI_PS_DEV_CFG_READ_EVENTID
- */
-struct wmi_ps_dev_cfg_read_cmd {
-	__le32 reserved;
-} __packed;
-
-/* WMI_PS_DEV_CFG_READ_EVENTID */
-struct wmi_ps_dev_cfg_read_event {
-	/* wmi_ps_cfg_cmd_status_e */
-	__le32 status;
-	/* Retrieved device Power Save configuration (WMI_PS_DEV_CFG_CMD
-	 * params)
-	 */
-	struct wmi_ps_dev_cfg dev_ps_cfg;
-	/* alignment to 32b */
-	u8 reserved[2];
-} __packed;
-
-/* Per Mac Power Save configurations */
-struct wmi_ps_mid_cfg {
-	/* Low power RX in BTI is enabled, BOOL */
-	u8 beacon_lprx_enable;
-	/* Sync to sector ID enabled, BOOL */
-	u8 beacon_sync_to_sectorId_enable;
-	/* Low power RX in DTI is enabled, BOOL */
-	u8 frame_exchange_lprx_enable;
-	/* Sleep Cycle while in scheduled PS, 1-31 */
-	u8 scheduled_sleep_cycle_pow2;
-	/* Stay Awake for k BIs every (sleep_cycle - k) BIs, 1-31 */
-	u8 scheduled_num_of_awake_bis;
-	u8 am_to_traffic_load_thresh_mbp;
-	u8 traffic_to_am_load_thresh_mbps;
-	u8 traffic_to_am_num_of_no_traffic_bis;
-	/* BOOL */
-	u8 continuous_traffic_psm;
-	__le16 no_traffic_to_min_usec;
-	__le16 no_traffic_to_max_usec;
-	__le16 snoozing_sleep_interval_milisec;
-	u8 max_no_data_awake_events;
-	/* Trigger WEB after k failed beacons */
-	u8 num_of_failed_beacons_rx_to_trigger_web;
-	/* Trigger BF after k failed beacons */
-	u8 num_of_failed_beacons_rx_to_trigger_bf;
-	/* Trigger SOB after k successful beacons */
-	u8 num_of_successful_beacons_rx_to_trigger_sob;
-} __packed;
-
-/* WMI_PS_MID_CFG_CMDID
- *
- * Configure Power Save parameters of a specific MID.
- * These parameters are relevant for the specific BSS this MID belongs to.
- *
- * Returned event:
- * - WMI_PS_MID_CFG_EVENTID
- */
-struct wmi_ps_mid_cfg_cmd {
-	/* MAC ID */
-	u8 mid;
-	/* mid PS configuration to be applied */
-	struct wmi_ps_mid_cfg ps_mid_cfg;
-} __packed;
-
-/* WMI_PS_MID_CFG_EVENTID */
-struct wmi_ps_mid_cfg_event {
-	/* MAC ID */
-	u8 mid;
-	/* alignment to 32b */
-	u8 reserved[3];
-	/* wmi_ps_cfg_cmd_status_e */
-	__le32 status;
-} __packed;
-
-/* WMI_PS_MID_CFG_READ_CMDID
- *
- * request to retrieve Power Save configuration of mid
- * (WMI_PS_MID_CFG_CMD params)
- *
- * Returned event:
- * - WMI_PS_MID_CFG_READ_EVENTID
- */
-struct wmi_ps_mid_cfg_read_cmd {
-	/* MAC ID */
-	u8 mid;
-	/* alignment to 32b */
-	u8 reserved[3];
-} __packed;
-
-/* WMI_PS_MID_CFG_READ_EVENTID */
-struct wmi_ps_mid_cfg_read_event {
-	/* MAC ID */
-	u8 mid;
-	/* Retrieved MID Power Save configuration(WMI_PS_MID_CFG_CMD params) */
-	struct wmi_ps_mid_cfg mid_ps_cfg;
-	/* wmi_ps_cfg_cmd_status_e */
-	__le32 status;
-} __packed;
-
 #define WMI_AOA_MAX_DATA_SIZE	(128)
 
 enum wmi_aoa_meas_status {
@@ -2264,6 +2455,20 @@
 	u8 reserved[3];
 } __packed;
 
+/* WMI_TOF_SET_LCI_EVENTID */
+struct wmi_tof_set_lci_event {
+	/* enum wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
+/* WMI_TOF_SET_LCR_EVENTID */
+struct wmi_tof_set_lcr_event {
+	/* enum wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
 /* Responder FTM Results */
 struct wmi_responder_ftm_res {
 	u8 t1[6];
@@ -2317,10 +2522,19 @@
 	__le32 tsf_sync;
 	/* actual received ftm per burst */
 	u8 actual_ftm_per_burst;
-	u8 reserved0[7];
+	/* Measurments are from RFs, defined by the mask */
+	__le32 meas_rf_mask;
+	u8 reserved0[3];
 	struct wmi_responder_ftm_res responder_ftm_res[0];
 } __packed;
 
+/* WMI_TOF_CFG_RESPONDER_EVENTID */
+struct wmi_tof_cfg_responder_event {
+	/* enum wmi_fw_status */
+	u8 status;
+	u8 reserved[3];
+} __packed;
+
 enum wmi_tof_channel_info_type {
 	WMI_TOF_CHANNEL_INFO_AOA		= 0x00,
 	WMI_TOF_CHANNEL_INFO_LCI		= 0x01,
@@ -2357,12 +2571,15 @@
 struct wmi_tof_get_tx_rx_offset_event {
 	/* enum wmi_fw_status */
 	u8 status;
-	u8 reserved1[3];
+	/* RF index used to read the offsets */
+	u8 rf_index;
+	u8 reserved1[2];
 	/* TX delay offset */
 	__le32 tx_offset;
 	/* RX delay offset */
 	__le32 rx_offset;
-	__le32 reserved2[2];
+	/* Offset to strongest tap of CIR */
+	__le32 precursor;
 } __packed;
 
 /* Result status codes for WMI commands */
@@ -2625,4 +2842,23 @@
 	u8 reserved[3];
 } __packed;
 
+/* WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID */
+struct wmi_set_silent_rssi_table_done_event {
+	/* enum wmi_silent_rssi_status */
+	__le32 status;
+	/* enum wmi_silent_rssi_table */
+	__le32 table;
+} __packed;
+
+/* \WMI_COMMAND_NOT_SUPPORTED_EVENTID */
+struct wmi_command_not_supported_event {
+	/* device id */
+	u8 mid;
+	u8 reserved0;
+	__le16 command_id;
+	/* for UT command only, otherwise reserved */
+	__le16 command_subtype;
+	__le16 reserved1;
+} __packed;
+
 #endif /* __WILOCITY_WMI_H__ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 02c5991..26d5f5e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -2683,6 +2683,21 @@
 		return 0;
 	}
 
+	if (in->client == IPA_CLIENT_APPS_WAN_PROD) {
+		sys->policy = IPA_POLICY_INTR_MODE;
+		sys->use_comm_evt_ring = true;
+		INIT_WORK(&sys->work, ipa3_send_nop_desc);
+
+		/*
+		 * enable source notification status for exception packets
+		 * (i.e. QMAP commands) to be routed to modem.
+		 */
+		sys->ep->status.status_en = true;
+		sys->ep->status.status_ep =
+			ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_CONS);
+		return 0;
+	}
+
 	if (IPA_CLIENT_IS_MEMCPY_DMA_PROD(in->client)) {
 		sys->policy = IPA_POLICY_NOINTR_MODE;
 		return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c b/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
index 6d82da2..d69d6ae 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_interrupts.c
@@ -336,7 +336,7 @@
 	ipa3_process_interrupts(true);
 	IPADBG_LOW("Exit\n");
 
-	ipa3_dec_client_disable_clks(&log_info);
+	ipa3_dec_client_disable_clks_no_block(&log_info);
 	return IRQ_HANDLED;
 }
 /**
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index b119a69..48be199 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1086,7 +1086,6 @@
 	int ret = 0;
 	bool qmap_check;
 	struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
-	struct ipa_tx_meta meta;
 
 	if (skb->protocol != htons(ETH_P_MAP)) {
 		IPAWANDBG_LOW
@@ -1142,17 +1141,11 @@
 	}
 	/* IPA_RM checking end */
 
-	if (RMNET_MAP_GET_CD_BIT(skb)) {
-		memset(&meta, 0, sizeof(meta));
-		meta.pkt_init_dst_ep_valid = true;
-		meta.pkt_init_dst_ep_remote = true;
-		meta.pkt_init_dst_ep =
-			ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_CONS);
-		ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, &meta);
-	} else {
-		ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL);
-	}
-
+	/*
+	 * both data packets and command will be routed to
+	 * IPA_CLIENT_Q6_WAN_CONS based on status configuration
+	 */
+	ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL);
 	if (ret) {
 		ret = NETDEV_TX_BUSY;
 		goto out;
@@ -1373,9 +1366,7 @@
 	}
 
 	if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_AGGREGATION) {
-		IPAWANERR("WAN UL Aggregation not supported!!\n");
-		WARN_ON(1);
-		return -EINVAL;
+		IPAWANDBG("WAN UL Aggregation enabled\n");
 		ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_DEAGGR;
 		ipa_wan_ep_cfg->ipa_ep_cfg.aggr.aggr = IPA_QCMAP;
 
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index a013edd..b929d8b 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -261,6 +261,8 @@
 	POWER_SUPPLY_ATTR(low_power),
 	POWER_SUPPLY_ATTR(temp_cool),
 	POWER_SUPPLY_ATTR(temp_warm),
+	POWER_SUPPLY_ATTR(temp_cold),
+	POWER_SUPPLY_ATTR(temp_hot),
 	POWER_SUPPLY_ATTR(system_temp_level),
 	POWER_SUPPLY_ATTR(resistance),
 	POWER_SUPPLY_ATTR(resistance_capacitive),
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index c793ee5..271c523 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -105,7 +105,7 @@
 };
 
 /* JEITA */
-enum {
+enum jeita_levels {
 	JEITA_COLD = 0,
 	JEITA_COOL,
 	JEITA_WARM,
@@ -252,6 +252,7 @@
 struct fg_dt_props {
 	bool	force_load_profile;
 	bool	hold_soc_while_full;
+	bool	linearize_soc;
 	bool	auto_recharge_soc;
 	int	cutoff_volt_mv;
 	int	empty_volt_mv;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 6f615e4..5e346dc 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -576,6 +576,41 @@
 	return 0;
 }
 
+static int fg_get_jeita_threshold(struct fg_chip *chip,
+				enum jeita_levels level, int *temp_decidegC)
+{
+	int rc;
+	u8 val;
+	u16 reg;
+
+	switch (level) {
+	case JEITA_COLD:
+		reg = BATT_INFO_JEITA_TOO_COLD(chip);
+		break;
+	case JEITA_COOL:
+		reg = BATT_INFO_JEITA_COLD(chip);
+		break;
+	case JEITA_WARM:
+		reg = BATT_INFO_JEITA_HOT(chip);
+		break;
+	case JEITA_HOT:
+		reg = BATT_INFO_JEITA_TOO_HOT(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = fg_read(chip, reg, &val, 1);
+	if (rc < 0) {
+		pr_err("Error in reading jeita level %d, rc=%d\n", level, rc);
+		return rc;
+	}
+
+	/* Resolution is 0.5C. Base is -30C. */
+	*temp_decidegC = (((5 * val) / 10) - 30) * 10;
+	return 0;
+}
+
 #define BATT_TEMP_NUMR		1
 #define BATT_TEMP_DENR		1
 static int fg_get_battery_temp(struct fg_chip *chip, int *val)
@@ -838,7 +873,7 @@
 	if (rc < 0)
 		return rc;
 
-	if (chip->delta_soc > 0)
+	if (chip->dt.linearize_soc && chip->delta_soc > 0)
 		*val = chip->maint_soc;
 	else
 		*val = msoc;
@@ -978,12 +1013,6 @@
 	return 0;
 }
 
-static inline void get_temp_setpoint(int threshold, u8 *val)
-{
-	/* Resolution is 0.5C. Base is -30C. */
-	*val = DIV_ROUND_CLOSEST((threshold + 30) * 10, 5);
-}
-
 static inline void get_batt_temp_delta(int delta, u8 *val)
 {
 	switch (delta) {
@@ -1658,12 +1687,38 @@
 	return 0;
 }
 
+static int fg_configure_full_soc(struct fg_chip *chip, int bsoc)
+{
+	int rc;
+	u8 full_soc[2] = {0xFF, 0xFF};
+
+	/*
+	 * Once SOC masking condition is cleared, FULL_SOC and MONOTONIC_SOC
+	 * needs to be updated to reflect the same. Write battery SOC to
+	 * FULL_SOC and write a full value to MONOTONIC_SOC.
+	 */
+	rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET,
+			(u8 *)&bsoc, 2, FG_IMA_ATOMIC);
+	if (rc < 0) {
+		pr_err("failed to write full_soc rc=%d\n", rc);
+		return rc;
+	}
+
+	rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
+			full_soc, 2, FG_IMA_ATOMIC);
+	if (rc < 0) {
+		pr_err("failed to write monotonic_soc rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 #define AUTO_RECHG_VOLT_LOW_LIMIT_MV	3700
 static int fg_charge_full_update(struct fg_chip *chip)
 {
 	union power_supply_propval prop = {0, };
 	int rc, msoc, bsoc, recharge_soc, msoc_raw;
-	u8 full_soc[2] = {0xFF, 0xFF};
 
 	if (!chip->dt.hold_soc_while_full)
 		return 0;
@@ -1722,24 +1777,24 @@
 			fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
 				msoc);
 		}
-	} else if (msoc_raw < recharge_soc && chip->charge_full) {
-		chip->delta_soc = FULL_CAPACITY - msoc;
+	} else if (msoc_raw <= recharge_soc && chip->charge_full) {
+		if (chip->dt.linearize_soc) {
+			chip->delta_soc = FULL_CAPACITY - msoc;
 
-		/*
-		 * We're spreading out the delta SOC over every 10% change
-		 * in monotonic SOC. We cannot spread more than 9% in the
-		 * range of 0-100 skipping the first 10%.
-		 */
-		if (chip->delta_soc > 9) {
-			chip->delta_soc = 0;
-			chip->maint_soc = 0;
-		} else {
-			chip->maint_soc = FULL_CAPACITY;
-			chip->last_msoc = msoc;
+			/*
+			 * We're spreading out the delta SOC over every 10%
+			 * change in monotonic SOC. We cannot spread more than
+			 * 9% in the range of 0-100 skipping the first 10%.
+			 */
+			if (chip->delta_soc > 9) {
+				chip->delta_soc = 0;
+				chip->maint_soc = 0;
+			} else {
+				chip->maint_soc = FULL_CAPACITY;
+				chip->last_msoc = msoc;
+			}
 		}
 
-		chip->charge_full = false;
-
 		/*
 		 * Raise the recharge voltage so that VBAT_LT_RECHG signal
 		 * will be asserted soon as battery SOC had dropped below
@@ -1752,35 +1807,23 @@
 				rc);
 			goto out;
 		}
+
+		/*
+		 * If charge_done is still set, wait for recharging or
+		 * discharging to happen.
+		 */
+		if (chip->charge_done)
+			goto out;
+
+		rc = fg_configure_full_soc(chip, bsoc);
+		if (rc < 0)
+			goto out;
+
+		chip->charge_full = false;
 		fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
 			msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
-	} else {
-		goto out;
 	}
 
-	if (!chip->charge_full)
-		goto out;
-
-	/*
-	 * During JEITA conditions, charge_full can happen early. FULL_SOC
-	 * and MONOTONIC_SOC needs to be updated to reflect the same. Write
-	 * battery SOC to FULL_SOC and write a full value to MONOTONIC_SOC.
-	 */
-	rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, (u8 *)&bsoc, 2,
-			FG_IMA_ATOMIC);
-	if (rc < 0) {
-		pr_err("failed to write full_soc rc=%d\n", rc);
-		goto out;
-	}
-
-	rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
-			full_soc, 2, FG_IMA_ATOMIC);
-	if (rc < 0) {
-		pr_err("failed to write monotonic_soc rc=%d\n", rc);
-		goto out;
-	}
-
-	fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc);
 out:
 	mutex_unlock(&chip->charge_full_lock);
 	return rc;
@@ -1863,6 +1906,44 @@
 	return 0;
 }
 
+static int fg_set_jeita_threshold(struct fg_chip *chip,
+				enum jeita_levels level, int temp_decidegC)
+{
+	int rc;
+	u8 val;
+	u16 reg;
+
+	if (temp_decidegC < -300 || temp_decidegC > 970)
+		return -EINVAL;
+
+	/* Resolution is 0.5C. Base is -30C. */
+	val = DIV_ROUND_CLOSEST(((temp_decidegC / 10) + 30) * 10, 5);
+	switch (level) {
+	case JEITA_COLD:
+		reg = BATT_INFO_JEITA_TOO_COLD(chip);
+		break;
+	case JEITA_COOL:
+		reg = BATT_INFO_JEITA_COLD(chip);
+		break;
+	case JEITA_WARM:
+		reg = BATT_INFO_JEITA_HOT(chip);
+		break;
+	case JEITA_HOT:
+		reg = BATT_INFO_JEITA_TOO_HOT(chip);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = fg_write(chip, reg, &val, 1);
+	if (rc < 0) {
+		pr_err("Error in setting jeita level %d, rc=%d\n", level, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
 {
 	u8 buf[2];
@@ -3137,6 +3218,9 @@
 {
 	int rc = 0, msoc;
 
+	if (!chip->dt.linearize_soc)
+		return 0;
+
 	mutex_lock(&chip->charge_full_lock);
 	if (chip->delta_soc <= 0)
 		goto out;
@@ -3365,6 +3449,9 @@
 	case POWER_SUPPLY_PROP_CAPACITY:
 		rc = fg_get_prop_capacity(chip, &pval->intval);
 		break;
+	case POWER_SUPPLY_PROP_CAPACITY_RAW:
+		rc = fg_get_msoc_raw(chip, &pval->intval);
+		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 		if (chip->battery_missing)
 			pval->intval = 3700000;
@@ -3377,6 +3464,34 @@
 	case POWER_SUPPLY_PROP_TEMP:
 		rc = fg_get_battery_temp(chip, &pval->intval);
 		break;
+	case POWER_SUPPLY_PROP_COLD_TEMP:
+		rc = fg_get_jeita_threshold(chip, JEITA_COLD, &pval->intval);
+		if (rc < 0) {
+			pr_err("Error in reading jeita_cold, rc=%d\n", rc);
+			return rc;
+		}
+		break;
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+		rc = fg_get_jeita_threshold(chip, JEITA_COOL, &pval->intval);
+		if (rc < 0) {
+			pr_err("Error in reading jeita_cool, rc=%d\n", rc);
+			return rc;
+		}
+		break;
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+		rc = fg_get_jeita_threshold(chip, JEITA_WARM, &pval->intval);
+		if (rc < 0) {
+			pr_err("Error in reading jeita_warm, rc=%d\n", rc);
+			return rc;
+		}
+		break;
+	case POWER_SUPPLY_PROP_HOT_TEMP:
+		rc = fg_get_jeita_threshold(chip, JEITA_HOT, &pval->intval);
+		if (rc < 0) {
+			pr_err("Error in reading jeita_hot, rc=%d\n", rc);
+			return rc;
+		}
+		break;
 	case POWER_SUPPLY_PROP_RESISTANCE:
 		rc = fg_get_battery_resistance(chip, &pval->intval);
 		break;
@@ -3500,6 +3615,48 @@
 			return -EINVAL;
 		}
 		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		if (chip->cl.active) {
+			pr_warn("Capacity learning active!\n");
+			return 0;
+		}
+		if (pval->intval <= 0 || pval->intval > chip->cl.nom_cap_uah) {
+			pr_err("charge_full is out of bounds\n");
+			return -EINVAL;
+		}
+		chip->cl.learned_cc_uah = pval->intval;
+		rc = fg_save_learned_cap_to_sram(chip);
+		if (rc < 0)
+			pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
+		break;
+	case POWER_SUPPLY_PROP_COLD_TEMP:
+		rc = fg_set_jeita_threshold(chip, JEITA_COLD, pval->intval);
+		if (rc < 0) {
+			pr_err("Error in writing jeita_cold, rc=%d\n", rc);
+			return rc;
+		}
+		break;
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+		rc = fg_set_jeita_threshold(chip, JEITA_COOL, pval->intval);
+		if (rc < 0) {
+			pr_err("Error in writing jeita_cool, rc=%d\n", rc);
+			return rc;
+		}
+		break;
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+		rc = fg_set_jeita_threshold(chip, JEITA_WARM, pval->intval);
+		if (rc < 0) {
+			pr_err("Error in writing jeita_warm, rc=%d\n", rc);
+			return rc;
+		}
+		break;
+	case POWER_SUPPLY_PROP_HOT_TEMP:
+		rc = fg_set_jeita_threshold(chip, JEITA_HOT, pval->intval);
+		if (rc < 0) {
+			pr_err("Error in writing jeita_hot, rc=%d\n", rc);
+			return rc;
+		}
+		break;
 	default:
 		break;
 	}
@@ -3515,6 +3672,11 @@
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 	case POWER_SUPPLY_PROP_CC_STEP:
 	case POWER_SUPPLY_PROP_CC_STEP_SEL:
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+	case POWER_SUPPLY_PROP_COLD_TEMP:
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+	case POWER_SUPPLY_PROP_HOT_TEMP:
 		return 1;
 	default:
 		break;
@@ -3555,7 +3717,12 @@
 
 static enum power_supply_property fg_psy_props[] = {
 	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CAPACITY_RAW,
 	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_COLD_TEMP,
+	POWER_SUPPLY_PROP_COOL_TEMP,
+	POWER_SUPPLY_PROP_WARM_TEMP,
+	POWER_SUPPLY_PROP_HOT_TEMP,
 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 	POWER_SUPPLY_PROP_VOLTAGE_OCV,
 	POWER_SUPPLY_PROP_CURRENT_NOW,
@@ -3734,29 +3901,29 @@
 		}
 	}
 
-	get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COLD], &val);
-	rc = fg_write(chip, BATT_INFO_JEITA_TOO_COLD(chip), &val, 1);
+	rc = fg_set_jeita_threshold(chip, JEITA_COLD,
+		chip->dt.jeita_thresholds[JEITA_COLD] * 10);
 	if (rc < 0) {
 		pr_err("Error in writing jeita_cold, rc=%d\n", rc);
 		return rc;
 	}
 
-	get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COOL], &val);
-	rc = fg_write(chip, BATT_INFO_JEITA_COLD(chip), &val, 1);
+	rc = fg_set_jeita_threshold(chip, JEITA_COOL,
+		chip->dt.jeita_thresholds[JEITA_COOL] * 10);
 	if (rc < 0) {
 		pr_err("Error in writing jeita_cool, rc=%d\n", rc);
 		return rc;
 	}
 
-	get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_WARM], &val);
-	rc = fg_write(chip, BATT_INFO_JEITA_HOT(chip), &val, 1);
+	rc = fg_set_jeita_threshold(chip, JEITA_WARM,
+		chip->dt.jeita_thresholds[JEITA_WARM] * 10);
 	if (rc < 0) {
 		pr_err("Error in writing jeita_warm, rc=%d\n", rc);
 		return rc;
 	}
 
-	get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_HOT], &val);
-	rc = fg_write(chip, BATT_INFO_JEITA_TOO_HOT(chip), &val, 1);
+	rc = fg_set_jeita_threshold(chip, JEITA_HOT,
+		chip->dt.jeita_thresholds[JEITA_HOT] * 10);
 	if (rc < 0) {
 		pr_err("Error in writing jeita_hot, rc=%d\n", rc);
 		return rc;
@@ -4680,6 +4847,9 @@
 	chip->dt.hold_soc_while_full = of_property_read_bool(node,
 					"qcom,hold-soc-while-full");
 
+	chip->dt.linearize_soc = of_property_read_bool(node,
+					"qcom,linearize-soc");
+
 	rc = fg_parse_ki_coefficients(chip);
 	if (rc < 0)
 		pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
@@ -5002,6 +5172,29 @@
 	return 0;
 }
 
+static void fg_gen3_shutdown(struct platform_device *pdev)
+{
+	struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
+	int rc, bsoc;
+
+	if (chip->charge_full) {
+		rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
+		if (rc < 0) {
+			pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
+			return;
+		}
+
+		/* We need 2 most significant bytes here */
+		bsoc = (u32)bsoc >> 16;
+
+		rc = fg_configure_full_soc(chip, bsoc);
+		if (rc < 0) {
+			pr_err("Error in configuring full_soc, rc=%d\n", rc);
+			return;
+		}
+	}
+}
+
 static const struct of_device_id fg_gen3_match_table[] = {
 	{.compatible = FG_GEN3_DEV_NAME},
 	{},
@@ -5016,6 +5209,7 @@
 	},
 	.probe		= fg_gen3_probe,
 	.remove		= fg_gen3_remove,
+	.shutdown	= fg_gen3_shutdown,
 };
 
 static int __init fg_gen3_init(void)
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 5304405..6abbaeb 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -795,6 +795,7 @@
  *************************/
 
 static enum power_supply_property smb2_dc_props[] = {
+	POWER_SUPPLY_PROP_INPUT_SUSPEND,
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_ONLINE,
 	POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -810,6 +811,9 @@
 	int rc = 0;
 
 	switch (psp) {
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		val->intval = get_effective_result(chg->dc_suspend_votable);
+		break;
 	case POWER_SUPPLY_PROP_PRESENT:
 		rc = smblib_get_prop_dc_present(chg, val);
 		break;
@@ -841,6 +845,10 @@
 	int rc = 0;
 
 	switch (psp) {
+	case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+		rc = vote(chg->dc_suspend_votable, WBC_VOTER,
+				(bool)val->intval, 0);
+		break;
 	case POWER_SUPPLY_PROP_CURRENT_MAX:
 		rc = smblib_set_prop_dc_current_max(chg, val);
 		break;
@@ -1199,7 +1207,7 @@
  * VBUS REGULATOR REGISTRATION *
  ******************************/
 
-struct regulator_ops smb2_vbus_reg_ops = {
+static struct regulator_ops smb2_vbus_reg_ops = {
 	.enable = smblib_vbus_regulator_enable,
 	.disable = smblib_vbus_regulator_disable,
 	.is_enabled = smblib_vbus_regulator_is_enabled,
@@ -1241,7 +1249,7 @@
  * VCONN REGULATOR REGISTRATION *
  ******************************/
 
-struct regulator_ops smb2_vconn_reg_ops = {
+static struct regulator_ops smb2_vconn_reg_ops = {
 	.enable = smblib_vconn_regulator_enable,
 	.disable = smblib_vconn_regulator_disable,
 	.is_enabled = smblib_vconn_regulator_is_enabled,
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 9b5b592..1b890d5 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -891,7 +891,7 @@
 	bool override;
 
 	/* suspend and return if 25mA or less is requested */
-	if (icl_ua < USBIN_25MA)
+	if (icl_ua <= USBIN_25MA)
 		return smblib_set_usb_suspend(chg, true);
 
 	if (icl_ua == INT_MAX)
@@ -1017,7 +1017,7 @@
 		icl_ua = 0;
 	}
 
-	suspend = (icl_ua < USBIN_25MA);
+	suspend = (icl_ua <= USBIN_25MA);
 	if (suspend)
 		goto suspend;
 
@@ -4153,7 +4153,7 @@
 
 	/* skip suspending input if its already suspended by some other voter */
 	usb_icl = get_effective_result(chg->usb_icl_votable);
-	if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
+	if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA)
 		return IRQ_HANDLED;
 
 	if (stat & USE_DCIN_BIT)
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 5251b6f..80f5bca 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -67,6 +67,7 @@
 #define WEAK_CHARGER_VOTER		"WEAK_CHARGER_VOTER"
 #define OTG_VOTER			"OTG_VOTER"
 #define FCC_CHANGE_VOTER		"FCC_CHANGE_VOTER"
+#define WBC_VOTER			"WBC_VOTER"
 
 #define VCONN_MAX_ATTEMPTS	3
 #define OTG_MAX_ATTEMPTS	3
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index e0c92c6..28c3512 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -111,7 +111,7 @@
 	debug_mask, __debug_mask, int, 0600
 );
 
-irqreturn_t smb138x_handle_slave_chg_state_change(int irq, void *data)
+static irqreturn_t smb138x_handle_slave_chg_state_change(int irq, void *data)
 {
 	struct smb_irq_data *irq_data = data;
 	struct smb138x *chip = irq_data->parent_data;
@@ -730,7 +730,7 @@
  * VBUS REGULATOR REGISTRATION *
  ******************************/
 
-struct regulator_ops smb138x_vbus_reg_ops = {
+static struct regulator_ops smb138x_vbus_reg_ops = {
 	.enable		= smblib_vbus_regulator_enable,
 	.disable	= smblib_vbus_regulator_disable,
 	.is_enabled	= smblib_vbus_regulator_is_enabled,
@@ -772,7 +772,7 @@
  * VCONN REGULATOR REGISTRATION *
  ******************************/
 
-struct regulator_ops smb138x_vconn_reg_ops = {
+static struct regulator_ops smb138x_vconn_reg_ops = {
 	.enable		= smblib_vconn_regulator_enable,
 	.disable	= smblib_vconn_regulator_disable,
 	.is_enabled	= smblib_vconn_regulator_is_enabled,
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 792ae42..32edd76 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -21,6 +21,7 @@
 #define MAX_UFS_QCOM_HOSTS	2
 #define MAX_U32                 (~(u32)0)
 #define MPHY_TX_FSM_STATE       0x41
+#define MPHY_RX_FSM_STATE       0xC1
 #define TX_FSM_HIBERN8          0x1
 #define HBRN8_POLL_TOUT_MS      100
 #define DEFAULT_CLK_RATE_HZ     1000000
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 7c5a1bc..f5a6736 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -144,10 +144,11 @@
 static int ufshcd_populate_vreg(struct device *dev, const char *name,
 		struct ufs_vreg **out_vreg)
 {
-	int ret = 0;
+	int len, ret = 0;
 	char prop_name[MAX_PROP_SIZE];
 	struct ufs_vreg *vreg = NULL;
 	struct device_node *np = dev->of_node;
+	const __be32 *prop;
 
 	if (!np) {
 		dev_err(dev, "%s: non DT initialization\n", __func__);
@@ -186,8 +187,16 @@
 			vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
 			vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
 		} else {
-			vreg->min_uV = UFS_VREG_VCC_MIN_UV;
-			vreg->max_uV = UFS_VREG_VCC_MAX_UV;
+			prop = of_get_property(np, "vcc-voltage-level", &len);
+			if (!prop || (len != (2 * sizeof(__be32)))) {
+				dev_warn(dev, "%s vcc-voltage-level property.\n",
+					prop ? "invalid format" : "no");
+				vreg->min_uV = UFS_VREG_VCC_MIN_UV;
+				vreg->max_uV = UFS_VREG_VCC_MAX_UV;
+			} else {
+				vreg->min_uV = be32_to_cpup(&prop[0]);
+				vreg->max_uV = be32_to_cpup(&prop[1]);
+			}
 		}
 	} else if (!strcmp(name, "vccq")) {
 		vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c132dbc..3578b88 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -864,6 +864,24 @@
 	}
 }
 
+static void ufshcd_print_fsm_state(struct ufs_hba *hba)
+{
+	int err = 0, tx_fsm_val = 0, rx_fsm_val = 0;
+
+	err = ufshcd_dme_get(hba,
+			UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+			UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+			&tx_fsm_val);
+	dev_err(hba->dev, "%s: TX_FSM_STATE = %u, err = %d\n", __func__,
+			tx_fsm_val, err);
+	err = ufshcd_dme_get(hba,
+			UIC_ARG_MIB_SEL(MPHY_RX_FSM_STATE,
+			UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)),
+			&rx_fsm_val);
+	dev_err(hba->dev, "%s: RX_FSM_STATE = %u, err = %d\n", __func__,
+			rx_fsm_val, err);
+}
+
 static void ufshcd_print_host_state(struct ufs_hba *hba)
 {
 	if (!(hba->ufshcd_dbg_print & UFSHCD_DBG_PRINT_HOST_STATE_EN))
@@ -888,6 +906,7 @@
 		hba->capabilities, hba->caps);
 	dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks,
 		hba->dev_info.quirks);
+	ufshcd_print_fsm_state(hba);
 }
 
 /**
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index 43f255e..6019e4b 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -604,10 +604,11 @@
 static unsigned long glink_qos_calc_rate_kBps(size_t pkt_size,
 				       unsigned long interval_us)
 {
-	unsigned long rate_kBps, rem;
+	unsigned long rem;
+	uint64_t rate_kBps;
 
 	rate_kBps = pkt_size * USEC_PER_SEC;
-	rem = do_div(rate_kBps, (interval_us * 1024));
+	rem = do_div(rate_kBps, interval_us * 1024);
 	return rate_kBps;
 }
 
@@ -5454,8 +5455,8 @@
 static void glink_scheduler_eval_prio(struct channel_ctx *ctx,
 			struct glink_core_xprt_ctx *xprt_ctx)
 {
-	unsigned long token_end_time;
-	unsigned long token_consume_time, rem;
+	unsigned long token_end_time, rem;
+	uint64_t token_consume_time;
 	unsigned long obs_rate_kBps;
 
 	if (ctx->initial_priority == 0)
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 209209b..ecf72ca 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -152,6 +152,8 @@
 #define ICNSS_QMI_ASSERT() do { } while (0)
 #endif
 
+#define QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED 0x77
+
 enum icnss_debug_quirks {
 	HW_ALWAYS_ON,
 	HW_DEBUG_ENABLE,
@@ -740,7 +742,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI vbatt request rejected, result:%d error:%d\n",
 			resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 	priv->stats.vbatt_resp++;
@@ -1224,7 +1226,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI MSA Mem info request rejected, result:%d error:%d\n",
 			resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 
@@ -1296,7 +1298,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI MSA ready request rejected: result:%d error:%d\n",
 			resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 	penv->stats.msa_ready_resp++;
@@ -1359,7 +1361,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI indication register request rejected, resut:%d error:%d\n",
 		       resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 	penv->stats.ind_register_resp++;
@@ -1406,7 +1408,9 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI capability request rejected, result:%d error:%d\n",
 		       resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
+		if (resp.resp.error == QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED)
+			icnss_pr_err("RF card Not present");
 		goto out;
 	}
 
@@ -1489,7 +1493,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI mode request rejected, mode:%d result:%d error:%d\n",
 			     mode, resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 	penv->stats.mode_resp++;
@@ -1539,7 +1543,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI config request rejected, result:%d error:%d\n",
 		       resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 	penv->stats.cfg_resp++;
@@ -1592,7 +1596,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI INI request rejected, fw_log_mode:%d result:%d error:%d\n",
 			     fw_log_mode, resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 	penv->stats.ini_resp++;
@@ -1652,7 +1656,7 @@
 	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI athdiag read request rejected, result:%d error:%d\n",
 			     resp->resp.result, resp->resp.error);
-		ret = resp->resp.result;
+		ret = -resp->resp.result;
 		goto out;
 	}
 
@@ -1718,7 +1722,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI athdiag write request rejected, result:%d error:%d\n",
 			     resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 out:
@@ -1813,7 +1817,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI rejuvenate ack request rejected, result:%d error %d\n",
 			     resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 	priv->stats.rejuvenate_ack_resp++;
@@ -1874,7 +1878,7 @@
 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
 		icnss_pr_err("QMI dynamic feature mask request rejected, result:%d error %d\n",
 			     resp.resp.result, resp.resp.error);
-		ret = resp.resp.result;
+		ret = -resp.resp.result;
 		goto out;
 	}
 
diff --git a/drivers/soc/qcom/llcc-sdm845.c b/drivers/soc/qcom/llcc-sdm845.c
index 739c053..3863b09 100644
--- a/drivers/soc/qcom/llcc-sdm845.c
+++ b/drivers/soc/qcom/llcc-sdm845.c
@@ -57,23 +57,24 @@
 	}
 
 static struct llcc_slice_config sdm845_data[] =  {
-	SCT_ENTRY("cpuss",       1, 1, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 1),
+	SCT_ENTRY("cpuss",       1, 1, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 1),
 	SCT_ENTRY("vidsc0",      2, 2, 512, 2, 1, 0x0,  0x0F0, 0, 0, 1, 1, 0),
 	SCT_ENTRY("vidsc1",      3, 3, 512, 2, 1, 0x0,  0x0F0, 0, 0, 1, 1, 0),
-	SCT_ENTRY("rotator",     4, 4, 563, 2, 1, 0x0,  0x00F, 2, 0, 1, 1, 0),
-	SCT_ENTRY("voice",       5, 5, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
-	SCT_ENTRY("audio",       6, 6, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
-	SCT_ENTRY("modemhp_grow", 7, 7, 1024, 2, 0, 0x0F0, 0xF0F, 0, 0, 1, 1, 0),
-	SCT_ENTRY("modem",       8, 8, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
-	SCT_ENTRY("compute",     10, 10, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
-	SCT_ENTRY("gpuhtw",      11, 11, 512, 1, 1, 0x0,  0xC, 0, 0, 1, 1, 0),
-	SCT_ENTRY("gpu",         12, 12, 2560, 1, 0, 0xFF0, 0x3, 0, 0, 1, 1, 0),
-	SCT_ENTRY("mmuhwt",      13, 13, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 0, 1),
-	SCT_ENTRY("compute_dma", 15, 15, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
-	SCT_ENTRY("display",     16, 16, 3072, 1, 0, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+	SCT_ENTRY("rotator",     4, 4, 563, 2, 1, 0x0,  0x00e, 2, 0, 1, 1, 0),
+	SCT_ENTRY("voice",       5, 5, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+	SCT_ENTRY("audio",       6, 6, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+	SCT_ENTRY("modemhp_grow", 7, 7, 1024, 2, 0, 0x0FC, 0xF00, 0, 0, 1, 1, 0),
+	SCT_ENTRY("modem",       8, 8, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+	SCT_ENTRY("compute",     10, 10, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+	SCT_ENTRY("gpuhtw",      11, 11, 512, 1, 1, 0xC,  0x0, 0, 0, 1, 1, 0),
+	SCT_ENTRY("gpu",         12, 12, 2304, 1, 0, 0xFF0, 0x2, 0, 0, 1, 1, 0),
+	SCT_ENTRY("mmuhwt",      13, 13, 256, 2, 0, 0x0,  0x1, 0, 0, 1, 0, 1),
+	SCT_ENTRY("compute_dma", 15, 15, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+	SCT_ENTRY("display",     16, 16, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
+	SCT_ENTRY("videofw",     17, 17, 2816, 1, 0, 0xFFC, 0x2, 0, 0, 1, 1, 0),
 	SCT_ENTRY("modemhp_fix", 20, 20, 1024, 2, 1, 0x0,  0xF00, 0, 0, 1, 1, 0),
 	SCT_ENTRY("modem_paging", 21, 21, 1024, 0, 1, 0x0,  0xF, 0, 0, 1, 1, 0),
-	SCT_ENTRY("audiohw",     22, 22, 1024, 1, 1, 0xFF0, 0xF, 0, 0, 1, 1, 0),
+	SCT_ENTRY("audiohw",     22, 22, 1024, 1, 1, 0xFFC, 0x2, 0, 0, 1, 1, 0),
 };
 
 static int sdm845_qcom_llcc_probe(struct platform_device *pdev)
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index ea01076..707d9e7 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -563,9 +563,6 @@
 		return ret;
 
 	list_for_each_entry_safe(node, node_tmp, clist, link) {
-		if (unlikely(node->node_info->defer_qos))
-			msm_bus_dev_init_qos(&node->dev, NULL);
-
 		bcm_clist_add(node);
 	}
 
@@ -668,6 +665,12 @@
 	kfree(cmdlist_active);
 	kfree(n_active);
 
+
+	list_for_each_entry_safe(node, node_tmp, clist, link) {
+		if (unlikely(node->node_info->defer_qos))
+			msm_bus_dev_init_qos(&node->dev, NULL);
+	}
+
 exit_msm_bus_commit_data:
 	list_for_each_entry_safe(node, node_tmp, clist, link) {
 		bcm_clist_clean(node);
@@ -962,6 +965,12 @@
 
 	MSM_BUS_DBG("Device = %d", node_dev->node_info->id);
 
+	if (node_dev->node_info->qos_params.defer_init_qos) {
+		node_dev->node_info->qos_params.defer_init_qos = false;
+		node_dev->node_info->defer_qos = true;
+		goto exit_init_qos;
+	}
+
 	if (node_dev->ap_owned) {
 		struct msm_bus_node_device_type *bus_node_info;
 
@@ -1290,6 +1299,8 @@
 				pdata_node_info->qos_params.reg_mode.write;
 	node_info->qos_params.urg_fwd_en =
 				pdata_node_info->qos_params.urg_fwd_en;
+	node_info->qos_params.defer_init_qos =
+				pdata_node_info->qos_params.defer_init_qos;
 	node_info->agg_params.buswidth = pdata_node_info->agg_params.buswidth;
 	node_info->agg_params.agg_scheme =
 					pdata_node_info->agg_params.agg_scheme;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
index 77cbbf1..32b6adf 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_of_rpmh.c
@@ -241,6 +241,8 @@
 	node_info->qos_params.urg_fwd_en = of_property_read_bool(dev_node,
 						"qcom,forwarding");
 
+	node_info->qos_params.defer_init_qos = of_property_read_bool(dev_node,
+						"qcom,defer-init-qos");
 }
 
 static int msm_bus_of_parse_clk_array(struct device_node *dev_node,
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
index ad04fef..a9733f1 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
@@ -136,6 +136,7 @@
 	struct msm_bus_noc_regulator reg;
 	struct msm_bus_noc_regulator_mode reg_mode;
 	bool urg_fwd_en;
+	bool defer_init_qos;
 };
 
 struct node_util_levels_type {
diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c
index 519bb611..25099bb 100644
--- a/drivers/soc/qcom/msm_glink_pkt.c
+++ b/drivers/soc/qcom/msm_glink_pkt.c
@@ -33,7 +33,8 @@
 #include <linux/termios.h>
 
 #include <soc/qcom/glink.h>
-
+/* This Limit ensures that auto queue will not exhaust memory on remote side */
+#define MAX_PENDING_GLINK_PKT 5
 #define MODULE_NAME "msm_glinkpkt"
 #define DEVICE_NAME "glinkpkt"
 #define WAKEUPSOURCE_TIMEOUT (2000) /* two seconds */
@@ -136,6 +137,7 @@
 	struct glink_link_info link_info;
 	void *link_state_handle;
 	bool link_up;
+	bool auto_intent_enabled;
 };
 
 /**
@@ -445,9 +447,26 @@
 bool glink_pkt_rmt_rx_intent_req_cb(void *handle, const void *priv, size_t sz)
 {
 	struct queue_rx_intent_work *work_item;
+	int pending_pkt_count = 0;
+	struct glink_rx_pkt *pkt = NULL;
+	unsigned long flags;
+	struct glink_pkt_dev *devp = (struct glink_pkt_dev *)priv;
 
 	GLINK_PKT_INFO("%s(): QUEUE RX INTENT to receive size[%zu]\n",
 		   __func__, sz);
+	if (devp->auto_intent_enabled) {
+		spin_lock_irqsave(&devp->pkt_list_lock, flags);
+		list_for_each_entry(pkt, &devp->pkt_list, list)
+			pending_pkt_count++;
+		spin_unlock_irqrestore(&devp->pkt_list_lock, flags);
+		if (pending_pkt_count > MAX_PENDING_GLINK_PKT) {
+			GLINK_PKT_ERR("%s failed, max limit reached\n",
+					__func__);
+			return false;
+		}
+	} else {
+		return false;
+	}
 
 	work_item = kzalloc(sizeof(*work_item), GFP_ATOMIC);
 	if (!work_item) {
@@ -456,7 +475,7 @@
 	}
 
 	work_item->intent_size = sz;
-	work_item->devp = (struct glink_pkt_dev *)priv;
+	work_item->devp = devp;
 	INIT_WORK(&work_item->work, glink_pkt_queue_rx_intent_worker);
 	queue_work(glink_pkt_wq, &work_item->work);
 
@@ -626,10 +645,11 @@
 	}
 
 	mutex_lock(&devp->ch_lock);
-	if (!glink_rx_intent_exists(devp->handle, count)) {
+	if (!glink_pkt_read_avail(devp) &&
+				!glink_rx_intent_exists(devp->handle, count)) {
 		ret  = glink_queue_rx_intent(devp->handle, devp, count);
 		if (ret) {
-			GLINK_PKT_ERR("%s: failed to queue_rx_intent ret[%d]\n",
+			GLINK_PKT_ERR("%s: failed to queue intent ret[%d]\n",
 					__func__, ret);
 			mutex_unlock(&devp->ch_lock);
 			return ret;
@@ -914,6 +934,7 @@
 	case GLINK_PKT_IOCTL_QUEUE_RX_INTENT:
 		ret = get_user(size, (uint32_t *)arg);
 		GLINK_PKT_INFO("%s: intent size[%d]\n", __func__, size);
+		devp->auto_intent_enabled = false;
 		ret  = glink_queue_rx_intent(devp->handle, devp, size);
 		if (ret) {
 			GLINK_PKT_ERR("%s: failed to QUEUE_RX_INTENT ret[%d]\n",
@@ -1182,6 +1203,7 @@
 				glink_pkt_link_state_cb;
 	devp->i = i;
 	devp->poll_mode = 0;
+	devp->auto_intent_enabled = true;
 	devp->ws_locked = 0;
 	devp->ch_state = GLINK_LOCAL_DISCONNECTED;
 	/* Default timeout for open wait is 120sec */
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index f5aff4f..926016f 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -77,9 +77,6 @@
 
 #define MSS_MAGIC			0XAABADEAD
 
-#define MSS_PDC_OFFSET			8
-#define MSS_PDC_MASK			BIT(MSS_PDC_OFFSET)
-
 /* Timeout value for MBA boot when minidump is enabled */
 #define MBA_ENCRYPTION_TIMEOUT	3000
 enum scm_cmd {
@@ -214,13 +211,14 @@
 static void pil_mss_pdc_sync(struct q6v5_data *drv, bool pdc_sync)
 {
 	u32 val = 0;
+	u32 mss_pdc_mask = BIT(drv->mss_pdc_offset);
 
 	if (drv->pdc_sync) {
 		val = readl_relaxed(drv->pdc_sync);
 		if (pdc_sync)
-			val |= MSS_PDC_MASK;
+			val |= mss_pdc_mask;
 		else
-			val &= ~MSS_PDC_MASK;
+			val &= ~mss_pdc_mask;
 		writel_relaxed(val, drv->pdc_sync);
 		/* Ensure PDC is written before next write */
 		wmb();
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index 7984dfe..e9d3534 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -293,6 +293,13 @@
 	if (res) {
 		q6->pdc_sync = devm_ioremap(&pdev->dev,
 						res->start, resource_size(res));
+		if (of_property_read_u32(pdev->dev.of_node,
+			"qcom,mss_pdc_offset", &q6->mss_pdc_offset)) {
+			dev_err(&pdev->dev,
+				"Offset for MSS PDC not specified\n");
+			return -EINVAL;
+		}
+
 	}
 
 	q6->alt_reset = NULL;
diff --git a/drivers/soc/qcom/pil-q6v5.h b/drivers/soc/qcom/pil-q6v5.h
index 9b4c811..4961b1f 100644
--- a/drivers/soc/qcom/pil-q6v5.h
+++ b/drivers/soc/qcom/pil-q6v5.h
@@ -74,6 +74,7 @@
 	bool restart_reg_sec;
 	bool override_acc;
 	int override_acc_1;
+	int mss_pdc_offset;
 	bool ahb_clk_vote;
 	bool mx_spike_wa;
 };
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 6acb731..de3dc69 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -192,16 +192,26 @@
 static void spi_setup_word_len(struct spi_geni_master *mas, u32 mode,
 						int bits_per_word)
 {
-	int pack_words = 0;
+	int pack_words = 1;
 	bool msb_first = (mode & SPI_LSB_FIRST) ? false : true;
 	u32 word_len = geni_read_reg(mas->base, SE_SPI_WORD_LEN);
+	unsigned long cfg0, cfg1;
 
+	/*
+	 * If bits_per_word isn't a byte aligned value, set the packing to be
+	 * 1 SPI word per FIFO word.
+	 */
 	if (!(mas->tx_fifo_width % bits_per_word))
 		pack_words = mas->tx_fifo_width / bits_per_word;
 	word_len &= ~WORD_LEN_MSK;
 	word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK);
 	se_config_packing(mas->base, bits_per_word, pack_words, msb_first);
 	geni_write_reg(word_len, mas->base, SE_SPI_WORD_LEN);
+	se_get_packing_config(bits_per_word, pack_words, msb_first,
+							&cfg0, &cfg1);
+	GENI_SE_DBG(mas->ipc, false, mas->dev,
+		"%s: cfg0 %lu cfg1 %lu bpw %d pack_words %d\n", __func__,
+		cfg0, cfg1, bits_per_word, pack_words);
 }
 
 static int setup_fifo_params(struct spi_device *spi_slv,
@@ -257,6 +267,12 @@
 	geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV);
 	geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
 	geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
+	GENI_SE_DBG(mas->ipc, false, mas->dev,
+		"%s:Loopback%d demux_sel0x%x demux_op_inv 0x%x clk_cfg 0x%x\n",
+		__func__, loopback_cfg, demux_sel, demux_output_inv, m_clk_cfg);
+	GENI_SE_DBG(mas->ipc, false, mas->dev,
+		"%s:clk_sel 0x%x cpol %d cpha %d\n", __func__,
+							clk_sel, cpol, cpha);
 	/* Ensure message level attributes are written before returning */
 	mb();
 setup_fifo_params_exit:
@@ -316,10 +332,7 @@
 		flags |= GSI_CS_TOGGLE;
 
 	word_len = xfer->bits_per_word - MIN_WORD_LEN;
-	if (mas->tx_fifo_width % xfer->bits_per_word)
-		pack = 0;
-	else
-		pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
+	pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
 	ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
 	if (ret) {
 		dev_err(mas->dev, "%s:Err setting clks:%d\n", __func__, ret);
@@ -504,19 +517,26 @@
 		}
 	}
 
+	if (!(mas->cur_word_len % MIN_WORD_LEN)) {
+		rx_len = ((xfer->len << 3) / mas->cur_word_len);
+	} else {
+		int bytes_per_word = (mas->cur_word_len / BITS_PER_BYTE) + 1;
+
+		rx_len = (xfer->len / bytes_per_word);
+	}
+
 	if (xfer->tx_buf && xfer->rx_buf) {
 		cmd = SPI_FULL_DUPLEX;
 		tx_nent += 2;
 		rx_nent++;
-		rx_len = ((xfer->len << 3) / mas->cur_word_len);
 	} else if (xfer->tx_buf) {
 		cmd = SPI_TX_ONLY;
 		tx_nent += 2;
+		rx_len = 0;
 	} else if (xfer->rx_buf) {
 		cmd = SPI_RX_ONLY;
 		tx_nent++;
 		rx_nent++;
-		rx_len = ((xfer->len << 3) / mas->cur_word_len);
 	}
 
 	cs |= spi_slv->chip_select;
@@ -844,7 +864,14 @@
 	spi_tx_cfg &= ~CS_TOGGLE;
 	if (xfer->cs_change)
 		spi_tx_cfg |= CS_TOGGLE;
-	trans_len = ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
+	if (!(mas->cur_word_len % MIN_WORD_LEN)) {
+		trans_len =
+			((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
+	} else {
+		int bytes_per_word = (mas->cur_word_len / BITS_PER_BYTE) + 1;
+
+		trans_len = (xfer->len / bytes_per_word) & TRANS_LEN_MSK;
+	}
 	if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
 		m_param |= FRAGMENTATION;
 
@@ -860,6 +887,9 @@
 	}
 	geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
 	geni_setup_m_cmd(mas->base, m_cmd, m_param);
+	GENI_SE_DBG(mas->ipc, false, mas->dev,
+		"%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x\n",
+		__func__, trans_len, xfer->len, spi_tx_cfg, m_cmd);
 	if (m_cmd & SPI_TX_ONLY)
 		geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
 	/* Ensure all writes are done before the WM interrupt */
@@ -872,6 +902,7 @@
 
 	reinit_completion(&mas->xfer_done);
 	geni_cancel_m_cmd(mas->base);
+	geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
 	/* Ensure cmd cancel is written */
 	mb();
 	timeout = wait_for_completion_timeout(&mas->xfer_done, HZ);
@@ -966,12 +997,25 @@
 {
 	int i = 0;
 	int tx_fifo_width = (mas->tx_fifo_width >> 3);
-	int max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
+	int max_bytes = 0;
 	const u8 *tx_buf = NULL;
 
 	if (!mas->cur_xfer)
 		return;
 
+	/*
+	 * For non-byte aligned bits-per-word values:
+	 * Assumption is that each SPI word will be accomodated in
+	 * ceil (bits_per_word / bits_per_byte)
+	 * and the next SPI word starts at the next byte.
+	 * In such cases, we can fit 1 SPI word per FIFO word so adjust the
+	 * max byte that can be sent per IRQ accordingly.
+	 */
+	if ((mas->tx_fifo_width % mas->cur_word_len))
+		max_bytes = (mas->tx_fifo_depth - mas->tx_wm) *
+				((mas->cur_word_len / BITS_PER_BYTE) + 1);
+	else
+		max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * tx_fifo_width;
 	tx_buf = mas->cur_xfer->tx_buf;
 	tx_buf += (mas->cur_xfer->len - mas->tx_rem_bytes);
 	max_bytes = min_t(int, mas->tx_rem_bytes, max_bytes);
@@ -979,8 +1023,13 @@
 		int j;
 		u32 fifo_word = 0;
 		u8 *fifo_byte;
-		int bytes_to_write = min_t(int, (max_bytes - i), tx_fifo_width);
+		int bytes_per_fifo = tx_fifo_width;
+		int bytes_to_write = 0;
 
+		if ((mas->tx_fifo_width % mas->cur_word_len))
+			bytes_per_fifo =
+				(mas->cur_word_len / BITS_PER_BYTE) + 1;
+		bytes_to_write = min_t(int, (max_bytes - i), bytes_per_fifo);
 		fifo_byte = (u8 *)&fifo_word;
 		for (j = 0; j < bytes_to_write; j++)
 			fifo_byte[j] = tx_buf[i++];
@@ -1019,15 +1068,24 @@
 			rx_bytes += rx_last_byte_valid;
 		}
 	}
-	rx_bytes += rx_wc * fifo_width;
+	if (!(mas->tx_fifo_width % mas->cur_word_len))
+		rx_bytes += rx_wc * fifo_width;
+	else
+		rx_bytes += rx_wc *
+			((mas->cur_word_len / BITS_PER_BYTE) + 1);
 	rx_bytes = min_t(int, mas->rx_rem_bytes, rx_bytes);
 	rx_buf += (mas->cur_xfer->len - mas->rx_rem_bytes);
 	while (i < rx_bytes) {
 		u32 fifo_word = 0;
 		u8 *fifo_byte;
-		int read_bytes = min_t(int, (rx_bytes - i), fifo_width);
+		int bytes_per_fifo = fifo_width;
+		int read_bytes = 0;
 		int j;
 
+		if ((mas->tx_fifo_width % mas->cur_word_len))
+			bytes_per_fifo =
+				(mas->cur_word_len / BITS_PER_BYTE) + 1;
+		read_bytes = min_t(int, (rx_bytes - i), bytes_per_fifo);
 		fifo_word = geni_read_reg(mas->base, SE_GENI_RX_FIFOn);
 		fifo_byte = (u8 *)&fifo_word;
 		for (j = 0; j < read_bytes; j++)
@@ -1039,8 +1097,14 @@
 static irqreturn_t geni_spi_irq(int irq, void *dev)
 {
 	struct spi_geni_master *mas = dev;
-	u32 m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS);
+	u32 m_irq = 0;
 
+	if (pm_runtime_status_suspended(dev)) {
+		GENI_SE_DBG(mas->ipc, false, mas->dev,
+				"%s: device is suspended\n", __func__);
+		goto exit_geni_spi_irq;
+	}
+	m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS);
 	if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
 		geni_spi_handle_rx(mas);
 
@@ -1050,7 +1114,26 @@
 	if ((m_irq & M_CMD_DONE_EN) || (m_irq & M_CMD_CANCEL_EN) ||
 		(m_irq & M_CMD_ABORT_EN)) {
 		complete(&mas->xfer_done);
+		/*
+		 * If this happens, then a CMD_DONE came before all the buffer
+		 * bytes were sent out. This is unusual, log this condition and
+		 * disable the WM interrupt to prevent the system from stalling
+		 * due an interrupt storm.
+		 * If this happens when all Rx bytes haven't been received, log
+		 * the condition.
+		 */
+		if (mas->tx_rem_bytes) {
+			geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
+			GENI_SE_DBG(mas->ipc, false, mas->dev,
+				"%s:Premature Done.tx_rem%d bpw%d\n",
+				__func__, mas->tx_rem_bytes, mas->cur_word_len);
+		}
+		if (mas->rx_rem_bytes)
+			GENI_SE_DBG(mas->ipc, false, mas->dev,
+				"%s:Premature Done.rx_rem%d bpw%d\n",
+				__func__, mas->rx_rem_bytes, mas->cur_word_len);
 	}
+exit_geni_spi_irq:
 	geni_write_reg(m_irq, mas->base, SE_GENI_M_IRQ_CLEAR);
 	return IRQ_HANDLED;
 }
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 101e51b..bb5f706 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -863,7 +863,7 @@
 	tzd = thermal_zone_get_zone_by_name(
 				sensor_data->virt_zone_name);
 	if (IS_ERR(tzd)) {
-		dev_err(dev, "sens:%s not available err: %ld\n",
+		dev_dbg(dev, "sens:%s not available err: %ld\n",
 				sensor_data->virt_zone_name,
 				PTR_ERR(tzd));
 		return tzd;
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index d590d24..4e5546e 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -354,7 +354,13 @@
 	mutex_lock(&hw->access_lock);
 	for_each_cpu(cpu_idx, &hw->core_map) {
 		if (cpu_idx == cpu)
-			hw->cdev_data[idx].max_freq = freq;
+		/*
+		 * If there is no limits restriction for CPU scaling max
+		 * frequency, vote for a very high value. This will allow
+		 * the CPU to use the boost frequencies.
+		 */
+			hw->cdev_data[idx].max_freq =
+				(freq == hw->max_freq) ? U32_MAX : freq;
 		if (max_freq > hw->cdev_data[idx].max_freq)
 			max_freq = hw->cdev_data[idx].max_freq;
 		idx++;
diff --git a/drivers/thermal/qcom/qmi_cooling.c b/drivers/thermal/qcom/qmi_cooling.c
index af82030..e1a01d8 100644
--- a/drivers/thermal/qcom/qmi_cooling.c
+++ b/drivers/thermal/qcom/qmi_cooling.c
@@ -85,6 +85,10 @@
 		.type = QMI_CDEV_MAX_LIMIT_TYPE,
 	},
 	{
+		.dev_name = "modem_skin",
+		.type = QMI_CDEV_MAX_LIMIT_TYPE,
+	},
+	{
 		.dev_name = "modem_bw",
 		.type = QMI_CDEV_MAX_LIMIT_TYPE,
 	},
diff --git a/drivers/thermal/qcom/qti_virtual_sensor.c b/drivers/thermal/qcom/qti_virtual_sensor.c
index 923680a..8cb7dc3 100644
--- a/drivers/thermal/qcom/qti_virtual_sensor.c
+++ b/drivers/thermal/qcom/qti_virtual_sensor.c
@@ -46,6 +46,24 @@
 				"cpu3-gold-usr"},
 		.logic = VIRT_MAXIMUM,
 	},
+	{
+		.virt_zone_name = "hexa-silv-max-step",
+		.num_sensors = 6,
+		.sensor_names = {"cpu0-silver-usr",
+				"cpu1-silver-usr",
+				"cpu2-silver-usr",
+				"cpu3-silver-usr",
+				"cpu4-silver-usr",
+				"cpu5-silver-usr"},
+		.logic = VIRT_MAXIMUM,
+	},
+	{
+		.virt_zone_name = "dual-gold-max-step",
+		.num_sensors = 2,
+		.sensor_names = {"cpu0-gold-usr",
+				"cpu1-gold-usr"},
+		.logic = VIRT_MAXIMUM,
+	},
 };
 
 int qti_virtual_sensor_register(struct device *dev)
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index f9054cb..c5e2703 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -98,7 +98,9 @@
 #define UART_PARAM		(0x1)
 
 /* UART DMA Rx GP_IRQ_BITS */
-#define UART_DMA_RX_ERRS	(GENMASK(5, 8))
+#define UART_DMA_RX_PARITY_ERR	BIT(5)
+#define UART_DMA_RX_ERRS	(GENMASK(5, 6))
+#define UART_DMA_RX_BREAK	(GENMASK(7, 8))
 
 #define UART_OVERSAMPLING	(32)
 #define STALE_TIMEOUT		(16)
@@ -125,6 +127,7 @@
 } while (0)
 
 #define DMA_RX_BUF_SIZE		(2048)
+#define CONSOLE_YIELD_LEN	(8 * 1024)
 struct msm_geni_serial_port {
 	struct uart_port uport;
 	char name[20];
@@ -141,7 +144,8 @@
 	int (*handle_rx)(struct uart_port *uport,
 			unsigned int rx_fifo_wc,
 			unsigned int rx_last_byte_valid,
-			unsigned int rx_last);
+			unsigned int rx_last,
+			bool drop_rx);
 	struct device *wrapper_dev;
 	struct se_geni_rsc serial_rsc;
 	dma_addr_t tx_dma;
@@ -159,6 +163,7 @@
 	unsigned int cur_baud;
 	int ioctl_count;
 	int edge_count;
+	unsigned int tx_yield_count;
 };
 
 static const struct uart_ops msm_geni_serial_pops;
@@ -167,11 +172,13 @@
 static int handle_rx_console(struct uart_port *uport,
 			unsigned int rx_fifo_wc,
 			unsigned int rx_last_byte_valid,
-			unsigned int rx_last);
+			unsigned int rx_last,
+			bool drop_rx);
 static int handle_rx_hs(struct uart_port *uport,
 			unsigned int rx_fifo_wc,
 			unsigned int rx_last_byte_valid,
-			unsigned int rx_last);
+			unsigned int rx_last,
+			bool drop_rx);
 static unsigned int msm_geni_serial_tx_empty(struct uart_port *port);
 static int msm_geni_serial_power_on(struct uart_port *uport);
 static void msm_geni_serial_power_off(struct uart_port *uport);
@@ -681,7 +688,8 @@
 static int handle_rx_console(struct uart_port *uport,
 			unsigned int rx_fifo_wc,
 			unsigned int rx_last_byte_valid,
-			unsigned int rx_last)
+			unsigned int rx_last,
+			bool drop_rx)
 {
 	int i, c;
 	unsigned char *rx_char;
@@ -694,6 +702,8 @@
 
 		*(msm_port->rx_fifo) =
 			geni_read_reg_nolog(uport->membase, SE_GENI_RX_FIFOn);
+		if (drop_rx)
+			continue;
 		rx_char = (unsigned char *)msm_port->rx_fifo;
 
 		if (i == (rx_fifo_wc - 1)) {
@@ -710,14 +720,16 @@
 				tty_insert_flip_char(tport, rx_char[c], flag);
 		}
 	}
-	tty_flip_buffer_push(tport);
+	if (!drop_rx)
+		tty_flip_buffer_push(tport);
 	return 0;
 }
 #else
 static int handle_rx_console(struct uart_port *uport,
 			unsigned int rx_fifo_wc,
 			unsigned int rx_last_byte_valid,
-			unsigned int rx_last)
+			unsigned int rx_last,
+			bool drop_rx)
 {
 	return -EPERM;
 }
@@ -1001,7 +1013,8 @@
 static int handle_rx_hs(struct uart_port *uport,
 			unsigned int rx_fifo_wc,
 			unsigned int rx_last_byte_valid,
-			unsigned int rx_last)
+			unsigned int rx_last,
+			bool drop_rx)
 {
 	unsigned char *rx_char;
 	struct tty_port *tport;
@@ -1016,6 +1029,8 @@
 	tport = &uport->state->port;
 	ioread32_rep((uport->membase + SE_GENI_RX_FIFOn), msm_port->rx_fifo,
 								rx_fifo_wc);
+	if (drop_rx)
+		return 0;
 
 	rx_char = (unsigned char *)msm_port->rx_fifo;
 	ret = tty_insert_flip_string(tport, rx_char, rx_bytes);
@@ -1031,7 +1046,7 @@
 	return ret;
 }
 
-static int msm_geni_serial_handle_rx(struct uart_port *uport)
+static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx)
 {
 	int ret = 0;
 	unsigned int rx_fifo_status;
@@ -1050,7 +1065,7 @@
 	rx_last = rx_fifo_status & RX_LAST;
 	if (rx_fifo_wc)
 		port->handle_rx(uport, rx_fifo_wc, rx_last_byte_valid,
-								rx_last);
+							rx_last, drop_rx);
 	return ret;
 }
 
@@ -1070,6 +1085,14 @@
 
 	xmit->tail = (xmit->tail + msm_port->xmit_size) & (UART_XMIT_SIZE - 1);
 	msm_port->xmit_size = 0;
+	if (uart_console(uport) &&
+	    (uport->icount.tx - msm_port->tx_yield_count) > CONSOLE_YIELD_LEN) {
+		msm_port->tx_yield_count = uport->icount.tx;
+		msm_geni_serial_stop_tx(uport);
+		uart_write_wakeup(uport);
+		goto exit_handle_tx;
+	}
+
 	tx_fifo_status = geni_read_reg_nolog(uport->membase,
 					SE_GENI_TX_FIFO_STATUS);
 	if (uart_circ_empty(xmit) && !tx_fifo_status) {
@@ -1128,13 +1151,13 @@
 	} else {
 		msm_port->xmit_size = xmit_size;
 	}
+exit_handle_tx:
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(uport);
-exit_handle_tx:
 	return ret;
 }
 
-static int msm_geni_serial_handle_dma_rx(struct uart_port *uport)
+static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
 {
 	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
 	unsigned int rx_bytes = 0;
@@ -1160,6 +1183,8 @@
 					__func__, rx_bytes);
 		goto exit_handle_dma_rx;
 	}
+	if (drop_rx)
+		goto exit_handle_dma_rx;
 
 	tport = &uport->state->port;
 	ret = tty_insert_flip_string(tport, (unsigned char *)(msm_port->rx_buf),
@@ -1211,6 +1236,7 @@
 	unsigned long flags;
 	unsigned int m_irq_en;
 	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+	bool drop_rx = false;
 
 	spin_lock_irqsave(&uport->lock, flags);
 	if (uart_console(uport) && uport->suspended)
@@ -1239,21 +1265,29 @@
 	}
 
 	if (!dma) {
-		if ((s_irq_status & S_GP_IRQ_0_EN) ||
-			(s_irq_status & S_GP_IRQ_1_EN) ||
-			(s_irq_status & S_GP_IRQ_2_EN) ||
-			(s_irq_status & S_GP_IRQ_3_EN)) {
-			IPC_LOG_MSG(msm_port->ipc_log_misc,
-				"%s.sirq 0x%x.\n", __func__, s_irq_status);
-			goto exit_geni_serial_isr;
-		}
-		if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
-			(s_irq_status & S_RX_FIFO_LAST_EN))
-			msm_geni_serial_handle_rx(uport);
-
 		if ((m_irq_status & m_irq_en) &
 		    (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
 			msm_geni_serial_handle_tx(uport);
+
+		if ((s_irq_status & S_GP_IRQ_0_EN) ||
+			(s_irq_status & S_GP_IRQ_1_EN)) {
+			if (s_irq_status & S_GP_IRQ_0_EN)
+				uport->icount.parity++;
+			IPC_LOG_MSG(msm_port->ipc_log_misc,
+				"%s.sirq 0x%x parity:%d\n",
+				__func__, s_irq_status, uport->icount.parity);
+			drop_rx = true;
+		} else if ((s_irq_status & S_GP_IRQ_2_EN) ||
+			(s_irq_status & S_GP_IRQ_3_EN)) {
+			uport->icount.brk++;
+			IPC_LOG_MSG(msm_port->ipc_log_misc,
+				"%s.sirq 0x%x break:%d\n",
+				__func__, s_irq_status, uport->icount.brk);
+		}
+
+		if ((s_irq_status & S_RX_FIFO_WATERMARK_EN) ||
+			(s_irq_status & S_RX_FIFO_LAST_EN))
+			msm_geni_serial_handle_rx(uport, drop_rx);
 	} else {
 		if (dma_tx_status) {
 			geni_write_reg_nolog(dma_tx_status, uport->membase,
@@ -1272,13 +1306,22 @@
 				goto exit_geni_serial_isr;
 			}
 			if (dma_rx_status & UART_DMA_RX_ERRS) {
+				if (dma_rx_status & UART_DMA_RX_PARITY_ERR)
+					uport->icount.parity++;
 				IPC_LOG_MSG(msm_port->ipc_log_misc,
-					"%s.Rx Errors.  0x%x.\n",
-						__func__, dma_rx_status);
-				goto exit_geni_serial_isr;
+					"%s.Rx Errors.  0x%x parity:%d\n",
+					__func__, dma_rx_status,
+					uport->icount.parity);
+				drop_rx = true;
+			} else if (dma_rx_status & UART_DMA_RX_BREAK) {
+				uport->icount.brk++;
+				IPC_LOG_MSG(msm_port->ipc_log_misc,
+					"%s.Rx Errors.  0x%x break:%d\n",
+					__func__, dma_rx_status,
+					uport->icount.brk);
 			}
 			if (dma_rx_status & RX_DMA_DONE)
-				msm_geni_serial_handle_dma_rx(uport);
+				msm_geni_serial_handle_dma_rx(uport, drop_rx);
 		}
 	}
 
diff --git a/drivers/usb/gadget/function/f_ccid.h b/drivers/usb/gadget/function/f_ccid.h
index 42a7ebb..935308c 100644
--- a/drivers/usb/gadget/function/f_ccid.h
+++ b/drivers/usb/gadget/function/f_ccid.h
@@ -55,29 +55,29 @@
 #define CCID_READ_DTR		_IOR('C', 3, int)
 
 struct usb_ccid_notification {
-	unsigned char buf[4];
+	__u8 buf[4];
 } __packed;
 
 struct ccid_bulk_in_header {
-	unsigned char bMessageType;
-	unsigned long wLength;
-	unsigned char bSlot;
-	unsigned char bSeq;
-	unsigned char bStatus;
-	unsigned char bError;
-	unsigned char bSpecific;
-	unsigned char abData[ABDATA_SIZE];
-	unsigned char bSizeToSend;
+	__u8 bMessageType;
+	__u32 wLength;
+	__u8 bSlot;
+	__u8 bSeq;
+	__u8 bStatus;
+	__u8 bError;
+	__u8 bSpecific;
+	__u8 abData[ABDATA_SIZE];
+	__u8 bSizeToSend;
 } __packed;
 
 struct ccid_bulk_out_header {
-	unsigned char bMessageType;
-	unsigned long wLength;
-	unsigned char bSlot;
-	unsigned char bSeq;
-	unsigned char bSpecific_0;
-	unsigned char bSpecific_1;
-	unsigned char bSpecific_2;
-	unsigned char APDU[ABDATA_SIZE];
+	__u8 bMessageType;
+	__u32 wLength;
+	__u8 bSlot;
+	__u8 bSeq;
+	__u8 bSpecific_0;
+	__u8 bSpecific_1;
+	__u8 bSpecific_2;
+	__u8 APDU[ABDATA_SIZE];
 } __packed;
 #endif
diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c
index e908ecf..be22de048 100644
--- a/drivers/usb/gadget/function/f_diag.c
+++ b/drivers/usb/gadget/function/f_diag.c
@@ -386,9 +386,11 @@
 	ch->priv = priv;
 	ch->notify = notify;
 
-	spin_lock_irqsave(&ch_lock, flags);
-	list_add_tail(&ch->list, &usb_diag_ch_list);
-	spin_unlock_irqrestore(&ch_lock, flags);
+	if (!found) {
+		spin_lock_irqsave(&ch_lock, flags);
+		list_add_tail(&ch->list, &usb_diag_ch_list);
+		spin_unlock_irqrestore(&ch_lock, flags);
+	}
 
 	return ch;
 }
@@ -863,6 +865,7 @@
 	struct diag_context *dev;
 	struct usb_diag_ch *_ch;
 	int found = 0;
+	unsigned long flags;
 
 	pr_debug("%s\n", __func__);
 
@@ -872,9 +875,19 @@
 			break;
 		}
 	}
+
 	if (!found) {
-		pr_err("%s: unable to get diag usb channel\n", __func__);
-		return ERR_PTR(-ENODEV);
+		pr_warn("%s: unable to get diag usb channel\n", __func__);
+
+		_ch = kzalloc(sizeof(*_ch), GFP_KERNEL);
+		if (_ch == NULL)
+			return ERR_PTR(-ENOMEM);
+
+		_ch->name = name;
+
+		spin_lock_irqsave(&ch_lock, flags);
+		list_add_tail(&_ch->list, &usb_diag_ch_list);
+		spin_unlock_irqrestore(&ch_lock, flags);
 	}
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 5a96299..e8961b5 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -430,6 +430,7 @@
 	int			num_svids;
 	struct vdm_tx		*vdm_tx;
 	struct vdm_tx		*vdm_tx_retry;
+	struct mutex		svid_handler_lock;
 	struct list_head	svid_handlers;
 
 	struct list_head	instance;
@@ -581,10 +582,15 @@
 {
 	struct usbpd_svid_handler *handler;
 
-	list_for_each_entry(handler, &pd->svid_handlers, entry)
-		if (svid == handler->svid)
+	mutex_lock(&pd->svid_handler_lock);
+	list_for_each_entry(handler, &pd->svid_handlers, entry) {
+		if (svid == handler->svid) {
+			mutex_unlock(&pd->svid_handler_lock);
 			return handler;
+		}
+	}
 
+	mutex_unlock(&pd->svid_handler_lock);
 	return NULL;
 }
 
@@ -1412,9 +1418,11 @@
 		return -EINVAL;
 	}
 
-	usbpd_dbg(&pd->dev, "registered handler for SVID 0x%04x\n", hdlr->svid);
-
+	usbpd_dbg(&pd->dev, "registered handler(%pK) for SVID 0x%04x\n",
+							hdlr, hdlr->svid);
+	mutex_lock(&pd->svid_handler_lock);
 	list_add_tail(&hdlr->entry, &pd->svid_handlers);
+	mutex_unlock(&pd->svid_handler_lock);
 	hdlr->request_usb_ss_lane = usbpd_release_ss_lane;
 
 	/* already connected with this SVID discovered? */
@@ -1436,7 +1444,12 @@
 
 void usbpd_unregister_svid(struct usbpd *pd, struct usbpd_svid_handler *hdlr)
 {
+
+	usbpd_dbg(&pd->dev, "unregistered handler(%pK) for SVID 0x%04x\n",
+							hdlr, hdlr->svid);
+	mutex_lock(&pd->svid_handler_lock);
 	list_del_init(&hdlr->entry);
+	mutex_unlock(&pd->svid_handler_lock);
 }
 EXPORT_SYMBOL(usbpd_unregister_svid);
 
@@ -1747,6 +1760,7 @@
 {
 	struct usbpd_svid_handler *handler;
 
+	mutex_lock(&pd->svid_handler_lock);
 	list_for_each_entry(handler, &pd->svid_handlers, entry) {
 		if (handler->discovered) {
 			handler->disconnect(handler);
@@ -1754,6 +1768,7 @@
 		}
 	}
 
+	mutex_unlock(&pd->svid_handler_lock);
 	pd->vdm_state = VDM_NONE;
 	kfree(pd->vdm_tx_retry);
 	pd->vdm_tx_retry = NULL;
@@ -3853,6 +3868,7 @@
 	hrtimer_init(&pd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	pd->timer.function = pd_timeout;
 	mutex_init(&pd->swap_lock);
+	mutex_init(&pd->svid_handler_lock);
 
 	pd->usb_psy = power_supply_get_by_name("usb");
 	if (!pd->usb_psy) {
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index 3ca2526..4443a29 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -24,6 +24,9 @@
 #define NMI_WATCHDOG_ENABLED      (1 << NMI_WATCHDOG_ENABLED_BIT)
 #define SOFT_WATCHDOG_ENABLED     (1 << SOFT_WATCHDOG_ENABLED_BIT)
 
+DECLARE_PER_CPU(unsigned long, hrtimer_interrupts);
+DECLARE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
+
 /**
  * touch_nmi_watchdog - restart NMI watchdog timeout.
  *
@@ -31,8 +34,11 @@
  * may be used to reset the timeout - for code which intentionally
  * disables interrupts for a long time. This call is stateless.
  */
-#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR_NMI)
 #include <asm/nmi.h>
+#endif
+
+#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR)
 extern void touch_nmi_watchdog(void);
 #else
 static inline void touch_nmi_watchdog(void)
@@ -130,6 +136,7 @@
 #define sysctl_softlockup_all_cpu_backtrace 0
 #define sysctl_hardlockup_all_cpu_backtrace 0
 #endif
+
 extern bool is_hardlockup(void);
 struct ctl_table;
 extern int proc_watchdog(struct ctl_table *, int ,
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 7c5b2b4..b6c8c92 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -199,6 +199,8 @@
 	POWER_SUPPLY_PROP_LOW_POWER,
 	POWER_SUPPLY_PROP_COOL_TEMP,
 	POWER_SUPPLY_PROP_WARM_TEMP,
+	POWER_SUPPLY_PROP_COLD_TEMP,
+	POWER_SUPPLY_PROP_HOT_TEMP,
 	POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
 	POWER_SUPPLY_PROP_RESISTANCE,
 	POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e1345ec..a4ea064 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -3964,4 +3964,6 @@
 void cpufreq_remove_update_util_hook(int cpu);
 #endif /* CONFIG_CPU_FREQ */
 
+extern DEFINE_PER_CPU_READ_MOSTLY(int, sched_load_boost);
+
 #endif
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 6eb24cc..a700e5f 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -47,7 +47,7 @@
 #define THERMAL_WEIGHT_DEFAULT 0
 
 /* Max sensors that can be used for a single virtual thermalzone */
-#define THERMAL_MAX_VIRT_SENSORS 5
+#define THERMAL_MAX_VIRT_SENSORS 8
 
 /* use value, which < 0K, to indicate an invalid/uninitialized temperature */
 #define THERMAL_TEMP_INVALID	-274000
diff --git a/include/linux/usb/ccid_desc.h b/include/linux/usb/ccid_desc.h
index 9a0c726..2e6dbb5 100644
--- a/include/linux/usb/ccid_desc.h
+++ b/include/linux/usb/ccid_desc.h
@@ -86,27 +86,27 @@
  * Table 5.1-1 Smart Card Device Class descriptors
  */
 struct usb_ccid_class_descriptor {
-	unsigned char  bLength;
-	unsigned char  bDescriptorType;
-	unsigned short bcdCCID;
-	unsigned char  bMaxSlotIndex;
-	unsigned char  bVoltageSupport;
-	unsigned long  dwProtocols;
-	unsigned long  dwDefaultClock;
-	unsigned long  dwMaximumClock;
-	unsigned char  bNumClockSupported;
-	unsigned long  dwDataRate;
-	unsigned long  dwMaxDataRate;
-	unsigned char  bNumDataRatesSupported;
-	unsigned long  dwMaxIFSD;
-	unsigned long  dwSynchProtocols;
-	unsigned long  dwMechanical;
-	unsigned long  dwFeatures;
-	unsigned long  dwMaxCCIDMessageLength;
-	unsigned char  bClassGetResponse;
-	unsigned char  bClassEnvelope;
-	unsigned short wLcdLayout;
-	unsigned char  bPINSupport;
-	unsigned char  bMaxCCIDBusySlots;
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u16 bcdCCID;
+	__u8  bMaxSlotIndex;
+	__u8  bVoltageSupport;
+	__u32  dwProtocols;
+	__u32  dwDefaultClock;
+	__u32  dwMaximumClock;
+	__u8  bNumClockSupported;
+	__u32  dwDataRate;
+	__u32  dwMaxDataRate;
+	__u8  bNumDataRatesSupported;
+	__u32  dwMaxIFSD;
+	__u32  dwSynchProtocols;
+	__u32  dwMechanical;
+	__u32  dwFeatures;
+	__u32  dwMaxCCIDMessageLength;
+	__u8  bClassGetResponse;
+	__u8  bClassEnvelope;
+	__u16 wLcdLayout;
+	__u8  bPINSupport;
+	__u8  bMaxCCIDBusySlots;
 } __packed;
 #endif
diff --git a/include/soc/qcom/memory_dump.h b/include/soc/qcom/memory_dump.h
index 50e4b8c..e67ee0e 100644
--- a/include/soc/qcom/memory_dump.h
+++ b/include/soc/qcom/memory_dump.h
@@ -83,6 +83,7 @@
 	MSM_DUMP_DATA_RPM = 0xEA,
 	MSM_DUMP_DATA_SCANDUMP = 0xEB,
 	MSM_DUMP_DATA_RPMH = 0xEC,
+	MSM_DUMP_DATA_POWER_REGS = 0xED,
 	MSM_DUMP_DATA_TMC_ETF = 0xF0,
 	MSM_DUMP_DATA_TMC_REG = 0x100,
 	MSM_DUMP_DATA_LOG_BUF = 0x110,
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 23a8ccf..fee26a9 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -23,6 +23,7 @@
 #define CAM_CCI_DEVICE_TYPE       (CAM_DEVICE_TYPE_BASE + 10)
 #define CAM_FLASH_DEVICE_TYPE     (CAM_DEVICE_TYPE_BASE + 11)
 #define CAM_EEPROM_DEVICE_TYPE    (CAM_DEVICE_TYPE_BASE + 12)
+#define CAM_OIS_DEVICE_TYPE       (CAM_DEVICE_TYPE_BASE + 13)
 
 /* cam_req_mgr hdl info */
 #define CAM_REQ_MGR_HDL_IDX_POS           8
diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h
index ac370ba..2fe7f2b 100644
--- a/include/uapi/media/cam_sensor.h
+++ b/include/uapi/media/cam_sensor.h
@@ -7,6 +7,7 @@
 
 #define CAM_SENSOR_PROBE_CMD   (CAM_COMMON_OPCODE_MAX + 1)
 #define CAM_FLASH_MAX_LED_TRIGGERS 3
+#define MAX_OIS_NAME_SIZE 32
 /**
  * struct cam_sensor_query_cap - capabilities info for sensor
  *
@@ -75,6 +76,16 @@
 } __attribute__((packed));
 
 /**
+ * struct cam_ois_query_cap_t - capabilities info for ois
+ *
+ * @slot_info                  :  Indicates about the slotId or cell Index
+ */
+struct cam_ois_query_cap_t {
+	uint32_t            slot_info;
+	uint16_t            reserved;
+} __attribute__((packed));
+
+/**
  * struct cam_cmd_i2c_info - Contains slave I2C related info
  *
  * @slave_addr      :    Slave address
@@ -88,6 +99,42 @@
 } __attribute__((packed));
 
 /**
+ * struct cam_ois_opcode - Contains OIS opcode
+ *
+ * @prog            :    OIS FW prog register address
+ * @coeff           :    OIS FW coeff register address
+ * @pheripheral     :    OIS pheripheral
+ * @memory          :    OIS memory
+ */
+struct cam_ois_opcode {
+	uint32_t prog;
+	uint32_t coeff;
+	uint32_t pheripheral;
+	uint32_t memory;
+} __attribute__((packed));
+
+/**
+ * struct cam_cmd_ois_info - Contains OIS slave info
+ *
+ * @slave_addr            :    OIS i2c slave address
+ * @i2c_freq_mode         :    i2c frequency mode
+ * @ois_fw_flag           :    indicates if fw is present or not
+ * @is_ois_calib          :    indicates the calibration data is available
+ * @ois_name              :    OIS name
+ * @opcode                :    opcode
+ * @cmd_type              :    Explains type of command
+ */
+struct cam_cmd_ois_info {
+	uint16_t              slave_addr;
+	uint8_t               i2c_freq_mode;
+	uint8_t               ois_fw_flag;
+	uint8_t               is_ois_calib;
+	char                  ois_name[MAX_OIS_NAME_SIZE];
+	struct cam_ois_opcode opcode;
+	uint8_t               cmd_type;
+} __attribute__((packed));
+
+/**
  * struct cam_cmd_probe - Contains sensor slave info
  *
  * @data_type       :   Slave register data type
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 4573d45..ccfb9bf 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3232,9 +3232,9 @@
 
 static inline
 unsigned long sum_capacity_reqs(unsigned long cfs_cap,
-				struct sched_capacity_reqs *scr)
+				struct sched_capacity_reqs *scr, int cpu)
 {
-	unsigned long total = add_capacity_margin(cfs_cap + scr->rt);
+	unsigned long total = add_capacity_margin(cfs_cap + scr->rt, cpu);
 	return total += scr->dl;
 }
 
@@ -3246,7 +3246,7 @@
 	struct sched_capacity_reqs *scr;
 
 	scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
-	if (sum_capacity_reqs(cpu_utilization, scr) < capacity_curr)
+	if (sum_capacity_reqs(cpu_utilization, scr, cpu) < capacity_curr)
 		return;
 
 	/*
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 116ffe4..c2372f8 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -84,6 +84,7 @@
 };
 
 static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu);
+static unsigned int stale_ns;
 
 /************************ Governor internals ***********************/
 
@@ -364,7 +365,7 @@
 		 * idle now (and clear iowait_boost for it).
 		 */
 		delta_ns = last_freq_update_time - j_sg_cpu->last_update;
-		if (delta_ns > sched_ravg_window) {
+		if (delta_ns > stale_ns) {
 			j_sg_cpu->iowait_boost = 0;
 			continue;
 		}
@@ -716,6 +717,7 @@
 
 	policy->governor_data = sg_policy;
 	sg_policy->tunables = tunables;
+	stale_ns = sched_ravg_window + (sched_ravg_window >> 3);
 
 	ret = kobject_init_and_add(&tunables->attr_set.kobj, &sugov_tunables_ktype,
 				   get_governor_parent_kobj(policy), "%s",
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index fde0639..38fa781 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -89,6 +89,7 @@
 unsigned int sysctl_sched_sync_hint_enable = 1;
 unsigned int sysctl_sched_initial_task_util = 0;
 unsigned int sysctl_sched_cstate_aware = 1;
+DEFINE_PER_CPU_READ_MOSTLY(int, sched_load_boost);
 
 #ifdef CONFIG_SCHED_WALT
 unsigned int sysctl_sched_use_walt_cpu_util = 1;
@@ -7043,7 +7044,7 @@
 			cpu_idle_idx = idle_get_state_idx(cpu_rq(i));
 
 			if (!need_idle &&
-			    add_capacity_margin(new_util_cum) <
+			    add_capacity_margin(new_util_cum, i) <
 			    capacity_curr_of(i)) {
 				if (sysctl_sched_cstate_aware) {
 					if (cpu_idle_idx < min_idle_idx) {
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 6b935e7..1bc4828 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1811,7 +1811,7 @@
 					cpu_idle_idx =
 					     idle_get_state_idx(cpu_rq(cpu));
 
-				if (add_capacity_margin(new_util_cum) <
+				if (add_capacity_margin(new_util_cum, cpu) <
 				    capacity_curr_of(cpu)) {
 					if (cpu_idle_idx < best_cpu_idle_idx ||
 					    (best_cpu != task_cpu(task) &&
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 72b79bb..0a1e62f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -29,6 +29,7 @@
 
 #ifdef CONFIG_SCHED_WALT
 extern unsigned int sched_ravg_window;
+extern unsigned int walt_cpu_util_freq_divisor;
 
 struct walt_sched_stats {
 	int nr_big_tasks;
@@ -1805,47 +1806,87 @@
 #endif
 
 static inline unsigned long
-cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+cpu_util_freq_pelt(int cpu)
 {
 	struct rq *rq = cpu_rq(cpu);
-	u64 util = rq->cfs.avg.util_avg;
+	unsigned long util = rq->cfs.avg.util_avg;
 	unsigned long capacity = capacity_orig_of(cpu);
 
-#ifdef CONFIG_SCHED_WALT
-	if (!walt_disabled && sysctl_sched_use_walt_cpu_util) {
+	util *= (100 + per_cpu(sched_load_boost, cpu));
+	do_div(util, 100);
 
-		util = freq_policy_load(rq);
-		util = div64_u64(util,
-				 sched_ravg_window >> SCHED_CAPACITY_SHIFT);
-
-		if (walt_load) {
-			u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum +
-				rq->grp_time.nt_prev_runnable_sum;
-			u64 pl = rq->walt_stats.pred_demands_sum;
-
-			nl = div64_u64(nl, sched_ravg_window >>
-						SCHED_CAPACITY_SHIFT);
-			pl = div64_u64(pl, sched_ravg_window >>
-						SCHED_CAPACITY_SHIFT);
-
-			walt_load->prev_window_util = util;
-			walt_load->nl = nl;
-			walt_load->pl = pl;
-			rq->old_busy_time = util;
-			rq->old_estimated_time = pl;
-			walt_load->ws = rq->window_start;
-		}
-	}
-#endif
 	return (util >= capacity) ? capacity : util;
 }
+
+#ifdef CONFIG_SCHED_WALT
+static inline unsigned long
+cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+	u64 util, util_unboosted;
+	struct rq *rq = cpu_rq(cpu);
+	unsigned long capacity = capacity_orig_of(cpu);
+	int boost;
+
+	if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
+		return cpu_util_freq_pelt(cpu);
+
+	boost = per_cpu(sched_load_boost, cpu);
+	util_unboosted = util = freq_policy_load(rq);
+	util = div64_u64(util * (100 + boost),
+			 walt_cpu_util_freq_divisor);
+
+	if (walt_load) {
+		u64 nl = cpu_rq(cpu)->nt_prev_runnable_sum +
+			rq->grp_time.nt_prev_runnable_sum;
+		u64 pl = rq->walt_stats.pred_demands_sum;
+
+		/* do_pl_notif() needs unboosted signals */
+		rq->old_busy_time = div64_u64(util_unboosted,
+					      sched_ravg_window >>
+					      SCHED_CAPACITY_SHIFT);
+		rq->old_estimated_time = div64_u64(pl, sched_ravg_window >>
+						       SCHED_CAPACITY_SHIFT);
+
+		nl = div64_u64(nl * (100 + boost),
+			       walt_cpu_util_freq_divisor);
+		pl = div64_u64(pl * (100 + boost),
+			       walt_cpu_util_freq_divisor);
+
+		walt_load->prev_window_util = util;
+		walt_load->nl = nl;
+		walt_load->pl = pl;
+		walt_load->ws = rq->window_start;
+	}
+
+	return (util >= capacity) ? capacity : util;
+}
+
+static inline unsigned long
+cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+	return cpu_util_freq_walt(cpu, walt_load);
+}
+
+#else
+
+static inline unsigned long
+cpu_util_freq(int cpu, struct sched_walt_cpu_load *walt_load)
+{
+	return cpu_util_freq_pelt(cpu);
+}
+
+#endif /* CONFIG_SCHED_WALT */
+
 #endif
 
 extern unsigned int capacity_margin_freq;
 
-static inline unsigned long add_capacity_margin(unsigned long cpu_capacity)
+static inline unsigned long
+add_capacity_margin(unsigned long cpu_capacity, int cpu)
 {
-	cpu_capacity  = cpu_capacity * capacity_margin_freq;
+	cpu_capacity  = cpu_capacity * capacity_margin_freq *
+			(100 + per_cpu(sched_load_boost, cpu));
+	cpu_capacity /= 100;
 	cpu_capacity /= SCHED_CAPACITY_SCALE;
 	return cpu_capacity;
 }
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index 60249e4..316c276 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -109,6 +109,12 @@
 /* Window size (in ns) */
 __read_mostly unsigned int sched_ravg_window = MIN_SCHED_RAVG_WINDOW;
 
+/*
+ * A after-boot constant divisor for cpu_util_freq_walt() to apply the load
+ * boost.
+ */
+__read_mostly unsigned int walt_cpu_util_freq_divisor;
+
 /* Initial task load. Newly created tasks are assigned this load. */
 unsigned int __read_mostly sched_init_task_load_windows;
 unsigned int __read_mostly sysctl_sched_init_task_load_pct = 15;
@@ -3107,4 +3113,7 @@
 		clear_top_tasks_bitmap(rq->top_tasks_bitmap[j]);
 	}
 	rq->cum_window_demand = 0;
+
+	walt_cpu_util_freq_divisor =
+	    (sched_ravg_window >> SCHED_CAPACITY_SHIFT) * 100;
 }
diff --git a/kernel/smp.c b/kernel/smp.c
index ee80cc8..313d9a8 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -15,6 +15,7 @@
 #include <linux/cpu.h>
 #include <linux/sched.h>
 #include <linux/hypervisor.h>
+#include <linux/suspend.h>
 
 #include "smpboot.h"
 
@@ -751,7 +752,8 @@
 	for_each_online_cpu(cpu) {
 		if (cpu == smp_processor_id())
 			continue;
-		if (!cpu_isolated(cpu))
+		if (suspend_freeze_state == FREEZE_STATE_ENTER ||
+		    !cpu_isolated(cpu))
 			wake_up_if_idle(cpu);
 	}
 	preempt_enable();
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index e671a32..843fb50 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -201,6 +201,7 @@
 	bool			migration_enabled;
 	bool			nohz_active;
 	bool			is_idle;
+	bool			must_forward_clk;
 	DECLARE_BITMAP(pending_map, WHEEL_SIZE);
 	struct hlist_head	vectors[WHEEL_SIZE];
 } ____cacheline_aligned;
@@ -874,13 +875,19 @@
 
 static inline void forward_timer_base(struct timer_base *base)
 {
-	unsigned long jnow = READ_ONCE(jiffies);
+	unsigned long jnow;
 
 	/*
-	 * We only forward the base when it's idle and we have a delta between
-	 * base clock and jiffies.
+	 * We only forward the base when we are idle or have just come out of
+	 * idle (must_forward_clk logic), and have a delta between base clock
+	 * and jiffies. In the common case, run_timers will take care of it.
 	 */
-	if (!base->is_idle || (long) (jnow - base->clk) < 2)
+	if (likely(!base->must_forward_clk))
+		return;
+
+	jnow = READ_ONCE(jiffies);
+	base->must_forward_clk = base->is_idle;
+	if ((long)(jnow - base->clk) < 2)
 		return;
 
 	/*
@@ -956,6 +963,11 @@
 	 * same array bucket then just return:
 	 */
 	if (timer_pending(timer)) {
+		/*
+		 * The downside of this optimization is that it can result in
+		 * larger granularity than you would get from adding a new
+		 * timer with this expiry.
+		 */
 		if (timer->expires == expires)
 			return 1;
 
@@ -966,6 +978,7 @@
 		 * dequeue/enqueue dance.
 		 */
 		base = lock_timer_base(timer, &flags);
+		forward_timer_base(base);
 
 		clk = base->clk;
 		idx = calc_wheel_index(expires, clk);
@@ -982,6 +995,7 @@
 		}
 	} else {
 		base = lock_timer_base(timer, &flags);
+		forward_timer_base(base);
 	}
 
 	ret = detach_if_pending(timer, base, false);
@@ -1009,12 +1023,10 @@
 			spin_lock(&base->lock);
 			WRITE_ONCE(timer->flags,
 				   (timer->flags & ~TIMER_BASEMASK) | base->cpu);
+			forward_timer_base(base);
 		}
 	}
 
-	/* Try to forward a stale timer base clock */
-	forward_timer_base(base);
-
 	timer->expires = expires;
 	/*
 	 * If 'idx' was calculated above and the base time did not advance
@@ -1130,6 +1142,7 @@
 		WRITE_ONCE(timer->flags,
 			   (timer->flags & ~TIMER_BASEMASK) | cpu);
 	}
+	forward_timer_base(base);
 
 	debug_activate(timer, timer->expires);
 	internal_add_timer(base, timer);
@@ -1546,10 +1559,16 @@
 		if (!is_max_delta)
 			expires = basem + (nextevt - basej) * TICK_NSEC;
 		/*
-		 * If we expect to sleep more than a tick, mark the base idle:
+		 * If we expect to sleep more than a tick, mark the base idle.
+		 * Also the tick is stopped so any added timer must forward
+		 * the base clk itself to keep granularity small. This idle
+		 * logic is only maintained for the BASE_STD base, deferrable
+		 * timers may still see large granularity skew (by design).
 		 */
-		if ((expires - basem) > TICK_NSEC)
+		if ((expires - basem) > TICK_NSEC) {
+			base->must_forward_clk = true;
 			base->is_idle = true;
+		}
 	}
 	spin_unlock(&base->lock);
 
@@ -1659,6 +1678,19 @@
 {
 	struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
 
+	/*
+	 * must_forward_clk must be cleared before running timers so that any
+	 * timer functions that call mod_timer will not try to forward the
+	 * base. idle trcking / clock forwarding logic is only used with
+	 * BASE_STD timers.
+	 *
+	 * The deferrable base does not do idle tracking at all, so we do
+	 * not forward it. This can result in very large variations in
+	 * granularity for deferrable timers, but they can be deferred for
+	 * long periods due to idle.
+	 */
+	base->must_forward_clk = false;
+
 	__run_timers(base);
 	if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active)
 		__run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index cffb5f2..cfbf027 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -81,10 +81,10 @@
 static DEFINE_PER_CPU(unsigned int, watchdog_en);
 static DEFINE_PER_CPU(bool, softlockup_touch_sync);
 static DEFINE_PER_CPU(bool, soft_watchdog_warn);
-static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
 static DEFINE_PER_CPU(unsigned long, soft_lockup_hrtimer_cnt);
 static DEFINE_PER_CPU(struct task_struct *, softlockup_task_ptr_saved);
-static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
+DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
+DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static unsigned long soft_lockup_nmi_warn;
 
 unsigned int __read_mostly softlockup_panic =
@@ -254,6 +254,10 @@
 {
 }
 
+void __weak watchdog_check_hardlockup_other_cpu(void)
+{
+}
+
 static int watchdog_enable_all_cpus(void);
 static void watchdog_disable_all_cpus(void);
 
@@ -271,6 +275,9 @@
 	/* kick the hardlockup detector */
 	watchdog_interrupt_count();
 
+	/* test for hardlockups on the next cpu */
+	watchdog_check_hardlockup_other_cpu();
+
 	/* kick the softlockup detector */
 	wake_up_process(__this_cpu_read(softlockup_watchdog));
 
diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c
index 12b8dd6..5b2c127 100644
--- a/kernel/watchdog_hld.c
+++ b/kernel/watchdog_hld.c
@@ -18,7 +18,11 @@
 
 static DEFINE_PER_CPU(bool, hard_watchdog_warn);
 static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
+static cpumask_t __read_mostly watchdog_cpus;
+#else
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
+#endif
 
 /* boot commands */
 /*
@@ -26,7 +30,10 @@
  */
 unsigned int __read_mostly hardlockup_panic =
 			CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
 static unsigned long hardlockup_allcpu_dumped;
+#endif
 /*
  * We may not want to enable hard lockup detection by default in all cases,
  * for example when running the kernel as a guest on a hypervisor. In these
@@ -68,6 +75,108 @@
 }
 EXPORT_SYMBOL(touch_nmi_watchdog);
 
+#ifdef CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU
+static unsigned int watchdog_next_cpu(unsigned int cpu)
+{
+	cpumask_t cpus = watchdog_cpus;
+	unsigned int next_cpu;
+
+	next_cpu = cpumask_next(cpu, &cpus);
+	if (next_cpu >= nr_cpu_ids)
+		next_cpu = cpumask_first(&cpus);
+
+	if (next_cpu == cpu)
+		return nr_cpu_ids;
+
+	return next_cpu;
+}
+
+static int is_hardlockup_other_cpu(unsigned int cpu)
+{
+	unsigned long hrint = per_cpu(hrtimer_interrupts, cpu);
+
+	if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
+		return 1;
+
+	per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
+	return 0;
+}
+
+void watchdog_check_hardlockup_other_cpu(void)
+{
+	unsigned int next_cpu;
+
+	/*
+	 * Test for hardlockups every 3 samples.  The sample period is
+	 *  watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over
+	 *  watchdog_thresh (over by 20%).
+	 */
+	if (__this_cpu_read(hrtimer_interrupts) % 3 != 0)
+		return;
+
+	/* check for a hardlockup on the next cpu */
+	next_cpu = watchdog_next_cpu(smp_processor_id());
+	if (next_cpu >= nr_cpu_ids)
+		return;
+
+	smp_rmb();
+
+	if (per_cpu(watchdog_nmi_touch, next_cpu) == true) {
+		per_cpu(watchdog_nmi_touch, next_cpu) = false;
+		return;
+	}
+
+	if (is_hardlockup_other_cpu(next_cpu)) {
+		/* only warn once */
+		if (per_cpu(hard_watchdog_warn, next_cpu) == true)
+			return;
+
+		if (hardlockup_panic)
+			panic("Watchdog detected hard LOCKUP on cpu %u",
+				next_cpu);
+		else
+			WARN(1, "Watchdog detected hard LOCKUP on cpu %u",
+				next_cpu);
+
+		per_cpu(hard_watchdog_warn, next_cpu) = true;
+	} else {
+		per_cpu(hard_watchdog_warn, next_cpu) = false;
+	}
+}
+
+int watchdog_nmi_enable(unsigned int cpu)
+{
+	/*
+	 * The new cpu will be marked online before the first hrtimer interrupt
+	 * runs on it.  If another cpu tests for a hardlockup on the new cpu
+	 * before it has run its first hrtimer, it will get a false positive.
+	 * Touch the watchdog on the new cpu to delay the first check for at
+	 * least 3 sampling periods to guarantee one hrtimer has run on the new
+	 * cpu.
+	 */
+	per_cpu(watchdog_nmi_touch, cpu) = true;
+	smp_wmb();
+	cpumask_set_cpu(cpu, &watchdog_cpus);
+	return 0;
+}
+
+void watchdog_nmi_disable(unsigned int cpu)
+{
+	unsigned int next_cpu = watchdog_next_cpu(cpu);
+
+	/*
+	 * Offlining this cpu will cause the cpu before this one to start
+	 * checking the one after this one.  If this cpu just finished checking
+	 * the next cpu and updating hrtimer_interrupts_saved, and then the
+	 * previous cpu checks it within one sample period, it will trigger a
+	 * false positive.  Touch the watchdog on the next cpu to prevent it.
+	 */
+	if (next_cpu < nr_cpu_ids)
+		per_cpu(watchdog_nmi_touch, next_cpu) = true;
+	smp_wmb();
+	cpumask_clear_cpu(cpu, &watchdog_cpus);
+}
+#else
 static struct perf_event_attr wd_hw_attr = {
 	.type		= PERF_TYPE_HARDWARE,
 	.config		= PERF_COUNT_HW_CPU_CYCLES,
@@ -228,3 +337,4 @@
 		cpu0_err = 0;
 	}
 }
+#endif
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2f9f7aa..411b383 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -779,11 +779,20 @@
 	  The frequency of hrtimer and NMI events and the soft and hard lockup
 	  thresholds can be controlled through the sysctl watchdog_thresh.
 
-config HARDLOCKUP_DETECTOR
+config HARDLOCKUP_DETECTOR_NMI
 	def_bool y
 	depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG
 	depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI
 
+config HARDLOCKUP_DETECTOR_OTHER_CPU
+       def_bool y
+       depends on LOCKUP_DETECTOR && SMP
+       depends on !HARDLOCKUP_DETECTOR_NMI && !HAVE_NMI_WATCHDOG
+
+config HARDLOCKUP_DETECTOR
+       def_bool y
+       depends on HARDLOCKUP_DETECTOR_NMI || HARDLOCKUP_DETECTOR_OTHER_CPU
+
 config BOOTPARAM_HARDLOCKUP_PANIC
 	bool "Panic (Reboot) On Hard Lockups"
 	depends on HARDLOCKUP_DETECTOR