Merge "msm: vidc: Add VP9 profile/level query support"
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index f4b6013..70f1148 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -143,6 +143,9 @@
 				rendering thread is running on masked CPUs.
 				Bit 0 is for CPU-0, bit 1 is for CPU-1...
 
+- qcom,l2pc-update-queue:
+				Disables L2PC on masked CPUs at queue time when it's true.
+
 - qcom,snapshot-size:
 				Specify the size of snapshot in bytes. This will override
 				snapshot size defined in the driver code.
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt
deleted file mode 100644
index ed1ddf5..0000000
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash.txt
+++ /dev/null
@@ -1,180 +0,0 @@
-Qualcomm Technologies PNP Flash LED
-
-QPNP (Qualcomm Technologies Plug N Play) Flash LED (Light
-Emitting Diode) driver is used to provide illumination to
-camera sensor when background light is dim to capture good
-picture. It can also be used for flashlight/torch application.
-It is part of PMIC on Qualcomm Technologies reference platforms.
-The PMIC is connected to the host processor via SPMI bus.
-
-Required properties:
-- compatible		: should be "qcom,qpnp-flash-led"
-- reg			: base address and size for flash LED modules
-
-Optional properties:
-- qcom,headroom		: headroom to use. Values should be 250, 300,
-			  400 and 500 in mV.
-- qcom,startup-dly	: delay before flashing after flash executed.
-			  Values should 10, 32, 64, and 128 in us.
-- qcom,clamp-curr	: current to clamp at when voltage droop happens.
-			  Values are in integer from 0 to 1000 inclusive,
-			  indicating 0 to 1000 mA.
-- qcom,self-check-enabled : boolean type. self fault check enablement
-- qcom,thermal-derate-enabled : boolean type. derate enablement when module
-				temperature reaches threshold
-- qcom,thermal-derate-threshold : thermal threshold for derate. Values
-				should be 95, 105, 115, 125 in C.
-- qcom,thermal-derate-rate	: derate rate when module temperature
-				reaches threshold. Values should be
-				"1_PERCENT", "1P25_PERCENT", "2_PERCENT",
-				"2P5_PERCENT", "5_PERCENT" in string.
-- qcom,current-ramp-enabled	: boolean type. stepped current ramp enablement
-- qcom,ramp-up-step		: current ramp up rate. Values should be
-				  "0P2US", "0P4US", "0P8US", "1P6US", "3P3US",
-				  "6P7US", "13P5US", "27US".
-- qcom,ramp-dn-step		: current ramp down rate. Values should be
-				  "0P2US", "0P4US", "0P8US", "1P6US", "3P3US",
-				  "6P7US", "13P5US", "27US".
-- qcom,vph-pwr-droop-enabled	: boolean type. VPH power droop enablement. Enablement
-				  allows current clamp when phone power drops below
-				  pre-determined threshold
-- qcom,vph-pwr-droop-threshold	: VPH power threshold for module to clamp current.
-				  Values are 2500 - 3200 in mV with 100 mV steps.
-- qcom,vph-pwr-droop-debounce-time : debounce time for module to confirm a voltage
-				     droop is happening. Values are 0, 10, 32, 64
-				     in us.
-- qcom,pmic-charger-support	: Boolean type. This tells if flash utilizes charger boost
-				  support
-- qcom,headroom-sense-ch0-enabled: Boolean type. This configures headroom sensing enablement
-				   for LED channel 0
-- qcom,headroom-sense-ch1-enabled: Boolean type. This configures headroom sensing enablement
-				   for LED channel 1
-- qcom,power-detect-enabled	: Boolean type. This enables driver to get maximum flash LED
-				  current at current battery level to avoid intensity clamp
-				  when battery voltage is low
-- qcom,otst2-moduled-enabled	: Boolean type. This enables driver to enable MASK to support
-				OTST2 connection.
-- qcom,follow-otst2-rb-disabled	: Boolean type. This allows driver to reset/deset module.
-				By default, driver resets module. This entry allows driver to
-				bypass reset module sequence.
-- qcom,die-current-derate-enabled: Boolean type. This enables driver to get maximum flash LED
-                                   current, based on PMIC die temperature threshold to
-				   avoid significant current derate from hardware. This property
-				   is not needed if PMIC is older than PMI8994v2.0.
-- qcom,die-temp-vadc		: VADC channel source for flash LED. This property is not
-				  needed if PMIC is older than PMI8994v2.0.
-- qcom,die-temp-threshold       : Integer type array for PMIC die temperature threshold.
-				  Array should have at least one value. Values should be in
-				  celcius. This property is not needed if PMIC is older than
-				  PMI8994v2.0.
-- qcom,die-temp-derate-current	: Integer type arrray for PMIC die temperature derate
-				  current. Array should have at least one value. Values
-				  should be in mA. This property is not needed if PMIC is older
-				  than PMI8994v2.0.
-
-Required properties inside child node. Chile node contains settings for each individual LED.
-Each LED hardware needs a node for itself and a switch node to control brightness.
-For the purpose of turning on/off LED and better regulator control, "led:switch" node
-is introduced. "led:switch" acquires several existing properties from other nodes for
-operational simplification. For backward compatibility purpose, switch node can be optional:
-- label			: type of led that will be used, either "flash" or "torch".
-- qcom,led-name		: name of the LED. Accepted values are "led:flash_0",
-			  "led:flash_1", "led:torch_0", "led:torch_1"
-- qcom,default-led-trigger	: trigger for the camera flash and torch. Accepted values are
-				"flash0_trigger", "flash1_trigger", "torch0_trigger", torch1_trigger"
-- qcom,id		: enumerated ID for each physical LED. Accepted values are "0",
-			  "1", etc..
-- qcom,max-current	: maximum current allowed on this LED. Valid values should be
-			  integer from 0 to 1000 inclusive, indicating 0 to 1000 mA.
-- qcom,pmic-revid	: PMIC revision id source. This property is needed for PMI8996
-			revision check.
-
-Optional properties inside child node:
-- qcom,current		: default current intensity for LED. Accepted values should be
-			  integer from 0 t 1000 inclusive, indicating 0 to 1000 mA.
-- qcom,duration	: Duration for flash LED. When duration time expires, hardware will turn off
-		flash LED. Values should be from 10 ms to 1280 ms with 10 ms incremental
-		step. Not applicable to torch. It is required for LED:SWITCH node to handle
-		LED used as flash.
-- reg<n>	: reg<n> (<n> represents number. eg 0,1,2,..) property is to add support for
-		multiple power sources. It includes two properties regulator-name and max-voltage.
-		Required property inside regulator node:
-		- regulator-name	: This denotes this node is a regulator node and which
-					regulator to use.
-		Optional property inside regulator node:
-		- max-voltage		: This specifies max voltage of regulator. Some switch
-					or boost regulator does not need this property.
-
-Example:
-	qcom,leds@d300 {
-		compatible = "qcom,qpnp-flash-led";
-		status = "okay";
-		reg = <0xd300 0x100>;
-		label = "flash";
-		qcom,headroom = <500>;
-		qcom,startup-dly = <128>;
-		qcom,clamp-curr = <200>;
-		qcom,pmic-charger-support;
-		qcom,self-check-enabled;
-		qcom,thermal-derate-enabled;
-		qcom,thermal-derate-threshold = <80>;
-		qcom,thermal-derate-rate = "4_PERCENT";
-		qcom,current-ramp-enabled;
-		qcom,ramp_up_step = "27US";
-		qcom,ramp_dn_step = "27US";
-		qcom,vph-pwr-droop-enabled;
-		qcom,vph-pwr-droop-threshold = <3200>;
-		qcom,vph-pwr-droop-debounce-time = <10>;
-		qcom,headroom-sense-ch0-enabled;
-		qcom,headroom-sense-ch1-enabled;
-		qcom,die-current-derate-enabled;
-		qcom,die-temp-vadc = <&pmi8994_vadc>;
-		qcom,die-temp-threshold = <85 80 75 70 65>;
-		qcom,die-temp-derate-current = <400 800 1200 1600 2000>;
-		qcom,pmic-revid = <&pmi8994_revid>;
-
-		pm8226_flash0: qcom,flash_0 {
-			label = "flash";
-			qcom,led-name = "led:flash_0";
-			qcom,default-led-trigger =
-					"flash0_trigger";
-			qcom,max-current = <1000>;
-			qcom,id = <0>;
-			qcom,duration = <1280>;
-			qcom,current = <625>;
-		};
-
-		pm8226_torch: qcom,torch_0 {
-			label = "torch";
-			qcom,led-name = "led:torch_0";
-			qcom,default-led-trigger =
-					"torch0_trigger";
-			boost-supply = <&pm8226_chg_boost>;
-			qcom,max-current = <200>;
-			qcom,id = <0>;
-			qcom,current = <120>;
-			qcom,max-current = <200>;
-			reg0 {
-				regulator-name =
-					 "pm8226_chg_boost";
-				max-voltage = <3600000>;
-			};
-		};
-
-		pm8226_switch: qcom,switch {
-			lable = "switch";
-			qcom,led-name = "led:switch";
-			qcom,default-led-trigger =
-					"switch_trigger";
-			qcom,id = <2>;
-			qcom,current = <625>;
-			qcom,duration = <1280>;
-			qcom,max-current = <1000>;
-			reg0 {
-				regulator-name =
-					"pm8226_chg_boost";
-				max-voltage = <3600000>;
-			};
-		};
-	};
-
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt
index dd8668c..8ee02bf 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-csiphy.txt
@@ -26,6 +26,9 @@
      reg-names = "csiphy";
      interrupts = <0 477 0>;
      interrupt-names = "csiphy";
+     regulator-names = "gdscr", "refgen";
+     gdscr-supply = <&titan_top_gdsc>;
+     refgen-supply = <&refgen>;
      clock-names = "camnoc_axi_clk", "soc_ahb_clk",
               "slow_ahb_src_clk", "cpas_ahb_clk",
               "cphy_rx_clk_src", "csiphy0_clk",
@@ -34,6 +37,5 @@
      clock-rates =
            <0 0 80000000 0 320000000 0 269333333 0 0 384000000>;
      clock-cntl-level = "turbo";
-     regulator-names = "gdscr";
      status = "ok";
 };
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
index 63da8ec..9798ac60 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
@@ -26,12 +26,10 @@
 	Value type: <prop-encoded-array>
 	Definition:  Base address of the LCDB SPMI peripheral.
 
-- qcom,force-module-reenable
-	Usage:      required if using SW mode for module enable
-	Value type:  <bool>
-	Definition: This enables the workaround to force enable
-		    the vph_pwr_2p5_ok signal required for
-		    turning on the LCDB module.
+- qcom,pmic-revid
+	Usage:      required
+	Value type: <phandle>
+	Definition:  Phandle to the PMIC's revid node
 
 Touch-to-wake (TTW) properties:
 
@@ -211,6 +209,12 @@
 	Definition:  Current limit (in mA) of the BOOST rail.
 		     Possible values are 200 to 1600mA in 200mA steps.
 
+- qcom,bst-headroom-mv
+	Usage:      optional
+	Value type:  <u16>
+	Definition:  Headroom of the boost (in mV). The minimum headroom is
+		     200mV and if not specified defaults to 200mV.
+
 =======
 Example
 =======
@@ -252,5 +256,6 @@
 		qcom,bst-pd-strength = <1>;
 		qcom,bst-ps = <1>;
 		qcom,bst-ps-threshold-ma = <50>;
+		qcom,bst-headroom-mv = <200>;
 	};
 };
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b5f9be7..6468b58 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -596,7 +596,7 @@
 # selected platforms.
 config ARCH_NR_GPIO
 	int
-	default 1024 if ARCH_QCOM
+	default 1280 if ARCH_QCOM
 	default 256
 	help
 	  Maximum number of GPIOs in the system.
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index ee7f735..c18ea56 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -44,9 +44,18 @@
 	sdm845-interposer-sdm670-cdp.dtb
 endif
 
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+	dtbo-$(CONFIG_ARCH_SDM670) += \
+		sdm670-cdp-overlay.dtbo \
+		sdm670-mtp-overlay.dtbo
+
+sdm670-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-mtp-overlay.dtbo-base := sdm670.dtb
+else
 dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
 	sdm670-mtp.dtb \
 	sdm670-cdp.dtb
+endif
 
 always		:= $(dtb-y)
 subdir-y	:= $(dts-dirs)
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
index ce849c6..d5dc94e 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi
@@ -27,7 +27,7 @@
 		qcom,mdss-dsi-lane-3-state;
 		qcom,mdss-dsi-dma-trigger = "trigger_sw";
 		qcom,mdss-dsi-mdp-trigger = "none";
-		qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>;
+		qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>;
 		qcom,mdss-pan-physical-width-dimension = <71>;
 		qcom,mdss-pan-physical-height-dimension = <129>;
 		qcom,mdss-dsi-te-pin-select = <1>;
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
index d3411c8..6a4200d 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi
@@ -27,7 +27,7 @@
 		qcom,mdss-dsi-lane-3-state;
 		qcom,mdss-dsi-dma-trigger = "trigger_sw";
 		qcom,mdss-dsi-mdp-trigger = "none";
-		qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>;
+		qcom,mdss-dsi-reset-sequence = <1 200>, <0 200>, <1 200>;
 		qcom,mdss-pan-physical-width-dimension = <71>;
 		qcom,mdss-pan-physical-height-dimension = <129>;
 		qcom,mdss-dsi-tx-eot-append;
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi
new file mode 100644
index 0000000..ceb6856
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi
@@ -0,0 +1,286 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+&mdss_mdp {
+	dsi_sim_dsc_375_cmd: qcom,mdss_dsi_sim_dsc_375_cmd {
+		qcom,mdss-dsi-panel-name =
+			"Simulator cmd mode DSC 3.75:1 dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,adjust-timer-wakeup-ms = <1>;
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-wd;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,panel-ack-disabled;
+
+		qcom,mdss-dsi-display-timings {
+			timing@0 {
+				qcom,mdss-dsi-panel-framerate = <60>;
+				qcom,mdss-dsi-panel-width = <1440>;
+				qcom,mdss-dsi-panel-height = <2560>;
+				qcom,mdss-dsi-h-front-porch = <100>;
+				qcom,mdss-dsi-h-back-porch = <32>;
+				qcom,mdss-dsi-h-pulse-width = <16>;
+				qcom,mdss-dsi-h-sync-skew = <0>;
+				qcom,mdss-dsi-v-back-porch = <8>;
+				qcom,mdss-dsi-v-front-porch = <10>;
+				qcom,mdss-dsi-v-pulse-width = <2>;
+				qcom,mdss-dsi-h-left-border = <0>;
+				qcom,mdss-dsi-h-right-border = <0>;
+				qcom,mdss-dsi-v-top-border = <0>;
+				qcom,mdss-dsi-v-bottom-border = <0>;
+				qcom,mdss-dsi-on-command = [
+					/* CMD2_P0 */
+					15 01 00 00 00 00 02 ff 20
+					15 01 00 00 00 00 02 fb 01
+					15 01 00 00 00 00 02 00 01
+					15 01 00 00 00 00 02 01 55
+					15 01 00 00 00 00 02 02 45
+					15 01 00 00 00 00 02 05 40
+					15 01 00 00 00 00 02 06 19
+					15 01 00 00 00 00 02 07 1e
+					15 01 00 00 00 00 02 0b 73
+					15 01 00 00 00 00 02 0c 73
+					15 01 00 00 00 00 02 0e b0
+					15 01 00 00 00 00 02 0f aE
+					15 01 00 00 00 00 02 11 b8
+					15 01 00 00 00 00 02 13 00
+					15 01 00 00 00 00 02 58 80
+					15 01 00 00 00 00 02 59 01
+					15 01 00 00 00 00 02 5a 00
+					15 01 00 00 00 00 02 5b 01
+					15 01 00 00 00 00 02 5c 80
+					15 01 00 00 00 00 02 5d 81
+					15 01 00 00 00 00 02 5e 00
+					15 01 00 00 00 00 02 5f 01
+					15 01 00 00 00 00 02 72 31
+					15 01 00 00 00 00 02 68 03
+					/* CMD2_P4 */
+					15 01 00 00 00 00 02 ff 24
+					15 01 00 00 00 00 02 fb 01
+					15 01 00 00 00 00 02 00 1c
+					15 01 00 00 00 00 02 01 0b
+					15 01 00 00 00 00 02 02 0c
+					15 01 00 00 00 00 02 03 01
+					15 01 00 00 00 00 02 04 0f
+					15 01 00 00 00 00 02 05 10
+					15 01 00 00 00 00 02 06 10
+					15 01 00 00 00 00 02 07 10
+					15 01 00 00 00 00 02 08 89
+					15 01 00 00 00 00 02 09 8a
+					15 01 00 00 00 00 02 0a 13
+					15 01 00 00 00 00 02 0b 13
+					15 01 00 00 00 00 02 0c 15
+					15 01 00 00 00 00 02 0d 15
+					15 01 00 00 00 00 02 0e 17
+					15 01 00 00 00 00 02 0f 17
+					15 01 00 00 00 00 02 10 1c
+					15 01 00 00 00 00 02 11 0b
+					15 01 00 00 00 00 02 12 0c
+					15 01 00 00 00 00 02 13 01
+					15 01 00 00 00 00 02 14 0f
+					15 01 00 00 00 00 02 15 10
+					15 01 00 00 00 00 02 16 10
+					15 01 00 00 00 00 02 17 10
+					15 01 00 00 00 00 02 18 89
+					15 01 00 00 00 00 02 19 8a
+					15 01 00 00 00 00 02 1a 13
+					15 01 00 00 00 00 02 1b 13
+					15 01 00 00 00 00 02 1c 15
+					15 01 00 00 00 00 02 1d 15
+					15 01 00 00 00 00 02 1e 17
+					15 01 00 00 00 00 02 1f 17
+					/* STV */
+					15 01 00 00 00 00 02 20 40
+					15 01 00 00 00 00 02 21 01
+					15 01 00 00 00 00 02 22 00
+					15 01 00 00 00 00 02 23 40
+					15 01 00 00 00 00 02 24 40
+					15 01 00 00 00 00 02 25 6d
+					15 01 00 00 00 00 02 26 40
+					15 01 00 00 00 00 02 27 40
+					/* Vend */
+					15 01 00 00 00 00 02 e0 00
+					15 01 00 00 00 00 02 dc 21
+					15 01 00 00 00 00 02 dd 22
+					15 01 00 00 00 00 02 de 07
+					15 01 00 00 00 00 02 df 07
+					15 01 00 00 00 00 02 e3 6d
+					15 01 00 00 00 00 02 e1 07
+					15 01 00 00 00 00 02 e2 07
+					/* UD */
+					15 01 00 00 00 00 02 29 d8
+					15 01 00 00 00 00 02 2a 2a
+					/* CLK */
+					15 01 00 00 00 00 02 4b 03
+					15 01 00 00 00 00 02 4c 11
+					15 01 00 00 00 00 02 4d 10
+					15 01 00 00 00 00 02 4e 01
+					15 01 00 00 00 00 02 4f 01
+					15 01 00 00 00 00 02 50 10
+					15 01 00 00 00 00 02 51 00
+					15 01 00 00 00 00 02 52 80
+					15 01 00 00 00 00 02 53 00
+					15 01 00 00 00 00 02 56 00
+					15 01 00 00 00 00 02 54 07
+					15 01 00 00 00 00 02 58 07
+					15 01 00 00 00 00 02 55 25
+					/* Reset XDONB */
+					15 01 00 00 00 00 02 5b 43
+					15 01 00 00 00 00 02 5c 00
+					15 01 00 00 00 00 02 5f 73
+					15 01 00 00 00 00 02 60 73
+					15 01 00 00 00 00 02 63 22
+					15 01 00 00 00 00 02 64 00
+					15 01 00 00 00 00 02 67 08
+					15 01 00 00 00 00 02 68 04
+					/* Resolution:1440x2560*/
+					15 01 00 00 00 00 02 72 02
+					/* mux */
+					15 01 00 00 00 00 02 7a 80
+					15 01 00 00 00 00 02 7b 91
+					15 01 00 00 00 00 02 7c d8
+					15 01 00 00 00 00 02 7d 60
+					15 01 00 00 00 00 02 7f 15
+					15 01 00 00 00 00 02 75 15
+					/* ABOFF */
+					15 01 00 00 00 00 02 b3 c0
+					15 01 00 00 00 00 02 b4 00
+					15 01 00 00 00 00 02 b5 00
+					/* Source EQ */
+					15 01 00 00 00 00 02 78 00
+					15 01 00 00 00 00 02 79 00
+					15 01 00 00 00 00 02 80 00
+					15 01 00 00 00 00 02 83 00
+					/* FP BP */
+					15 01 00 00 00 00 02 93 0a
+					15 01 00 00 00 00 02 94 0a
+					/* Inversion Type */
+					15 01 00 00 00 00 02 8a 00
+					15 01 00 00 00 00 02 9b ff
+					/* IMGSWAP =1 @PortSwap=1 */
+					15 01 00 00 00 00 02 9d b0
+					15 01 00 00 00 00 02 9f 63
+					15 01 00 00 00 00 02 98 10
+					/* FRM */
+					15 01 00 00 00 00 02 ec 00
+					/* CMD1 */
+					15 01 00 00 00 00 02 ff 10
+					/* VESA DSC PPS settings
+					 *  (1440x2560 slide 16H)
+					 */
+					39 01 00 00 00 00 11 c1 09
+					20 00 10 02 00 02 68 01 bb
+					00 0a 06 67 04 c5
+
+					39 01 00 00 00 00 03 c2 10 f0
+					/* C0h = 0x0(2 Port SDC)
+					 * 0x01(1 PortA FBC)
+					 * 0x02(MTK) 0x03(1 PortA VESA)
+					 */
+					15 01 00 00 00 00 02 c0 03
+					/* VBP+VSA=,VFP = 10H */
+					15 01 00 00 00 00 04 3b 03 0a 0a
+					/* FTE on */
+					15 01 00 00 00 00 02 35 00
+					/* EN_BK =1(auto black) */
+					15 01 00 00 00 00 02 e5 01
+					/* CMD mode(10) VDO mode(03) */
+					15 01 00 00 00 00 02 bb 10
+					/* Non Reload MTP */
+					15 01 00 00 00 00 02 fb 01
+					/* SlpOut + DispOn */
+					05 01 00 00 78 00 02 11 00
+					05 01 00 00 78 00 02 29 00
+					];
+				qcom,mdss-dsi-off-command = [05 01 00 00 78 00
+					02 28 00 05 01 00 00 78 00 02 10 00];
+
+				qcom,mdss-dsi-on-command-state = "dsi_hs_mode";
+				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+				qcom,mdss-dsi-h-sync-pulse = <0>;
+				qcom,compression-mode = "dsc";
+				qcom,mdss-dsc-slice-height = <16>;
+				qcom,mdss-dsc-slice-width = <720>;
+				qcom,mdss-dsc-slice-per-pkt = <2>;
+				qcom,mdss-dsc-bit-per-component = <10>;
+				qcom,mdss-dsc-bit-per-pixel = <8>;
+				qcom,mdss-dsc-block-prediction-enable;
+			};
+			timing@1 {
+				qcom,mdss-dsi-panel-width = <1080>;
+				qcom,mdss-dsi-panel-height = <1920>;
+				qcom,mdss-dsi-h-front-porch = <0>;
+				qcom,mdss-dsi-h-back-porch = <0>;
+				qcom,mdss-dsi-h-pulse-width = <0>;
+				qcom,mdss-dsi-h-sync-skew = <0>;
+				qcom,mdss-dsi-v-back-porch = <0>;
+				qcom,mdss-dsi-v-front-porch = <0>;
+				qcom,mdss-dsi-v-pulse-width = <0>;
+				qcom,mdss-dsi-h-left-border = <0>;
+				qcom,mdss-dsi-h-right-border = <0>;
+				qcom,mdss-dsi-v-top-border = <0>;
+				qcom,mdss-dsi-v-bottom-border = <0>;
+				qcom,mdss-dsi-panel-framerate = <60>;
+				qcom,mdss-dsi-on-command = [
+					15 01 00 00 00 00 02 bb 10
+					15 01 00 00 00 00 02 b0 03
+					05 01 00 00 78 00 01 11
+					15 01 00 00 00 00 02 51 ff
+					15 01 00 00 00 00 02 53 24
+					15 01 00 00 00 00 02 ff 23
+					15 01 00 00 00 00 02 08 05
+					15 01 00 00 00 00 02 46 90
+					15 01 00 00 00 00 02 ff 10
+					15 01 00 00 00 00 02 ff f0
+					15 01 00 00 00 00 02 92 01
+					15 01 00 00 00 00 02 ff 10
+					/* enable TE generation */
+					15 01 00 00 00 00 02 35 00
+					05 01 00 00 28 00 01 29];
+				qcom,mdss-dsi-off-command = [
+					05 01 00 00 10 00 01 28
+					05 01 00 00 40 00 01 10];
+				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+				qcom,mdss-dsi-h-sync-pulse = <0>;
+				qcom,compression-mode = "dsc";
+				qcom,mdss-dsc-slice-height = <16>;
+				qcom,mdss-dsc-slice-width = <540>;
+				qcom,mdss-dsc-slice-per-pkt = <2>;
+				qcom,mdss-dsc-bit-per-component = <10>;
+				qcom,mdss-dsc-bit-per-pixel = <8>;
+				qcom,mdss-dsc-block-prediction-enable;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi
new file mode 100644
index 0000000..5d977e7
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi
@@ -0,0 +1,281 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&mdss_mdp {
+	dsi_dual_sim_dsc_375_cmd: qcom,mdss_dsi_dual_sim_dsc_375_cmd {
+		qcom,mdss-dsi-panel-name =
+			"Sim dual cmd mode DSC 3.75:1 dsi panel";
+		qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
+		qcom,mdss-dsi-virtual-channel-id = <0>;
+		qcom,mdss-dsi-stream = <0>;
+		qcom,mdss-dsi-bpp = <24>;
+		qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+		qcom,mdss-dsi-underflow-color = <0xff>;
+		qcom,mdss-dsi-border-color = <0>;
+		qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+		qcom,mdss-dsi-bllp-eof-power-mode;
+		qcom,mdss-dsi-bllp-power-mode;
+		qcom,cmd-sync-wait-broadcast;
+		qcom,mdss-dsi-lane-0-state;
+		qcom,mdss-dsi-lane-1-state;
+		qcom,mdss-dsi-lane-2-state;
+		qcom,mdss-dsi-lane-3-state;
+		qcom,mdss-dsi-hor-line-idle = <0 40 256>,
+						<40 120 128>,
+						<120 240 64>;
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-bl-max-level = <4095>;
+		qcom,mdss-dsi-dma-trigger = "trigger_sw";
+		qcom,mdss-dsi-mdp-trigger = "none";
+		qcom,mdss-dsi-te-pin-select = <1>;
+		qcom,mdss-dsi-wr-mem-start = <0x2c>;
+		qcom,mdss-dsi-wr-mem-continue = <0x3c>;
+		qcom,mdss-dsi-te-dcs-command = <1>;
+		qcom,mdss-dsi-te-check-enable;
+		qcom,mdss-dsi-te-using-wd;
+		qcom,mdss-dsi-te-using-te-pin;
+		qcom,panel-ack-disabled;
+
+		qcom,mdss-dsi-display-timings {
+			timing@0 {
+				qcom,mdss-dsi-panel-width = <1080>;
+				qcom,mdss-dsi-panel-height = <3840>;
+				qcom,mdss-dsi-h-front-porch = <30>;
+				qcom,mdss-dsi-h-back-porch = <100>;
+				qcom,mdss-dsi-h-pulse-width = <4>;
+				qcom,mdss-dsi-h-sync-skew = <0>;
+				qcom,mdss-dsi-v-back-porch = <7>;
+				qcom,mdss-dsi-v-front-porch = <8>;
+				qcom,mdss-dsi-v-pulse-width = <1>;
+				qcom,mdss-dsi-h-sync-pulse = <0>;
+				qcom,mdss-dsi-panel-framerate = <60>;
+
+				qcom,mdss-dsi-on-command = [
+					39 01 00 00 00 00 11 91 09 20 00 20 02
+					00 03 1c 04 21 00
+					0f 03 19 01 97
+					39 01 00 00 00 00 03 92 10 f0
+					15 01 00 00 00 00 02 90 03
+					15 01 00 00 00 00 02 03 01
+					39 01 00 00 00 00 06 f0 55 aa 52 08 04
+					15 01 00 00 00 00 02 c0 03
+					39 01 00 00 00 00 06 f0 55 aa 52 08 07
+					15 01 00 00 00 00 02 ef 01
+					39 01 00 00 00 00 06 f0 55 aa 52 08 00
+					15 01 00 00 00 00 02 b4 01
+					15 01 00 00 00 00 02 35 00
+					39 01 00 00 00 00 06 f0 55 aa 52 08 01
+					39 01 00 00 00 00 05 ff aa 55 a5 80
+					15 01 00 00 00 00 02 6f 01
+					15 01 00 00 00 00 02 f3 10
+					39 01 00 00 00 00 05 ff aa 55 a5 00
+					/* sleep out + delay 120ms */
+					05 01 00 00 78 00 01 11
+					/* display on + delay 120ms */
+					05 01 00 00 78 00 01 29
+					];
+				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+				qcom,mdss-dsi-off-command =
+					[05 01 00 00 78 00 02 28 00
+					 05 01 00 00 78 00 02 10 00];
+				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+
+				qcom,compression-mode = "dsc";
+				qcom,mdss-dsc-slice-height = <32>;
+				qcom,mdss-dsc-slice-width = <1080>;
+				qcom,mdss-dsc-slice-per-pkt = <1>;
+				qcom,mdss-dsc-bit-per-component = <10>;
+				qcom,mdss-dsc-bit-per-pixel = <8>;
+				qcom,mdss-dsc-block-prediction-enable;
+			};
+			timing@1 {
+				qcom,mdss-dsi-panel-framerate = <60>;
+				qcom,mdss-dsi-panel-width = <720>;
+				qcom,mdss-dsi-panel-height = <2560>;
+				qcom,mdss-dsi-h-front-porch = <100>;
+				qcom,mdss-dsi-h-back-porch = <32>;
+				qcom,mdss-dsi-h-pulse-width = <16>;
+				qcom,mdss-dsi-h-sync-skew = <0>;
+				qcom,mdss-dsi-v-back-porch = <7>;
+				qcom,mdss-dsi-v-front-porch = <8>;
+				qcom,mdss-dsi-v-pulse-width = <1>;
+				qcom,mdss-dsi-h-left-border = <0>;
+				qcom,mdss-dsi-h-right-border = <0>;
+				qcom,mdss-dsi-v-top-border = <0>;
+				qcom,mdss-dsi-v-bottom-border = <0>;
+				qcom,mdss-dsi-h-sync-pulse = <0>;
+				qcom,mdss-dsi-on-command = [
+					/* CMD2_P0 */
+					15 01 00 00 00 00 02 FF 20
+					15 01 00 00 00 00 02 fb 01
+					15 01 00 00 00 00 02 00 01
+					15 01 00 00 00 00 02 01 55
+					15 01 00 00 00 00 02 02 45
+					15 01 00 00 00 00 02 05 40
+					15 01 00 00 00 00 02 06 19
+					15 01 00 00 00 00 02 07 1E
+					15 01 00 00 00 00 02 0B 73
+					15 01 00 00 00 00 02 0C 73
+					15 01 00 00 00 00 02 0E B0
+					15 01 00 00 00 00 02 0F AE
+					15 01 00 00 00 00 02 11 B8
+					15 01 00 00 00 00 02 13 00
+					15 01 00 00 00 00 02 58 80
+					15 01 00 00 00 00 02 59 01
+					15 01 00 00 00 00 02 5A 00
+					15 01 00 00 00 00 02 5B 01
+					15 01 00 00 00 00 02 5C 80
+					15 01 00 00 00 00 02 5D 81
+					15 01 00 00 00 00 02 5E 00
+					15 01 00 00 00 00 02 5F 01
+					15 01 00 00 00 00 02 72 31
+					15 01 00 00 00 00 02 68 03
+					/* CMD2_P4 */
+					15 01 00 00 00 00 02 ff 24
+					15 01 00 00 00 00 02 fb 01
+					15 01 00 00 00 00 02 00 1C
+					15 01 00 00 00 00 02 01 0B
+					15 01 00 00 00 00 02 02 0C
+					15 01 00 00 00 00 02 03 01
+					15 01 00 00 00 00 02 04 0F
+					15 01 00 00 00 00 02 05 10
+					15 01 00 00 00 00 02 06 10
+					15 01 00 00 00 00 02 07 10
+					15 01 00 00 00 00 02 08 89
+					15 01 00 00 00 00 02 09 8A
+					15 01 00 00 00 00 02 0A 13
+					15 01 00 00 00 00 02 0B 13
+					15 01 00 00 00 00 02 0C 15
+					15 01 00 00 00 00 02 0D 15
+					15 01 00 00 00 00 02 0E 17
+					15 01 00 00 00 00 02 0F 17
+					15 01 00 00 00 00 02 10 1C
+					15 01 00 00 00 00 02 11 0B
+					15 01 00 00 00 00 02 12 0C
+					15 01 00 00 00 00 02 13 01
+					15 01 00 00 00 00 02 14 0F
+					15 01 00 00 00 00 02 15 10
+					15 01 00 00 00 00 02 16 10
+					15 01 00 00 00 00 02 17 10
+					15 01 00 00 00 00 02 18 89
+					15 01 00 00 00 00 02 19 8A
+					15 01 00 00 00 00 02 1A 13
+					15 01 00 00 00 00 02 1B 13
+					15 01 00 00 00 00 02 1C 15
+					15 01 00 00 00 00 02 1D 15
+					15 01 00 00 00 00 02 1E 17
+					15 01 00 00 00 00 02 1F 17
+					/* STV */
+					15 01 00 00 00 00 02 20 40
+					15 01 00 00 00 00 02 21 01
+					15 01 00 00 00 00 02 22 00
+					15 01 00 00 00 00 02 23 40
+					15 01 00 00 00 00 02 24 40
+					15 01 00 00 00 00 02 25 6D
+					15 01 00 00 00 00 02 26 40
+					15 01 00 00 00 00 02 27 40
+					/* Vend */
+					15 01 00 00 00 00 02 E0 00
+					15 01 00 00 00 00 02 DC 21
+					15 01 00 00 00 00 02 DD 22
+					15 01 00 00 00 00 02 DE 07
+					15 01 00 00 00 00 02 DF 07
+					15 01 00 00 00 00 02 E3 6D
+					15 01 00 00 00 00 02 E1 07
+					15 01 00 00 00 00 02 E2 07
+					/* UD */
+					15 01 00 00 00 00 02 29 D8
+					15 01 00 00 00 00 02 2A 2A
+					/* CLK */
+					15 01 00 00 00 00 02 4B 03
+					15 01 00 00 00 00 02 4C 11
+					15 01 00 00 00 00 02 4D 10
+					15 01 00 00 00 00 02 4E 01
+					15 01 00 00 00 00 02 4F 01
+					15 01 00 00 00 00 02 50 10
+					15 01 00 00 00 00 02 51 00
+					15 01 00 00 00 00 02 52 80
+					15 01 00 00 00 00 02 53 00
+					15 01 00 00 00 00 02 56 00
+					15 01 00 00 00 00 02 54 07
+					15 01 00 00 00 00 02 58 07
+					15 01 00 00 00 00 02 55 25
+					/* Reset XDONB */
+					15 01 00 00 00 00 02 5B 43
+					15 01 00 00 00 00 02 5C 00
+					15 01 00 00 00 00 02 5F 73
+					15 01 00 00 00 00 02 60 73
+					15 01 00 00 00 00 02 63 22
+					15 01 00 00 00 00 02 64 00
+					15 01 00 00 00 00 02 67 08
+					15 01 00 00 00 00 02 68 04
+					/* Resolution:1440x2560*/
+					15 01 00 00 00 00 02 72 02
+					/* mux */
+					15 01 00 00 00 00 02 7A 80
+					15 01 00 00 00 00 02 7B 91
+					15 01 00 00 00 00 02 7C D8
+					15 01 00 00 00 00 02 7D 60
+					15 01 00 00 00 00 02 7F 15
+					15 01 00 00 00 00 02 75 15
+					/* ABOFF */
+					15 01 00 00 00 00 02 B3 C0
+					15 01 00 00 00 00 02 B4 00
+					15 01 00 00 00 00 02 B5 00
+					/* Source EQ */
+					15 01 00 00 00 00 02 78 00
+					15 01 00 00 00 00 02 79 00
+					15 01 00 00 00 00 02 80 00
+					15 01 00 00 00 00 02 83 00
+					/* FP BP */
+					15 01 00 00 00 00 02 93 0A
+					15 01 00 00 00 00 02 94 0A
+					/* Inversion Type */
+					15 01 00 00 00 00 02 8A 00
+					15 01 00 00 00 00 02 9B FF
+					/* IMGSWAP =1 @PortSwap=1 */
+					15 01 00 00 00 00 02 9D B0
+					15 01 00 00 00 00 02 9F 63
+					15 01 00 00 00 00 02 98 10
+					/* FRM */
+					15 01 00 00 00 00 02 EC 00
+					/* CMD1 */
+					15 01 00 00 00 00 02 ff 10
+					/* VBP+VSA=,VFP = 10H */
+					15 01 00 00 00 00 04 3B 03 0A 0A
+					/* FTE on */
+					15 01 00 00 00 00 02 35 00
+					/* EN_BK =1(auto black) */
+					15 01 00 00 00 00 02 E5 01
+					/* CMD mode(10) VDO mode(03) */
+					15 01 00 00 00 00 02 BB 10
+					/* Non Reload MTP */
+					15 01 00 00 00 00 02 FB 01
+					/* SlpOut + DispOn */
+					05 01 00 00 78 00 02 11 00
+					05 01 00 00 78 00 02 29 00
+					];
+				qcom,mdss-dsi-off-command = [05 01 00 00 78 00
+					02 28 00 05 01 00 00 78 00 02 10 00];
+				qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+				qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+				qcom,compression-mode = "dsc";
+				qcom,mdss-dsc-slice-height = <16>;
+				qcom,mdss-dsc-slice-width = <720>;
+				qcom,mdss-dsc-slice-per-pkt = <1>;
+				qcom,mdss-dsc-bit-per-component = <10>;
+				qcom,mdss-dsc-bit-per-pixel = <8>;
+				qcom,mdss-dsc-block-prediction-enable;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
new file mode 100644
index 0000000..f0c820f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
@@ -0,0 +1,30 @@
+/* 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"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <1 0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
new file mode 100644
index 0000000..c8537bc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
@@ -0,0 +1,29 @@
+/* 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"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 MTP";
+	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dts b/arch/arm64/boot/dts/qcom/sdm670.dts
new file mode 100644
index 0000000..1d5e5e0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670.dts
@@ -0,0 +1,21 @@
+/* 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"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 SoC";
+	compatible = "qcom,sdm670";
+	qcom,board-id = <0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 0dec428..f6cd37b 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -21,6 +21,7 @@
 #include <dt-bindings/clock/qcom,rpmh.h>
 #include <dt-bindings/soc/qcom,tcs-mbox.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/clock/qcom,aop-qmp.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. SDM670";
@@ -295,6 +296,13 @@
 
 	soc: soc { };
 
+	vendor: vendor {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0 0 0xffffffff>;
+		compatible = "simple-bus";
+	};
+
 	reserved-memory {
 		#address-cells = <2>;
 		#size-cells = <2>;
@@ -887,6 +895,13 @@
 		#reset-cells = <1>;
 	};
 
+	clock_aop: qcom,aopclk {
+		compatible = "qcom,aop-qmp-clk-v2";
+		#clock-cells = <1>;
+		mboxes = <&qmp_aop 0>;
+		mbox-names = "qdss_clk";
+	};
+
 	slim_aud: slim@62dc0000 {
 		cell-index = <1>;
 		compatible = "qcom,slim-ngd";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 3a0e4b6..dddf1fb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -294,6 +294,18 @@
 	qcom,platform-reset-gpio = <&tlmm 6 0>;
 };
 
+&dsi_sim_dsc_375_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
 &dsi_nt35597_truly_dsc_cmd_display {
 	qcom,dsi-display-active;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index d2189a7..c1fcb62 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -1862,6 +1862,18 @@
 		clock-names = "apb_pclk";
 	};
 
+	cti0_swao:cti@6b04000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
+		reg = <0x6b04000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti0-swao";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
 	turing_etm0 {
 		compatible = "qcom,coresight-remote-etm";
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index c3e8b60..3d58dc1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -152,6 +152,18 @@
 	qcom,platform-reset-gpio = <&tlmm 6 0>;
 };
 
+&dsi_sim_dsc_375_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
 &dsi_nt35597_truly_dsc_cmd_display {
 	qcom,dsi-display-active;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index f33e400..db3d23c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -12,8 +12,10 @@
 
 #include "dsi-panel-sim-video.dtsi"
 #include "dsi-panel-sim-cmd.dtsi"
+#include "dsi-panel-sim-dsc375-cmd.dtsi"
 #include "dsi-panel-sim-dualmipi-video.dtsi"
 #include "dsi-panel-sim-dualmipi-cmd.dtsi"
+#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi"
 #include "dsi-panel-sharp-dsc-4k-video.dtsi"
 #include "dsi-panel-sharp-dsc-4k-cmd.dtsi"
 #include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi"
@@ -363,6 +365,42 @@
 		qcom,dsi-panel = <&dsi_dual_sim_cmd>;
 	};
 
+	dsi_sim_dsc_375_cmd_display: qcom,dsi-display@12 {
+		compatible = "qcom,dsi-display";
+		label = "dsi_sim_dsc_375_cmd_display";
+		qcom,display-type = "primary";
+
+		qcom,dsi-ctrl = <&mdss_dsi0>;
+		qcom,dsi-phy = <&mdss_dsi_phy0>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+		clock-names = "src_byte_clk", "src_pixel_clk";
+
+		pinctrl-names = "panel_active", "panel_suspend";
+		pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+		qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>;
+	};
+
+	dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@13 {
+		compatible = "qcom,dsi-display";
+		label = "dsi_dual_sim_dsc_375_cmd_display";
+		qcom,display-type = "primary";
+
+		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+		clock-names = "src_byte_clk", "src_pixel_clk";
+
+		pinctrl-names = "panel_active", "panel_suspend";
+		pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+		qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>;
+	};
+
 	sde_wb: qcom,wb-display@0 {
 		compatible = "qcom,wb-display";
 		cell-index = <0>;
@@ -668,3 +706,43 @@
 		};
 	};
 };
+
+&dsi_sim_dsc_375_cmd {
+	qcom,mdss-dsi-t-clk-post = <0x0d>;
+	qcom,mdss-dsi-t-clk-pre = <0x2d>;
+	qcom,mdss-dsi-display-timings {
+		timing@0 { /* 1080p */
+			qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07
+				07 04 03 04 00];
+			qcom,display-topology = <1 1 1>;
+			qcom,default-topology-index = <0>;
+		};
+		timing@1 { /* qhd */
+			qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
+				05 03 03 04 00];
+			qcom,display-topology = <1 1 1>,
+						<2 2 1>, /* dsc merge */
+						<2 1 1>; /* 3d mux */
+			qcom,default-topology-index = <0>;
+		};
+	};
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+	qcom,mdss-dsi-t-clk-post = <0x0d>;
+	qcom,mdss-dsi-t-clk-pre = <0x2d>;
+	qcom,mdss-dsi-display-timings {
+		timing@0 { /* qhd */
+			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+				07 05 03 04 00];
+			qcom,display-topology = <2 2 2>;
+			qcom,default-topology-index = <0>;
+		};
+		timing@1 { /* 4k */
+			qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
+				06 04 03 04 00];
+			qcom,display-topology = <2 2 2>;
+			qcom,default-topology-index = <0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index f721025..16d0988 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -375,7 +375,7 @@
 				MSM_BUS_SLAVE_EBI_CH0 240000 700000>,
 			<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3_1 0 40000>;
 
-		dwc3@a600000 {
+		dwc3@a800000 {
 			compatible = "snps,dwc3";
 			reg = <0x0a800000 0xcd00>;
 			interrupts = <0 138 0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index 13b5bfd..c42a7be 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -20,8 +20,9 @@
 		reg-cam-base = <0x65000>;
 		interrupts = <0 477 0>;
 		interrupt-names = "csiphy";
-		regulator-names = "gdscr";
+		regulator-names = "gdscr", "refgen";
 		gdscr-supply = <&titan_top_gdsc>;
+		refgen-supply = <&refgen>;
 		csi-vdd-voltage = <1200000>;
 		mipi-csi-vdd-supply = <&pm8998_l26>;
 		mipi-dsi-vdd-supply = <&pm8998_l1>;
@@ -55,8 +56,9 @@
 		reg-cam-base = <0x66000>;
 		interrupts = <0 478 0>;
 		interrupt-names = "csiphy";
-		regulator-names = "gdscr";
+		regulator-names = "gdscr", "refgen";
 		gdscr-supply = <&titan_top_gdsc>;
+		refgen-supply = <&refgen>;
 		csi-vdd-voltage = <1200000>;
 		mipi-csi-vdd-supply = <&pm8998_l26>;
 		mipi-dsi-vdd-supply = <&pm8998_l1>;
@@ -91,8 +93,9 @@
 		reg-cam-base = <0x67000>;
 		interrupts = <0 479 0>;
 		interrupt-names = "csiphy";
-		regulator-names = "gdscr";
+		regulator-names = "gdscr", "refgen";
 		gdscr-supply = <&titan_top_gdsc>;
+		refgen-supply = <&refgen>;
 		csi-vdd-voltage = <1200000>;
 		mipi-csi-vdd-supply = <&pm8998_l26>;
 		mipi-dsi-vdd-supply = <&pm8998_l1>;
@@ -126,8 +129,9 @@
 		reg-cam-base = <0x68000>;
 		interrupts = <0 448 0>;
 		interrupt-names = "csiphy";
-		regulator-names = "gdscr";
+		regulator-names = "gdscr", "refgen";
 		gdscr-supply = <&titan_top_gdsc>;
+		refgen-supply = <&refgen>;
 		csi-vdd-voltage = <1200000>;
 		mipi-csi-vdd-supply = <&pm8998_l26>;
 		mipi-dsi-vdd-supply = <&pm8998_l1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 35ac89f..314cfbb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -459,6 +459,16 @@
 			};
 		};
 	};
+
+	gpu_gx_domain_addr: syscon@0x5091508 {
+		compatible = "syscon";
+		reg = <0x5091508 0x4>;
+	};
+
+	gpu_gx_sw_reset: syscon@0x5091008 {
+		compatible = "syscon";
+		reg = <0x5091008 0x4>;
+	};
 };
 
 &clock_cpucc {
@@ -521,6 +531,26 @@
 		<  1689600000 0x40441058 0x00004646 0x2 17 >,
 		<  1766400000 0x4044115c 0x00004a4a 0x2 18 >;
 
+	qcom,pwrcl-speedbin1-v0 =
+		<   300000000 0x000c000f 0x00002020 0x1 1 >,
+		<   403200000 0x500c0115 0x00002020 0x1 2 >,
+		<   480000000 0x50140219 0x00002020 0x1 3 >,
+		<   576000000 0x5014031e 0x00002020 0x1 4 >,
+		<   652800000 0x401c0422 0x00002020 0x1 5 >,
+		<   748800000 0x401c0527 0x00002020 0x1 6 >,
+		<   825600000 0x401c062b 0x00002222 0x1 7 >,
+		<   902400000 0x4024072f 0x00002626 0x1 8 >,
+		<   979200000 0x40240833 0x00002929 0x1 9 >,
+		<  1056000000 0x402c0937 0x00002c2c 0x2 10 >,
+		<  1132800000 0x402c0a3b 0x00002f2f 0x2 11 >,
+		<  1228800000 0x402c0b40 0x00003333 0x2 12 >,
+		<  1324800000 0x40340c45 0x00003737 0x2 13 >,
+		<  1420800000 0x40340d4a 0x00003b3b 0x2 14 >,
+		<  1516800000 0x403c0e4f 0x00003f3f 0x2 15 >,
+		<  1612800000 0x403c0f54 0x00004343 0x2 16 >,
+		<  1689600000 0x40441058 0x00004646 0x2 17 >,
+		<  1766400000 0x4044115c 0x00004a4a 0x2 18 >;
+
 	qcom,perfcl-speedbin0-v0 =
 		<   300000000 0x000c000f 0x00002020 0x1 1 >,
 		<   403200000 0x500c0115 0x00002020 0x1 2 >,
@@ -587,11 +617,16 @@
 	qcom,l3-memacc-level-vc-bin1 = <8 13>;
 
 	qcom,pwrcl-memacc-level-vc-bin0 = <12 16>;
+	qcom,pwrcl-memacc-level-vc-bin1 = <12 16>;
 
 	qcom,perfcl-memacc-level-vc-bin0 = <14 22>;
 	qcom,perfcl-memacc-level-vc-bin1 = <14 22>;
 };
 
+&bwmon {
+	qcom,count-unit = <0x10000>;
+};
+
 &clock_gcc {
 	compatible = "qcom,gcc-sdm845-v2", "syscon";
 };
@@ -639,3 +674,232 @@
 &mdss_mdp {
 	clock-max-rate = <0 0 0 0 430000000 19200000 0>;
 };
+
+&energy_costs {
+	CPU_COST_0: core-cost0 {
+		busy-cost-data = <
+			 300000 11
+			 403200 17
+			 480000 21
+			 576000 26
+			 652800 31
+			 748800 37
+			 825600 42
+			 902400 47
+			 979200 52
+			1056000 57
+			1132800 62
+			1228800 69
+			1324800 78
+			1420800 89
+			1516800 103
+			1612800 122
+			1689600 140
+			1766400 159
+		>;
+		idle-cost-data = <
+			22 18 14 12
+		>;
+	};
+	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
+			2092800 7120
+			2169600 7870
+			2246400 8620
+			2323200 9330
+			2400000 10030
+			2476800 10830
+			2553600 12080
+			2630400 14580
+			2707200 19960
+		>;
+		idle-cost-data = <
+			100 80 60 40
+		>;
+	};
+	CLUSTER_COST_0: cluster-cost0 {
+		busy-cost-data = <
+			 300000  3
+			 403200  4
+			 480000  4
+			 576000  4
+			 652800  5
+			 748800  5
+			 825600  6
+			 902400  7
+			 979200  7
+			1056000  8
+			1132800  9
+			1228800  9
+			1324800 10
+			1420800 11
+			1516800 12
+			1612800 13
+			1689600 15
+			1766400 17
+		>;
+		idle-cost-data = <
+			4 3 2 1
+		>;
+	};
+	CLUSTER_COST_1: cluster-cost1 {
+		busy-cost-data = <
+			 300000  24
+			 403200  24
+			 480000  25
+			 576000  25
+			 652800  26
+			 748800  27
+			 825600  28
+			 902400  29
+			 979200  30
+			1056000  32
+			1132800  34
+			1209600  37
+			1286400  40
+			1363200  45
+			1459200  50
+			1536000  57
+			1612800  64
+			1689600  74
+			1766400  84
+			1843200  96
+			1920000 106
+			1996800 113
+			2092800 120
+			2169600 125
+			2246400 127
+			2323200 130
+			2400000 135
+			2476800 140
+			2553600 145
+			2630400 150
+			2707200 155
+		>;
+		idle-cost-data = <
+			4 3 2 1
+		>;
+	};
+};
+
+&gpu_gx_gdsc {
+	domain-addr = <&gpu_gx_domain_addr>;
+	sw-reset = <&gpu_gx_sw_reset>;
+	qcom,reset-aon-logic;
+};
+
+/* GPU overrides */
+&msm_gpu {
+	/* Updated chip ID */
+	qcom,chipid = <0x06030001>;
+	qcom,initial-pwrlevel = <5>;
+
+	qcom,gpu-pwrlevels {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		compatible = "qcom,gpu-pwrlevels";
+
+		qcom,gpu-pwrlevel@0 {
+			reg = <0>;
+			qcom,gpu-freq = <675000000>;
+			qcom,bus-freq = <12>;
+			qcom,bus-min = <10>;
+			qcom,bus-max = <12>;
+		};
+
+		qcom,gpu-pwrlevel@1 {
+			reg = <1>;
+			qcom,gpu-freq = <596000000>;
+			qcom,bus-freq = <10>;
+			qcom,bus-min = <9>;
+			qcom,bus-max = <11>;
+		};
+
+		qcom,gpu-pwrlevel@2 {
+			reg = <2>;
+			qcom,gpu-freq = <520000000>;
+			qcom,bus-freq = <9>;
+			qcom,bus-min = <8>;
+			qcom,bus-max = <10>;
+		};
+
+		qcom,gpu-pwrlevel@3 {
+			reg = <3>;
+			qcom,gpu-freq = <414000000>;
+			qcom,bus-freq = <8>;
+			qcom,bus-min = <7>;
+			qcom,bus-max = <9>;
+		};
+
+		qcom,gpu-pwrlevel@4 {
+			reg = <4>;
+			qcom,gpu-freq = <342000000>;
+			qcom,bus-freq = <6>;
+			qcom,bus-min = <5>;
+			qcom,bus-max = <7>;
+		};
+
+		qcom,gpu-pwrlevel@5 {
+			reg = <5>;
+			qcom,gpu-freq = <257000000>;
+			qcom,bus-freq = <4>;
+			qcom,bus-min = <3>;
+			qcom,bus-max = <5>;
+		};
+
+		qcom,gpu-pwrlevel@6 {
+			reg = <6>;
+			qcom,gpu-freq = <0>;
+			qcom,bus-freq = <0>;
+			qcom,bus-min = <0>;
+			qcom,bus-max = <0>;
+		};
+	};
+};
+
+&gmu {
+	qcom,gmu-pwrlevels {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		compatible = "qcom,gmu-pwrlevels";
+
+		qcom,gmu-pwrlevel@0 {
+			reg = <0>;
+			qcom,gmu-freq = <500000000>;
+		};
+
+		qcom,gmu-pwrlevel@1 {
+			reg = <1>;
+			qcom,gmu-freq = <200000000>;
+		};
+
+		qcom,gmu-pwrlevel@2 {
+			reg = <2>;
+			qcom,gmu-freq = <0>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 8105588..88f2e05d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -344,7 +344,7 @@
 		};
 	};
 
-	energy-costs {
+	energy_costs: energy-costs {
 		compatible = "sched-energy";
 
 		CPU_COST_0: core-cost0 {
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 8e1a31b..636c982 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -2444,6 +2444,10 @@
 		VERIFY(err, 0 == copy_from_user(&p.init, param, size));
 		if (err)
 			goto bail;
+		VERIFY(err, p.init.init.filelen >= 0 &&
+			p.init.init.memlen >= 0);
+		if (err)
+			goto bail;
 		VERIFY(err, 0 == fastrpc_init_process(fl, &p.init));
 		if (err)
 			goto bail;
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index f93aba1..258a6f2 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -113,8 +113,8 @@
 
 #define PLL_MIN_LVAL			0x21
 #define PLL_MIN_FREQ_REG		0x94
-#define PLL_POST_DIV1			0x1F
-#define PLL_POST_DIV2			0x11F
+#define PLL_POST_DIV1			0x09
+#define PLL_POST_DIV2			0x109
 #define PLL_MODE			0x0
 #define PLL_L_VAL			0x4
 #define PLL_USER_CTRL			0xc
@@ -134,8 +134,8 @@
 #define ISENSE_OFF_DATA			0x0
 #define CONSTANT_32			0x20
 
-#define APM_MX_MODE			0x0
-#define APM_APC_MODE			0x2
+#define APM_MX_MODE			0x4100000
+#define APM_APC_MODE			0x4100002
 #define APM_READ_DATA_MASK		0xc
 #define APM_MX_MODE_VAL			0x4
 #define APM_APC_READ_VAL		0x8
@@ -563,7 +563,7 @@
 {
 	struct clk_osm *cpuclk = to_clk_osm(hw);
 
-	clk_osm_write_reg(cpuclk, 1, ENABLE_REG, OSM_BASE);
+	clk_osm_masked_write_reg(cpuclk, ENABLE_OSM, ENABLE_REG, ENABLE_OSM);
 
 	/* Make sure the write goes through before proceeding */
 	clk_osm_mb(cpuclk, OSM_BASE);
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 5633a8f..ae0325e 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -49,6 +49,7 @@
 #include <asm/cpuidle.h>
 #include "lpm-levels.h"
 #include <trace/events/power.h>
+#include "../clk/clk.h"
 #define CREATE_TRACE_POINTS
 #include <trace/events/trace_msm_low_power.h>
 
@@ -980,6 +981,9 @@
 		if (suspend_in_progress && from_idle && level->notify_rpm)
 			continue;
 
+		if (level->is_reset && !system_sleep_allowed())
+			continue;
+
 		best_level = i;
 
 		if (from_idle &&
@@ -1042,7 +1046,8 @@
 		clear_predict_history();
 		clear_cl_predict_history();
 
-		system_sleep_enter(us);
+		if (system_sleep_enter(us))
+			return -EBUSY;
 	}
 	/* Notify cluster enter event after successfully config completion */
 	cluster_notify(cluster, level, true);
@@ -1631,6 +1636,7 @@
 	 * clocks that are enabled and preventing the system level
 	 * LPMs(XO and Vmin).
 	 */
+	clock_debug_print_enabled();
 
 	psci_enter_sleep(lpm_cpu, idx, true);
 
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 4dcf3b4..7e40cc6 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -532,6 +532,20 @@
 	return rc;
 }
 
+static void dp_display_clean(struct dp_display_private *dp)
+{
+	if (dp_display_is_hdcp_enabled(dp)) {
+		dp->hdcp_status = HDCP_STATE_INACTIVE;
+
+		cancel_delayed_work_sync(&dp->hdcp_cb_work);
+		if (dp->hdcp.ops->off)
+			dp->hdcp.ops->off(dp->hdcp.data);
+	}
+
+	dp->ctrl->push_idle(dp->ctrl);
+	dp->ctrl->off(dp->ctrl, false);
+}
+
 static int dp_display_usbpd_disconnect_cb(struct device *dev)
 {
 	int rc = 0;
@@ -560,20 +574,14 @@
 	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))
+	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) {
 		pr_warn("timeout\n");
 
-	/*
-	 * If a cable/dongle is connected to the TX device but
-	 * no sink device is connected, we call host
-	 * initialization where orientation settings are
-	 * configured. When the cable/dongle is disconnect,
-	 * call host de-initialization to make sure
-	 * we re-configure the orientation settings during
-	 * the next connect event.
-	 */
-	if (!dp->power_on && dp->core_initialized)
-		dp_display_host_deinit(dp);
+		if (dp->power_on)
+			dp_display_clean(dp);
+	}
+
+	dp_display_host_deinit(dp);
 end:
 	return rc;
 }
@@ -613,10 +621,8 @@
 		goto end;
 	}
 
-	if (dp->usbpd->alt_mode_cfg_done) {
-		dp_display_host_init(dp);
+	if (dp->usbpd->alt_mode_cfg_done)
 		dp_display_process_hpd_high(dp);
-	}
 end:
 	return rc;
 }
@@ -831,8 +837,10 @@
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
+	if (!dp->power_on || !dp->core_initialized)
+		goto error;
+
 	dp->ctrl->off(dp->ctrl, dp->hpd_irq_on);
-	dp_display_host_deinit(dp);
 
 	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 7e3d81f..8bf3471 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -25,34 +25,12 @@
 	DP_LANE_COUNT_4	= 4,
 };
 
-enum phy_test_pattern {
-	PHY_TEST_PATTERN_NONE,
-	PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING,
-	PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT,
-	PHY_TEST_PATTERN_PRBS7,
-	PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN,
-	PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN,
-};
-
 enum dynamic_range {
 	DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
 	DP_DYNAMIC_RANGE_RGB_CEA = 0x01,
 	DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF,
 };
 
-enum test_video_pattern {
-	DP_TEST_VIDEO_PATTERN_NONE = 0x00,
-	DP_TEST_VIDEO_PATTERN_COLOR_RAMPS = 0x01,
-	DP_TEST_VIDEO_PATTERN_BW_VERT_LINES = 0x02,
-	DP_TEST_VIDEO_PATTERN_COLOR_SQUARE = 0x03,
-};
-
-enum dp_link_response {
-	TEST_ACK			= 0x1,
-	TEST_NACK			= 0x2,
-	TEST_EDID_CHECKSUM_WRITE	= 0x4,
-};
-
 enum audio_sample_rate {
 	AUDIO_SAMPLE_RATE_32_KHZ	= 0x00,
 	AUDIO_SAMPLE_RATE_44_1_KHZ	= 0x01,
@@ -125,7 +103,7 @@
  * git bit depth value. This function assumes that bit depth has
  * already been validated.
  */
-static inline u32 dp_link_bit_depth_to_bpp(enum test_bit_depth tbd)
+static inline u32 dp_link_bit_depth_to_bpp(u32 tbd)
 {
 	u32 bpp;
 
@@ -156,19 +134,22 @@
 static char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel)
 {
 	switch (phy_test_pattern_sel) {
-	case PHY_TEST_PATTERN_NONE:
-		return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_NONE);
-	case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
-		return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING);
-	case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+	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(
-			PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
-	case PHY_TEST_PATTERN_PRBS7:
-		return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_PRBS7);
-	case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
-		return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN);
-	case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
-		return DP_LINK_ENUM_STR(PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN);
+			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";
 	}
@@ -242,26 +223,16 @@
 static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
 {
 	int ret = 0;
-	int const test_audio_period_ch_1_addr = 0x273;
-	int const test_audio_period_ch_2_addr = 0x274;
-	int const test_audio_period_ch_3_addr = 0x275;
-	int const test_audio_period_ch_4_addr = 0x276;
-	int const test_audio_period_ch_5_addr = 0x277;
-	int const test_audio_period_ch_6_addr = 0x278;
-	int const test_audio_period_ch_7_addr = 0x279;
-	int const test_audio_period_ch_8_addr = 0x27A;
 	struct dp_link_request *req = &link->request;
 
-	/* TEST_AUDIO_PERIOD_CH_1 (Byte 0x273) */
-	ret = dp_link_get_period(link, test_audio_period_ch_1_addr);
+	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1);
 	if (ret == -EINVAL)
 		goto exit;
 
 	req->test_audio_period_ch_1 = ret;
 	pr_debug("test_audio_period_ch_1 = 0x%x\n", ret);
 
-	/* TEST_AUDIO_PERIOD_CH_2 (Byte 0x274) */
-	ret = dp_link_get_period(link, test_audio_period_ch_2_addr);
+	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2);
 	if (ret == -EINVAL)
 		goto exit;
 
@@ -269,47 +240,42 @@
 	pr_debug("test_audio_period_ch_2 = 0x%x\n", ret);
 
 	/* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */
-	ret = dp_link_get_period(link, test_audio_period_ch_3_addr);
+	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3);
 	if (ret == -EINVAL)
 		goto exit;
 
 	req->test_audio_period_ch_3 = ret;
 	pr_debug("test_audio_period_ch_3 = 0x%x\n", ret);
 
-	/* TEST_AUDIO_PERIOD_CH_4 (Byte 0x276) */
-	ret = dp_link_get_period(link, test_audio_period_ch_4_addr);
+	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4);
 	if (ret == -EINVAL)
 		goto exit;
 
 	req->test_audio_period_ch_4 = ret;
 	pr_debug("test_audio_period_ch_4 = 0x%x\n", ret);
 
-	/* TEST_AUDIO_PERIOD_CH_5 (Byte 0x277) */
-	ret = dp_link_get_period(link, test_audio_period_ch_5_addr);
+	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5);
 	if (ret == -EINVAL)
 		goto exit;
 
 	req->test_audio_period_ch_5 = ret;
 	pr_debug("test_audio_period_ch_5 = 0x%x\n", ret);
 
-	/* TEST_AUDIO_PERIOD_CH_6 (Byte 0x278) */
-	ret = dp_link_get_period(link, test_audio_period_ch_6_addr);
+	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6);
 	if (ret == -EINVAL)
 		goto exit;
 
 	req->test_audio_period_ch_6 = ret;
 	pr_debug("test_audio_period_ch_6 = 0x%x\n", ret);
 
-	/* TEST_AUDIO_PERIOD_CH_7 (Byte 0x279) */
-	ret = dp_link_get_period(link, test_audio_period_ch_7_addr);
+	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7);
 	if (ret == -EINVAL)
 		goto exit;
 
 	req->test_audio_period_ch_7 = ret;
 	pr_debug("test_audio_period_ch_7 = 0x%x\n", ret);
 
-	/* TEST_AUDIO_PERIOD_CH_8 (Byte 0x27A) */
-	ret = dp_link_get_period(link, test_audio_period_ch_8_addr);
+	ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8);
 	if (ret == -EINVAL)
 		goto exit;
 
@@ -326,12 +292,10 @@
 	u8 data;
 	int rlen;
 	int const param_len = 0x1;
-	int const test_audio_pattern_type_addr = 0x272;
 	int const max_audio_pattern_type = 0x1;
 
-	/* Read the requested audio pattern type (Byte 0x272). */
 	rlen = drm_dp_dpcd_read(link->aux->drm_aux,
-		test_audio_pattern_type_addr, &bp, param_len);
+		DP_TEST_AUDIO_PATTERN_TYPE, &bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link audio mode data\n");
 		ret = -EINVAL;
@@ -360,14 +324,12 @@
 	u8 data;
 	int rlen;
 	int const param_len = 0x1;
-	int const test_audio_mode_addr = 0x271;
 	int const max_audio_sampling_rate = 0x6;
 	int const max_audio_channel_count = 0x8;
 	int sampling_rate = 0x0;
 	int channel_count = 0x0;
 
-	/* Read the requested audio mode (Byte 0x271). */
-	rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_audio_mode_addr,
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_AUDIO_MODE,
 			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link audio mode data\n");
@@ -435,10 +397,10 @@
 static bool dp_link_is_video_pattern_valid(u32 pattern)
 {
 	switch (pattern) {
-	case DP_TEST_VIDEO_PATTERN_NONE:
-	case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS:
-	case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES:
-	case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE:
+	case DP_NO_TEST_PATTERN:
+	case DP_COLOR_RAMP:
+	case DP_BLACK_AND_WHITE_VERTICAL_LINES:
+	case DP_COLOR_SQUARE:
 		return true;
 	default:
 		return false;
@@ -448,14 +410,14 @@
 static char *dp_link_video_pattern_to_string(u32 test_video_pattern)
 {
 	switch (test_video_pattern) {
-	case DP_TEST_VIDEO_PATTERN_NONE:
-		return DP_LINK_ENUM_STR(DP_TEST_VIDEO_PATTERN_NONE);
-	case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS:
-		return DP_LINK_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_RAMPS);
-	case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES:
-		return DP_LINK_ENUM_STR(DP_TEST_VIDEO_PATTERN_BW_VERT_LINES);
-	case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE:
-		return DP_LINK_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_SQUARE);
+	case DP_NO_TEST_PATTERN:
+		return DP_LINK_ENUM_STR(DP_NO_TEST_PATTERN);
+	case DP_COLOR_RAMP:
+		return DP_LINK_ENUM_STR(DP_COLOR_RAMP);
+	case DP_BLACK_AND_WHITE_VERTICAL_LINES:
+		return DP_LINK_ENUM_STR(DP_BLACK_AND_WHITE_VERTICAL_LINES);
+	case DP_COLOR_SQUARE:
+		return DP_LINK_ENUM_STR(DP_COLOR_SQUARE);
 	default:
 		return "unknown";
 	}
@@ -575,7 +537,6 @@
 	u32 len = 1;
 	int rlen;
 
-	/* Read the requested video link pattern (Byte 0x221). */
 	rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len);
 	if (rlen < 1) {
 		pr_err("failed to read 0x%x\n", addr);
@@ -601,11 +562,8 @@
 	u8 data;
 	u32 dyn_range;
 	int const param_len = 0x1;
-	int const test_video_pattern_addr = 0x221;
-	int const test_misc_addr = 0x232;
 
-	/* Read the requested video link pattern (Byte 0x221). */
-	rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_video_pattern_addr,
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PATTERN,
 			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link video pattern\n");
@@ -627,7 +585,7 @@
 			link->request.test_video_pattern));
 
 	/* Read the requested color bit depth and dynamic range (Byte 0x232) */
-	rlen = drm_dp_dpcd_read(link->aux->drm_aux, test_misc_addr,
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_MISC0,
 			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read link bit depth\n");
@@ -637,7 +595,7 @@
 	data = bp;
 
 	/* Dynamic Range */
-	dyn_range = (data & BIT(3)) >> 3;
+	dyn_range = (data & DP_TEST_DYNAMIC_RANGE_CEA) >> 3;
 	if (!dp_link_is_dynamic_range_valid(dyn_range)) {
 		pr_err("invalid link dynamic range = 0x%x", dyn_range);
 		ret = -EINVAL;
@@ -650,8 +608,7 @@
 			link->request.test_dyn_range));
 
 	/* Color bit depth */
-	data &= (BIT(5) | BIT(6) | BIT(7));
-	data >>= 5;
+	data &= DP_TEST_BIT_DEPTH_MASK;
 	if (!dp_link_is_bit_depth_valid(data)) {
 		pr_err("invalid link bit depth = 0x%x\n", data);
 		ret = -EINVAL;
@@ -664,87 +621,87 @@
 		dp_link_bit_depth_to_string(link->request.test_bit_depth));
 
 	/* resolution timing params */
-	ret = dp_link_parse_timing_params1(link, 0x222, 2,
+	ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2,
 			&link->request.test_h_total);
 	if (ret) {
-		pr_err("failed to parse test_h_total (0x222)\n");
+		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);
 
-	ret = dp_link_parse_timing_params1(link, 0x224, 2,
+	ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2,
 			&link->request.test_v_total);
 	if (ret) {
-		pr_err("failed to parse test_v_total (0x224)\n");
+		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);
 
-	ret = dp_link_parse_timing_params1(link, 0x226, 2,
+	ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2,
 			&link->request.test_h_start);
 	if (ret) {
-		pr_err("failed to parse test_h_start (0x226)\n");
+		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);
 
-	ret = dp_link_parse_timing_params1(link, 0x228, 2,
+	ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2,
 			&link->request.test_v_start);
 	if (ret) {
-		pr_err("failed to parse test_v_start (0x228)\n");
+		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);
 
-	ret = dp_link_parse_timing_params2(link, 0x22A, 2,
+	ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2,
 			&link->request.test_hsync_pol,
 			&link->request.test_hsync_width);
 	if (ret) {
-		pr_err("failed to parse (0x22A)\n");
+		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);
 
-	ret = dp_link_parse_timing_params2(link, 0x22C, 2,
+	ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2,
 			&link->request.test_vsync_pol,
 			&link->request.test_vsync_width);
 	if (ret) {
-		pr_err("failed to parse (0x22C)\n");
+		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);
 
-	ret = dp_link_parse_timing_params1(link, 0x22E, 2,
+	ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2,
 			&link->request.test_h_width);
 	if (ret) {
-		pr_err("failed to parse test_h_width (0x22E)\n");
+		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);
 
-	ret = dp_link_parse_timing_params1(link, 0x230, 2,
+	ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2,
 			&link->request.test_v_height);
 	if (ret) {
-		pr_err("failed to parse test_v_height (0x230)\n");
+		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);
 
-	ret = dp_link_parse_timing_params3(link, 0x233,
+	ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1,
 		&link->request.test_rr_d);
-	link->request.test_rr_d &= BIT(0);
+	link->request.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR;
 	if (ret) {
-		pr_err("failed to parse test_rr_d (0x233)\n");
+		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);
 
-	ret = dp_link_parse_timing_params3(link, 0x234,
+	ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR,
 		&link->request.test_rr_n);
 	if (ret) {
-		pr_err("failed to parse test_rr_n (0x234)\n");
+		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);
@@ -795,7 +752,6 @@
 	int rlen;
 	int const param_len = 0x1;
 
-	/* Read the requested link rate (Byte 0x219). */
 	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LINK_RATE,
 			&bp, param_len);
 	if (rlen < param_len) {
@@ -814,7 +770,6 @@
 	link->request.test_link_rate = data;
 	pr_debug("link rate = 0x%x\n", link->request.test_link_rate);
 
-	/* Read the requested lane count (Byte 0x220). */
 	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LANE_COUNT,
 			&bp, param_len);
 	if (rlen < param_len) {
@@ -840,12 +795,12 @@
 static bool dp_link_is_phy_test_pattern_supported(u32 phy_test_pattern_sel)
 {
 	switch (phy_test_pattern_sel) {
-	case PHY_TEST_PATTERN_NONE:
-	case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
-	case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
-	case PHY_TEST_PATTERN_PRBS7:
-	case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
-	case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
+	case DP_TEST_PHY_PATTERN_NONE:
+	case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
+	case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
+	case DP_TEST_PHY_PATTERN_PRBS7:
+	case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
+	case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
 		return true;
 	default:
 		return false;
@@ -865,10 +820,9 @@
 	u8 data;
 	int rlen;
 	int const param_len = 0x1;
-	int const phy_test_pattern_addr = 0x248;
 	int ret = 0;
 
-	rlen = drm_dp_dpcd_read(link->aux->drm_aux, phy_test_pattern_addr,
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PHY_PATTERN,
 			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed to read phy link pattern\n");
@@ -892,12 +846,18 @@
 static char *dp_link_get_test_name(u32 test_requested)
 {
 	switch (test_requested) {
-	case TEST_LINK_TRAINING: return DP_LINK_ENUM_STR(TEST_LINK_TRAINING);
-	case TEST_VIDEO_PATTERN: return DP_LINK_ENUM_STR(TEST_VIDEO_PATTERN);
-	case PHY_TEST_PATTERN:	 return DP_LINK_ENUM_STR(PHY_TEST_PATTERN);
-	case TEST_EDID_READ:	 return DP_LINK_ENUM_STR(TEST_EDID_READ);
-	case TEST_AUDIO_PATTERN: return DP_LINK_ENUM_STR(TEST_AUDIO_PATTERN);
-	default:		 return "unknown";
+	case DP_TEST_LINK_TRAINING:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
+	case DP_TEST_LINK_VIDEO_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
+	case DP_TEST_LINK_EDID_READ:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
+	case DP_TEST_LINK_PHY_TEST_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
+	case DP_TEST_LINK_AUDIO_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
+	default:
+		return "unknown";
 	}
 }
 
@@ -909,10 +869,12 @@
  */
 static bool dp_link_is_video_audio_test_requested(u32 link)
 {
-	return (link == TEST_VIDEO_PATTERN) ||
-		(link == (TEST_AUDIO_PATTERN | TEST_VIDEO_PATTERN)) ||
-		(link == TEST_AUDIO_PATTERN) ||
-		(link == (TEST_AUDIO_PATTERN | TEST_AUDIO_DISABLED_VIDEO));
+	return (link == DP_TEST_LINK_VIDEO_PATTERN) ||
+		(link == (DP_TEST_LINK_AUDIO_PATTERN |
+		DP_TEST_LINK_VIDEO_PATTERN)) ||
+		(link == DP_TEST_LINK_AUDIO_PATTERN) ||
+		(link == (DP_TEST_LINK_AUDIO_PATTERN |
+		DP_TEST_LINK_AUDIO_DISABLED_VIDEO));
 }
 
 /**
@@ -923,9 +885,9 @@
  */
 static bool dp_link_is_test_supported(u32 test_requested)
 {
-	return (test_requested == TEST_LINK_TRAINING) ||
-		(test_requested == TEST_EDID_READ) ||
-		(test_requested == PHY_TEST_PATTERN) ||
+	return (test_requested == DP_TEST_LINK_TRAINING) ||
+		(test_requested == DP_TEST_LINK_EDID_READ) ||
+		(test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) ||
 		dp_link_is_video_audio_test_requested(test_requested);
 }
 
@@ -961,9 +923,9 @@
 
 	pr_debug("device service irq vector = 0x%x\n", data);
 
-	if (!(data & BIT(1))) {
+	if (!(data & DP_AUTOMATED_TEST_REQUEST)) {
 		pr_debug("no test requested\n");
-		goto end;
+		return 0;
 	}
 
 	/**
@@ -988,14 +950,14 @@
 	pr_debug("%s (0x%x) requested\n", dp_link_get_test_name(data), data);
 	link->request.test_requested = data;
 
-	if (link->request.test_requested == PHY_TEST_PATTERN) {
+	if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) {
 		ret = dp_link_parse_phy_test_params(link);
 		if (ret)
 			goto end;
 		ret = dp_link_parse_link_training_params(link);
 	}
 
-	if (link->request.test_requested == TEST_LINK_TRAINING)
+	if (link->request.test_requested == DP_TEST_LINK_TRAINING)
 		ret = dp_link_parse_link_training_params(link);
 
 	if (dp_link_is_video_audio_test_requested(
@@ -1012,13 +974,13 @@
 	drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_REQUEST, buf, 1);
 
 	/**
-	 * Send a TEST_ACK if all link parameters are valid, otherwise send
-	 * a TEST_NACK.
+	 * Send a DP_TEST_ACK if all link parameters are valid, otherwise send
+	 * a DP_TEST_NAK.
 	 */
 	if (ret)
-		link->request.response = TEST_NACK;
+		link->request.response = DP_TEST_NAK;
 	else
-		link->request.response = TEST_ACK;
+		link->request.response = DP_TEST_ACK;
 
 	return ret;
 }
@@ -1069,7 +1031,7 @@
 
 static bool dp_link_is_link_training_requested(struct dp_link_private *link)
 {
-	return (link->request.test_requested == TEST_LINK_TRAINING);
+	return (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN);
 }
 
 /**
@@ -1089,7 +1051,7 @@
 		return -EINVAL;
 
 	pr_debug("%s link rate = 0x%x, lane count = 0x%x\n",
-			dp_link_get_test_name(TEST_LINK_TRAINING),
+			dp_link_get_test_name(DP_TEST_LINK_PHY_TEST_PATTERN),
 			link->request.test_link_rate,
 			link->request.test_lane_count);
 
@@ -1104,7 +1066,7 @@
 	struct dp_link_private *link = container_of(dp_link,
 			struct dp_link_private, dp_link);
 
-	return (link->request.test_requested == PHY_TEST_PATTERN);
+	return (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN);
 }
 
 static int dp_link_parse_vx_px(struct dp_link_private *link)
@@ -1112,15 +1074,14 @@
 	u8 bp;
 	u8 data;
 	int const param_len = 0x1;
-	int const addr1 = 0x206;
-	int const addr2 = 0x207;
 	int ret = 0;
 	u32 v0, p0, v1, p1, v2, p2, v3, p3;
 	int rlen;
 
 	pr_debug("\n");
 
-	rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr1, &bp, param_len);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE0_1,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed reading lanes 0/1\n");
 		ret = -EINVAL;
@@ -1141,7 +1102,8 @@
 	p1 = data & 0x3;
 	data = data >> 2;
 
-	rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr2, &bp, param_len);
+	rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE2_3,
+			&bp, param_len);
 	if (rlen < param_len) {
 		pr_err("failed reading lanes 2/3\n");
 		ret = -EINVAL;
@@ -1218,6 +1180,11 @@
 	return 0;
 }
 
+static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
+{
+	return link_status[r - DP_LANE0_1_STATUS];
+}
+
 /**
  * dp_link_process_link_status_update() - processes link status updates
  * @link: Display Port link module data
@@ -1231,7 +1198,8 @@
  */
 static int dp_link_process_link_status_update(struct dp_link_private *link)
 {
-	if (!(link->link_status[2] & BIT(7)) || /* link status updated */
+	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) &&
 	     drm_dp_channel_eq_ok(link->link_status,
@@ -1249,7 +1217,11 @@
 
 static bool dp_link_is_ds_port_status_changed(struct dp_link_private *link)
 {
-	return (link->link_status[2] & BIT(6)); /* port status changed */
+	if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
+		DP_DOWNSTREAM_PORT_STATUS_CHANGED) /* port status changed */
+		return true;
+
+	return false;
 }
 
 /**
@@ -1273,13 +1245,14 @@
 
 static bool dp_link_is_video_pattern_requested(struct dp_link_private *link)
 {
-	return (link->request.test_requested & TEST_VIDEO_PATTERN)
-		&& !(link->request.test_requested & TEST_AUDIO_DISABLED_VIDEO);
+	return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN)
+		&& !(link->request.test_requested &
+		DP_TEST_LINK_AUDIO_DISABLED_VIDEO);
 }
 
 static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link)
 {
-	return (link->request.test_requested & TEST_AUDIO_PATTERN);
+	return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN);
 }
 
 /**
@@ -1298,7 +1271,7 @@
 		goto end;
 
 	pr_debug("%s: bit depth=%d(%d bpp) pattern=%s\n",
-		dp_link_get_test_name(TEST_VIDEO_PATTERN),
+		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),
 		dp_link_video_pattern_to_string(
@@ -1349,7 +1322,6 @@
 {
 	link->request = (const struct dp_link_request){ 0 };
 	link->request.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN;
-
 	link->dp_link.test_requested = 0;
 }
 
@@ -1381,19 +1353,19 @@
 
 	ret = dp_link_process_link_training_request(link);
 	if (!ret) {
-		dp_link->test_requested |= TEST_LINK_TRAINING;
+		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 |= PHY_TEST_PATTERN;
+		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 |= LINK_STATUS_UPDATED;
+		dp_link->test_requested |= DP_LINK_STATUS_UPDATED;
 		goto exit;
 	}
 
@@ -1405,13 +1377,13 @@
 
 	ret = dp_link_process_video_pattern_request(link);
 	if (!ret) {
-		dp_link->test_requested |= TEST_VIDEO_PATTERN;
+		dp_link->test_requested |= DP_TEST_LINK_VIDEO_PATTERN;
 		goto exit;
 	}
 
 	ret = dp_link_process_audio_pattern_request(link);
 	if (!ret) {
-		dp_link->test_requested |= TEST_AUDIO_PATTERN;
+		dp_link->test_requested |= DP_TEST_LINK_AUDIO_PATTERN;
 		goto exit;
 	}
 
@@ -1532,7 +1504,7 @@
 
 static u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp)
 {
-	enum test_bit_depth tbd;
+	u32 tbd;
 
 	/*
 	 * Few simplistic rules and assumptions made here:
@@ -1554,6 +1526,9 @@
 		break;
 	}
 
+	if (tbd != DP_TEST_BIT_DEPTH_UNKNOWN)
+		tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT);
+
 	return tbd;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 8ea43da..419186f 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -31,27 +31,8 @@
 	DP_LINK_PRE_EMPHASIS_MAX	= DP_LINK_PRE_EMPHASIS_LEVEL_2,
 };
 
-enum test_type {
-	UNKNOWN_TEST		  = 0,
-	TEST_LINK_TRAINING	  = 0x01,
-	TEST_VIDEO_PATTERN	  = 0x02,
-	PHY_TEST_PATTERN	  = 0x08,
-	TEST_EDID_READ		  = 0x04,
-	TEST_AUDIO_PATTERN	  = 0x20,
-	TEST_AUDIO_DISABLED_VIDEO = 0x40,
-};
-
-enum status_update {
-	LINK_STATUS_UPDATED    = 0x100,
-	DS_PORT_STATUS_CHANGED = 0x200,
-};
-
-enum test_bit_depth {
-	DP_TEST_BIT_DEPTH_6 = 0x00,
-	DP_TEST_BIT_DEPTH_8 = 0x01,
-	DP_TEST_BIT_DEPTH_10 = 0x02,
-	DP_TEST_BIT_DEPTH_UNKNOWN = 0xFFFFFFFF,
-};
+#define DS_PORT_STATUS_CHANGED 0x200
+#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF
 
 struct dp_link {
 	u32 test_requested;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 33ef04b..5e47daf 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -142,11 +142,6 @@
 {
 	struct msm_drm_private *priv;
 
-	if (msm_is_suspend_blocked(dev)) {
-		DRM_DEBUG("rejecting commit during suspend\n");
-		return -EBUSY;
-	}
-
 	priv = dev->dev_private;
 	if (priv && priv->kms && priv->kms->funcs &&
 			priv->kms->funcs->atomic_check)
@@ -1668,12 +1663,8 @@
 static int msm_pm_suspend(struct device *dev)
 {
 	struct drm_device *ddev;
-	struct drm_modeset_acquire_ctx ctx;
-	struct drm_connector *conn;
-	struct drm_atomic_state *state;
-	struct drm_crtc_state *crtc_state;
 	struct msm_drm_private *priv;
-	int ret = 0;
+	struct msm_kms *kms;
 
 	if (!dev)
 		return -EINVAL;
@@ -1683,68 +1674,10 @@
 		return -EINVAL;
 
 	priv = ddev->dev_private;
-	SDE_EVT32(0);
+	kms = priv->kms;
 
-	/* acquire modeset lock(s) */
-	drm_modeset_acquire_init(&ctx, 0);
-
-retry:
-	ret = drm_modeset_lock_all_ctx(ddev, &ctx);
-	if (ret)
-		goto unlock;
-
-	/* save current state for resume */
-	if (priv->suspend_state)
-		drm_atomic_state_free(priv->suspend_state);
-	priv->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx);
-	if (IS_ERR_OR_NULL(priv->suspend_state)) {
-		DRM_ERROR("failed to back up suspend state\n");
-		priv->suspend_state = NULL;
-		goto unlock;
-	}
-
-	/* create atomic state to disable all CRTCs */
-	state = drm_atomic_state_alloc(ddev);
-	if (IS_ERR_OR_NULL(state)) {
-		DRM_ERROR("failed to allocate crtc disable state\n");
-		goto unlock;
-	}
-
-	state->acquire_ctx = &ctx;
-	drm_for_each_connector(conn, ddev) {
-
-		if (!conn->state || !conn->state->crtc ||
-				conn->dpms != DRM_MODE_DPMS_ON)
-			continue;
-
-		/* force CRTC to be inactive */
-		crtc_state = drm_atomic_get_crtc_state(state,
-				conn->state->crtc);
-		if (IS_ERR_OR_NULL(crtc_state)) {
-			DRM_ERROR("failed to get crtc %d state\n",
-					conn->state->crtc->base.id);
-			drm_atomic_state_free(state);
-			goto unlock;
-		}
-		crtc_state->active = false;
-	}
-
-	/* commit the "disable all" state */
-	ret = drm_atomic_commit(state);
-	if (ret < 0) {
-		DRM_ERROR("failed to disable crtcs, %d\n", ret);
-		drm_atomic_state_free(state);
-	} else {
-		priv->suspend_block = true;
-	}
-
-unlock:
-	if (ret == -EDEADLK) {
-		drm_modeset_backoff(&ctx);
-		goto retry;
-	}
-	drm_modeset_drop_locks(&ctx);
-	drm_modeset_acquire_fini(&ctx);
+	if (kms && kms->funcs && kms->funcs->pm_suspend)
+		return kms->funcs->pm_suspend(dev);
 
 	/* disable hot-plug polling */
 	drm_kms_helper_poll_disable(ddev);
@@ -1756,7 +1689,7 @@
 {
 	struct drm_device *ddev;
 	struct msm_drm_private *priv;
-	int ret;
+	struct msm_kms *kms;
 
 	if (!dev)
 		return -EINVAL;
@@ -1766,26 +1699,10 @@
 		return -EINVAL;
 
 	priv = ddev->dev_private;
+	kms = priv->kms;
 
-	SDE_EVT32(priv->suspend_state != NULL);
-
-	drm_mode_config_reset(ddev);
-
-	drm_modeset_lock_all(ddev);
-
-	priv->suspend_block = false;
-
-	if (priv->suspend_state) {
-		priv->suspend_state->acquire_ctx =
-			ddev->mode_config.acquire_ctx;
-		ret = drm_atomic_commit(priv->suspend_state);
-		if (ret < 0) {
-			DRM_ERROR("failed to restore state, %d\n", ret);
-			drm_atomic_state_free(priv->suspend_state);
-		}
-		priv->suspend_state = NULL;
-	}
-	drm_modeset_unlock_all(ddev);
+	if (kms && kms->funcs && kms->funcs->pm_resume)
+		return kms->funcs->pm_resume(dev);
 
 	/* enable hot-plug polling */
 	drm_kms_helper_poll_enable(ddev);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index c2f17c8..fc4d243 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -591,10 +591,6 @@
 	 */
 	struct task_struct *struct_mutex_task;
 
-	/* saved atomic state during system suspend */
-	struct drm_atomic_state *suspend_state;
-	bool suspend_block;
-
 	/* list of clients waiting for events */
 	struct list_head client_event_list;
 
@@ -605,12 +601,14 @@
 	struct dentry *debug_root;
 };
 
+/* get struct msm_kms * from drm_device * */
+#define ddev_to_msm_kms(D) ((D) && (D)->dev_private ? \
+		((struct msm_drm_private *)((D)->dev_private))->kms : NULL)
+
 struct msm_format {
 	uint32_t pixel_format;
 };
 
-int msm_atomic_check(struct drm_device *dev,
-		     struct drm_atomic_state *state);
 /* callback from wq once fence has passed: */
 struct msm_fence_cb {
 	struct work_struct work;
@@ -625,25 +623,6 @@
 		(_cb)->func = _func;                         \
 	} while (0)
 
-static inline bool msm_is_suspend_state(struct drm_device *dev)
-{
-	if (!dev || !dev->dev_private)
-		return false;
-
-	return ((struct msm_drm_private *)dev->dev_private)->suspend_state != 0;
-}
-
-static inline bool msm_is_suspend_blocked(struct drm_device *dev)
-{
-	if (!dev || !dev->dev_private)
-		return false;
-
-	if (!msm_is_suspend_state(dev))
-		return false;
-
-	return ((struct msm_drm_private *)dev->dev_private)->suspend_block != 0;
-}
-
 int msm_atomic_commit(struct drm_device *dev,
 		struct drm_atomic_state *state, bool nonblock);
 
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index e7fae38..76523c7 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -93,6 +93,9 @@
 	void (*lastclose)(struct msm_kms *kms);
 	int (*register_events)(struct msm_kms *kms,
 			struct drm_mode_object *obj, u32 event, bool en);
+	/* pm suspend/resume hooks */
+	int (*pm_suspend)(struct device *dev);
+	int (*pm_resume)(struct device *dev);
 	/* cleanup: */
 	void (*destroy)(struct msm_kms *kms);
 	/* get address space */
diff --git a/drivers/gpu/drm/msm/msm_prop.h b/drivers/gpu/drm/msm/msm_prop.h
index 9a53e56..d257a8c 100644
--- a/drivers/gpu/drm/msm/msm_prop.h
+++ b/drivers/gpu/drm/msm/msm_prop.h
@@ -95,6 +95,22 @@
 };
 
 /**
+ * msm_property_index_to_drm_property - get drm property struct from prop index
+ * @info: Pointer to property info container struct
+ * @property_idx: Property index
+ * Returns: drm_property pointer associated with property index
+ */
+static inline
+struct drm_property *msm_property_index_to_drm_property(
+		struct msm_property_info *info, uint32_t property_idx)
+{
+	if (!info || property_idx >= info->property_count)
+		return NULL;
+
+	return info->property_array[property_idx];
+}
+
+/**
  * msm_property_get_default - query default value of a property
  * @info: Pointer to property info container struct
  * @property_idx: Property index
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 447a6c3..946adbb 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -903,7 +903,18 @@
 	}
 
 	/* signal connector's retire fence */
-	sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, 0);
+	sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false);
+}
+
+void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts)
+{
+	if (!connector) {
+		SDE_ERROR("invalid connector\n");
+		return;
+	}
+
+	/* signal connector's retire fence */
+	sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true);
 }
 
 static enum drm_connector_status
@@ -980,6 +991,39 @@
 	return rc;
 }
 
+int sde_connector_set_property_for_commit(struct drm_connector *connector,
+		struct drm_atomic_state *atomic_state,
+		uint32_t property_idx, uint64_t value)
+{
+	struct drm_connector_state *state;
+	struct drm_property *property;
+	struct sde_connector *c_conn;
+
+	if (!connector || !atomic_state) {
+		SDE_ERROR("invalid argument(s), conn %d, state %d\n",
+				connector != NULL, atomic_state != NULL);
+		return -EINVAL;
+	}
+
+	c_conn = to_sde_connector(connector);
+	property = msm_property_index_to_drm_property(
+			&c_conn->property_info, property_idx);
+	if (!property) {
+		SDE_ERROR("invalid property index %d\n", property_idx);
+		return -EINVAL;
+	}
+
+	state = drm_atomic_get_connector_state(atomic_state, connector);
+	if (IS_ERR_OR_NULL(state)) {
+		SDE_ERROR("failed to get conn %d state\n",
+				connector->base.id);
+		return -EINVAL;
+	}
+
+	return drm_atomic_connector_set_property(
+			connector, state, property, value);
+}
+
 #ifdef CONFIG_DEBUG_FS
 /**
  * sde_connector_init_debugfs - initialize connector debugfs
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 4747d3a..69c7e8b0 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -403,6 +403,20 @@
 }
 
 /**
+ * sde_connector_set_property_for_commit - add property set to atomic state
+ *	Add a connector state property update for the specified property index
+ *	to the atomic state in preparation for a drm_atomic_commit.
+ * @connector: Pointer to drm connector
+ * @atomic_state: Pointer to DRM atomic state structure for commit
+ * @property_idx: Connector property index
+ * @value: Updated property value
+ * Returns: Zero on success
+ */
+int sde_connector_set_property_for_commit(struct drm_connector *connector,
+		struct drm_atomic_state *atomic_state,
+		uint32_t property_idx, uint64_t value);
+
+/**
  * sde_connector_init - create drm connector object for a given display
  * @dev: Pointer to drm device struct
  * @encoder: Pointer to associated encoder
@@ -435,6 +449,13 @@
 void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts);
 
 /**
+ * sde_connector_commit_reset - reset the completion signal
+ * @connector: Pointer to drm connector object
+ * @ts: timestamp to be updated in the fence signalling
+ */
+void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts);
+
+/**
  * sde_connector_get_info - query display specific information
  * @connector: Pointer to drm connector object
  * @info: Pointer to msm display information structure
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c
index dfdfc1a..1402fdd 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c
@@ -202,6 +202,44 @@
 	return ret;
 }
 
+/**
+ * sde_core_irq_disable_nolock - disable core interrupt given by the index
+ *                               without lock
+ * @sde_kms:		Pointer to sde kms context
+ * @irq_idx:		interrupt index
+ */
+int sde_core_irq_disable_nolock(struct sde_kms *sde_kms, int irq_idx)
+{
+	int ret = 0;
+
+	if (!sde_kms || !sde_kms->hw_intr || !sde_kms->irq_obj.enable_counts) {
+		SDE_ERROR("invalid params\n");
+		return -EINVAL;
+	}
+
+	if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->irq_idx_tbl_size) {
+		SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx);
+		return -EINVAL;
+	}
+
+	SDE_DEBUG("irq_idx=%d enable_count=%d\n", irq_idx,
+			atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
+
+	SDE_EVT32(irq_idx,
+			atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]));
+	if (atomic_dec_return(&sde_kms->irq_obj.enable_counts[irq_idx]) == 0) {
+		ret = sde_kms->hw_intr->ops.disable_irq_nolock(
+				sde_kms->hw_intr,
+				irq_idx);
+		if (ret)
+			SDE_ERROR("Fail to disable IRQ for irq_idx:%d\n",
+					irq_idx);
+		SDE_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret);
+	}
+
+	return ret;
+}
+
 u32 sde_core_irq_read_nolock(struct sde_kms *sde_kms, int irq_idx, bool clear)
 {
 	if (!sde_kms || !sde_kms->hw_intr ||
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.h b/drivers/gpu/drm/msm/sde/sde_core_irq.h
index c32c19c..88061c2 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.h
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.h
@@ -102,6 +102,19 @@
 		uint32_t irq_count);
 
 /**
+ * sde_core_irq_disable_nolock - no lock version of sde_core_irq_disable
+ * @sde_kms:		SDE handle
+ * @irq_idx:		Irq index
+ * @return:		0 for success disabling IRQ, otherwise failure
+ *
+ * This function increments count on each enable and decrements on each
+ * disable.  Interrupts is disabled if count is 0 after decrement.
+ */
+int sde_core_irq_disable_nolock(
+		struct sde_kms *sde_kms,
+		int irq_idx);
+
+/**
  * sde_core_irq_read - IRQ helper function for reading IRQ status
  * @sde_kms:		SDE handle
  * @irq_idx:		irq index
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index b35af0d..d992a5b 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -2041,7 +2041,7 @@
 
 	if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) {
 		SDE_ATRACE_BEGIN("signal_release_fence");
-		sde_fence_signal(&sde_crtc->output_fence, fevent->ts, 0);
+		sde_fence_signal(&sde_crtc->output_fence, fevent->ts, false);
 		SDE_ATRACE_END("signal_release_fence");
 	}
 
@@ -2868,7 +2868,7 @@
 	}
 
 	/* revert suspend actions, if necessary */
-	if (msm_is_suspend_state(crtc->dev))
+	if (sde_kms_is_suspend_state(crtc->dev))
 		_sde_crtc_set_suspend(crtc, false);
 
 	/* remove previous state, if present */
@@ -2992,7 +2992,7 @@
 	struct sde_crtc_irq_info *node = NULL;
 	struct drm_event event;
 	u32 power_on;
-	int ret;
+	int ret, i;
 
 	if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) {
 		SDE_ERROR("invalid crtc\n");
@@ -3004,7 +3004,7 @@
 
 	SDE_DEBUG("crtc%d\n", crtc->base.id);
 
-	if (msm_is_suspend_state(crtc->dev))
+	if (sde_kms_is_suspend_state(crtc->dev))
 		_sde_crtc_set_suspend(crtc, true);
 
 	mutex_lock(&sde_crtc->crtc_lock);
@@ -3067,6 +3067,15 @@
 		sde_power_handle_unregister_event(&priv->phandle,
 				sde_crtc->power_event);
 
+	/**
+	 * All callbacks are unregistered and frame done waits are complete
+	 * at this point. No buffers are accessed by hardware.
+	 * reset the fence timeline if there is any issue.
+	 */
+	sde_fence_signal(&sde_crtc->output_fence, ktime_get(), true);
+	for (i = 0; i < cstate->num_connectors; ++i)
+		sde_connector_commit_reset(cstate->connectors[i], ktime_get());
+
 	memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
 	sde_crtc->num_mixers = 0;
 
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index d2637a4..edfef24 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -637,7 +637,7 @@
 
 		if (hw_mdptop->ops.setup_split_pipe)
 			hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
-	} else {
+	} else if (sde_enc->hw_pp[0]) {
 		/*
 		 * slave encoder
 		 * - determine split index from master index,
@@ -2277,6 +2277,11 @@
 		return;
 	}
 
+	if (!phys->hw_pp) {
+		SDE_ERROR("invalid pingpong hw\n");
+		return;
+	}
+
 	ctl = phys->hw_ctl;
 	if (!ctl || !ctl->ops.trigger_flush) {
 		SDE_ERROR("missing trigger cb\n");
@@ -2318,7 +2323,12 @@
 	struct sde_hw_ctl *ctl;
 
 	if (!phys) {
-		SDE_ERROR("invalid encoder\n");
+		SDE_ERROR("invalid argument(s)\n");
+		return;
+	}
+
+	if (!phys->hw_pp) {
+		SDE_ERROR("invalid pingpong hw\n");
 		return;
 	}
 
@@ -2580,7 +2590,7 @@
 		bool active;
 
 		phys = sde_enc->phys_encs[i];
-		if (!phys || !phys->ops.update_split_role)
+		if (!phys || !phys->ops.update_split_role || !phys->hw_pp)
 			continue;
 
 		active = test_bit(i, &params->affected_displays);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 23604bd..70a25dd 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -131,6 +131,9 @@
 	struct sde_hw_ctl *ctl;
 	u32 flush_mask = 0;
 
+	if (!phys_enc)
+		return;
+
 	ctl = phys_enc->hw_ctl;
 	if (!ctl || !ctl->ops.get_bitmask_intf ||
 			!ctl->ops.update_pending_flush)
@@ -151,6 +154,9 @@
 	struct sde_hw_ctl *ctl;
 	struct sde_hw_intf_cfg intf_cfg = { 0 };
 
+	if (!phys_enc)
+		return;
+
 	ctl = phys_enc->hw_ctl;
 	if (!ctl || !ctl->ops.setup_intf_cfg)
 		return;
@@ -410,6 +416,9 @@
 				| SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
 	bool do_log = false;
 
+	if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl)
+		return -EINVAL;
+
 	cmd_enc->pp_timeout_report_cnt++;
 	if (cmd_enc->pp_timeout_report_cnt == PP_TIMEOUT_MAX_TRIALS) {
 		frame_event |= SDE_ENCODER_FRAME_EVENT_PANEL_DEAD;
@@ -603,7 +612,7 @@
 	int ret = 0;
 	int refcount;
 
-	if (!phys_enc) {
+	if (!phys_enc || !phys_enc->hw_pp) {
 		SDE_ERROR("invalid encoder\n");
 		return -EINVAL;
 	}
@@ -695,7 +704,7 @@
 	struct msm_drm_private *priv;
 	struct sde_kms *sde_kms;
 
-	if (!phys_enc) {
+	if (!phys_enc || !phys_enc->hw_pp) {
 		SDE_ERROR("invalid encoder\n");
 		return;
 	}
@@ -991,8 +1000,8 @@
 	struct sde_encoder_wait_info wait_info;
 	int ret;
 
-	if (!phys_enc) {
-		SDE_ERROR("invalid encoder\n");
+	if (!phys_enc || !phys_enc->hw_ctl) {
+		SDE_ERROR("invalid argument(s)\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 7850cb7..b7d6284 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -385,6 +385,9 @@
 		return;
 
 	hw_ctl = phys_enc->hw_ctl;
+	if (!hw_ctl)
+		return;
+
 	SDE_ATRACE_BEGIN("vblank_irq");
 
 	/* signal only for master, where there is a pending kickoff */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 2b736e5..afef192 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -156,10 +156,18 @@
 		struct drm_framebuffer *fb, const struct sde_format *format,
 		struct sde_rect *wb_roi)
 {
-	struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
-	struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg;
+	struct sde_hw_cdm *hw_cdm;
+	struct sde_hw_cdm_cfg *cdm_cfg;
 	int ret;
 
+	if (!phys_enc || !format)
+		return;
+
+	cdm_cfg = &phys_enc->cdm_cfg;
+	hw_cdm = phys_enc->hw_cdm;
+	if (!hw_cdm)
+		return;
+
 	if (!SDE_FORMAT_IS_YUV(format)) {
 		SDE_DEBUG("[cdm_disable fmt:%x]\n",
 				format->base.pixel_format);
@@ -172,6 +180,9 @@
 
 	memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg));
 
+	if (!wb_roi)
+		return;
+
 	cdm_cfg->output_width = wb_roi->w;
 	cdm_cfg->output_height = wb_roi->h;
 	cdm_cfg->output_fmt = format;
@@ -512,11 +523,18 @@
 static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
 {
 	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
-	struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
-	struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
-	struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
+	struct sde_hw_wb *hw_wb;
+	struct sde_hw_ctl *hw_ctl;
+	struct sde_hw_cdm *hw_cdm;
 	u32 flush_mask = 0;
 
+	if (!phys_enc)
+		return;
+
+	hw_wb = wb_enc->hw_wb;
+	hw_ctl = phys_enc->hw_ctl;
+	hw_cdm = phys_enc->hw_cdm;
+
 	SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
 
 	if (!hw_ctl) {
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index b654e5a..b3bc28f 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -338,7 +338,8 @@
 	return rc;
 }
 
-void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, bool is_error)
+void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
+							bool reset_timeline)
 {
 	unsigned long flags;
 	struct sde_fence *fc, *next;
@@ -348,14 +349,25 @@
 	if (!ctx) {
 		SDE_ERROR("invalid ctx, %pK\n", ctx);
 		return;
-	} else if (is_error) {
-		return;
 	}
 
 	INIT_LIST_HEAD(&local_list_head);
 
 	spin_lock_irqsave(&ctx->lock, flags);
-	if ((int)(ctx->done_count - ctx->commit_count) < 0) {
+	if (reset_timeline) {
+		if ((int)(ctx->done_count - ctx->commit_count) < 0) {
+			SDE_ERROR(
+				"timeline reset attempt! done count:%d commit:%d\n",
+				ctx->done_count, ctx->commit_count);
+			ctx->done_count = ctx->commit_count;
+			SDE_EVT32(ctx->drm_id, ctx->done_count,
+				ctx->commit_count, ktime_to_us(ts),
+				reset_timeline, SDE_EVTLOG_FATAL);
+		} else {
+			spin_unlock_irqrestore(&ctx->lock, flags);
+			return;
+		}
+	} else if ((int)(ctx->done_count - ctx->commit_count) < 0) {
 		++ctx->done_count;
 		SDE_DEBUG("fence_signal:done count:%d commit count:%d\n",
 					ctx->done_count, ctx->commit_count);
@@ -363,7 +375,7 @@
 		SDE_ERROR("extra signal attempt! done count:%d commit:%d\n",
 					ctx->done_count, ctx->commit_count);
 		SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
-			ktime_to_us(ts), SDE_EVTLOG_FATAL);
+			ktime_to_us(ts), reset_timeline, SDE_EVTLOG_FATAL);
 		spin_unlock_irqrestore(&ctx->lock, flags);
 		return;
 	}
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.h b/drivers/gpu/drm/msm/sde/sde_fence.h
index 51afdae..029175b 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.h
+++ b/drivers/gpu/drm/msm/sde/sde_fence.h
@@ -128,10 +128,10 @@
  * sde_fence_signal - advance fence timeline to signal outstanding fences
  * @fence: Pointer fence container
  * @ts: fence timestamp
- * @is_error: Set to non-zero if the commit didn't complete successfully
+ * @reset_timeline: reset the fence timeline to done count equal to commit count
  */
 void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts,
-		bool is_error);
+		bool reset_timeline);
 #else
 static inline void *sde_sync_get(uint64_t fd)
 {
@@ -170,7 +170,7 @@
 }
 
 static inline void sde_fence_signal(struct sde_fence_context *fence,
-						ktime_t ts, bool is_error)
+						ktime_t ts, bool reset_timeline)
 {
 	/* do nothing */
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 2136f9c..6880f7b 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -22,6 +22,11 @@
 #define SDE_UBWC_META_BLOCK_SIZE	256
 #define SDE_UBWC_PLANE_SIZE_ALIGNMENT	4096
 
+#define SDE_TILE_HEIGHT_DEFAULT	1
+#define SDE_TILE_HEIGHT_TILED	4
+#define SDE_TILE_HEIGHT_UBWC	4
+#define SDE_TILE_HEIGHT_NV12	8
+
 #define SDE_MAX_IMG_WIDTH		0x3FFF
 #define SDE_MAX_IMG_HEIGHT		0x3FFF
 
@@ -48,9 +53,30 @@
 	.bpp = bp,                                                        \
 	.fetch_mode = fm,                                                 \
 	.flag = {(flg)},                                                  \
-	.num_planes = np                                                  \
+	.num_planes = np,                                                 \
+	.tile_height = SDE_TILE_HEIGHT_DEFAULT                            \
 }
 
+#define INTERLEAVED_RGB_FMT_TILED(fmt, a, r, g, b, e0, e1, e2, e3, uc,    \
+alpha, bp, flg, fm, np, th)                                               \
+{                                                                         \
+	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
+	.fetch_planes = SDE_PLANE_INTERLEAVED,                            \
+	.alpha_enable = alpha,                                            \
+	.element = { (e0), (e1), (e2), (e3) },                            \
+	.bits = { g, b, r, a },                                           \
+	.chroma_sample = SDE_CHROMA_RGB,                                  \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = uc,                                               \
+	.bpp = bp,                                                        \
+	.fetch_mode = fm,                                                 \
+	.flag = {(flg)},                                                  \
+	.num_planes = np,                                                 \
+	.tile_height = th                                                 \
+}
+
+
 #define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3,              \
 alpha, chroma, count, bp, flg, fm, np)                                    \
 {                                                                         \
@@ -66,7 +92,8 @@
 	.bpp = bp,                                                        \
 	.fetch_mode = fm,                                                 \
 	.flag = {(flg)},                                                  \
-	.num_planes = np                                                  \
+	.num_planes = np,                                                 \
+	.tile_height = SDE_TILE_HEIGHT_DEFAULT                            \
 }
 
 #define PSEUDO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)      \
@@ -83,7 +110,27 @@
 	.bpp = 2,                                                         \
 	.fetch_mode = fm,                                                 \
 	.flag = {(flg)},                                                  \
-	.num_planes = np                                                  \
+	.num_planes = np,                                                 \
+	.tile_height = SDE_TILE_HEIGHT_DEFAULT                            \
+}
+
+#define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma,             \
+flg, fm, np, th)                                                          \
+{                                                                         \
+	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
+	.fetch_planes = SDE_PLANE_PSEUDO_PLANAR,                          \
+	.alpha_enable = false,                                            \
+	.element = { (e0), (e1), 0, 0 },                                  \
+	.bits = { g, b, r, a },                                           \
+	.chroma_sample = chroma,                                          \
+	.unpack_align_msb = 0,                                            \
+	.unpack_tight = 1,                                                \
+	.unpack_count = 2,                                                \
+	.bpp = 2,                                                         \
+	.fetch_mode = fm,                                                 \
+	.flag = {(flg)},                                                  \
+	.num_planes = np,                                                 \
+	.tile_height = th                                                 \
 }
 
 #define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\
@@ -100,9 +147,30 @@
 	.bpp = 2,                                                         \
 	.fetch_mode = fm,                                                 \
 	.flag = {(flg)},                                                  \
-	.num_planes = np                                                  \
+	.num_planes = np,                                                 \
+	.tile_height = SDE_TILE_HEIGHT_DEFAULT                            \
 }
 
+#define PSEUDO_YUV_FMT_LOOSE_TILED(fmt, a, r, g, b, e0, e1, chroma,       \
+flg, fm, np, th)                                                          \
+{                                                                         \
+	.base.pixel_format = DRM_FORMAT_ ## fmt,                          \
+	.fetch_planes = SDE_PLANE_PSEUDO_PLANAR,                          \
+	.alpha_enable = false,                                            \
+	.element = { (e0), (e1), 0, 0 },                                  \
+	.bits = { g, b, r, a },                                           \
+	.chroma_sample = chroma,                                          \
+	.unpack_align_msb = 1,                                            \
+	.unpack_tight = 0,                                                \
+	.unpack_count = 2,                                                \
+	.bpp = 2,                                                         \
+	.fetch_mode = fm,                                                 \
+	.flag = {(flg)},                                                  \
+	.num_planes = np,                                                 \
+	.tile_height = th                                                 \
+}
+
+
 #define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp,    \
 flg, fm, np)                                                      \
 {                                                                         \
@@ -118,7 +186,8 @@
 	.bpp = bp,                                                        \
 	.fetch_mode = fm,                                                 \
 	.flag = {(flg)},                                                  \
-	.num_planes = np                                                  \
+	.num_planes = np,                                                 \
+	.tile_height = SDE_TILE_HEIGHT_DEFAULT                            \
 }
 
 /*
@@ -414,75 +483,99 @@
  * These tables hold the A5x tile formats supported.
  */
 static const struct sde_format sde_format_map_tile[] = {
-	INTERLEAVED_RGB_FMT(ARGB8888,
+	INTERLEAVED_RGB_FMT_TILED(BGR565,
+		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+		false, 2, 0,
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+	INTERLEAVED_RGB_FMT_TILED(ARGB8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		true, 4, 0,
-		SDE_FETCH_UBWC, 1),
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
 
-	INTERLEAVED_RGB_FMT(ABGR8888,
+	INTERLEAVED_RGB_FMT_TILED(ABGR8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
 		true, 4, 0,
-		SDE_FETCH_UBWC, 1),
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
 
-	INTERLEAVED_RGB_FMT(RGBA8888,
+	INTERLEAVED_RGB_FMT_TILED(XBGR8888,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		false, 4, 0,
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+	INTERLEAVED_RGB_FMT_TILED(RGBA8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, 0,
-		SDE_FETCH_UBWC, 1),
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
 
-	INTERLEAVED_RGB_FMT(BGRA8888,
+	INTERLEAVED_RGB_FMT_TILED(BGRA8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		true, 4, 0,
-		SDE_FETCH_UBWC, 1),
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
 
-	INTERLEAVED_RGB_FMT(BGRX8888,
+	INTERLEAVED_RGB_FMT_TILED(BGRX8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
 		false, 4, 0,
-		SDE_FETCH_UBWC, 1),
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
 
-	INTERLEAVED_RGB_FMT(XRGB8888,
+	INTERLEAVED_RGB_FMT_TILED(XRGB8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
 		false, 4, 0,
-		SDE_FETCH_UBWC, 1),
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
 
-	INTERLEAVED_RGB_FMT(RGBX8888,
+	INTERLEAVED_RGB_FMT_TILED(RGBX8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		false, 4, 0,
-		SDE_FETCH_UBWC, 1),
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
 
-	PSEUDO_YUV_FMT(NV12,
+	INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		true, 4, SDE_FORMAT_FLAG_DX,
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+	INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
+		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
+		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+		true, 4, SDE_FORMAT_FLAG_DX,
+		SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED),
+
+	PSEUDO_YUV_FMT_TILED(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
 		SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
 
-	PSEUDO_YUV_FMT(NV21,
+	PSEUDO_YUV_FMT_TILED(NV21,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C1_B_Cb,
 		SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV,
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
 };
 
 static const struct sde_format sde_format_map_p010_tile[] = {
-	PSEUDO_YUV_FMT_LOOSE(NV12,
+	PSEUDO_YUV_FMT_LOOSE_TILED(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
 		SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
 };
 
 static const struct sde_format sde_format_map_tp10_tile[] = {
-	PSEUDO_YUV_FMT(NV12,
+	PSEUDO_YUV_FMT_TILED(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
 		SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX),
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12),
 };
 
 /*
@@ -492,42 +585,42 @@
  * the data will be passed by user-space.
  */
 static const struct sde_format sde_format_map_ubwc[] = {
-	INTERLEAVED_RGB_FMT(BGR565,
+	INTERLEAVED_RGB_FMT_TILED(BGR565,
 		0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
 		false, 2, SDE_FORMAT_FLAG_COMPRESSED,
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
 
-	INTERLEAVED_RGB_FMT(ABGR8888,
+	INTERLEAVED_RGB_FMT_TILED(ABGR8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, SDE_FORMAT_FLAG_COMPRESSED,
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
 
-	INTERLEAVED_RGB_FMT(XBGR8888,
+	INTERLEAVED_RGB_FMT_TILED(XBGR8888,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		false, 4, SDE_FORMAT_FLAG_COMPRESSED,
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
 
-	INTERLEAVED_RGB_FMT(ABGR2101010,
+	INTERLEAVED_RGB_FMT_TILED(ABGR2101010,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
 
-	INTERLEAVED_RGB_FMT(XBGR2101010,
+	INTERLEAVED_RGB_FMT_TILED(XBGR2101010,
 		COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
 		true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
-		SDE_FETCH_UBWC, 2),
+		SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC),
 
-	PSEUDO_YUV_FMT(NV12,
+	PSEUDO_YUV_FMT_TILED(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
 		SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV |
 				SDE_FORMAT_FLAG_COMPRESSED,
-		SDE_FETCH_UBWC, 4),
+		SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
 };
 
 static const struct sde_format sde_format_map_p010[] = {
@@ -539,21 +632,21 @@
 };
 
 static const struct sde_format sde_format_map_p010_ubwc[] = {
-	PSEUDO_YUV_FMT_LOOSE(NV12,
+	PSEUDO_YUV_FMT_LOOSE_TILED(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
 		SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX |
 				SDE_FORMAT_FLAG_COMPRESSED),
-		SDE_FETCH_UBWC, 4),
+		SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
 };
 
 static const struct sde_format sde_format_map_tp10_ubwc[] = {
-	PSEUDO_YUV_FMT(NV12,
+	PSEUDO_YUV_FMT_TILED(NV12,
 		0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
 		C1_B_Cb, C2_R_Cr,
 		SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX |
 				SDE_FORMAT_FLAG_COMPRESSED),
-		SDE_FETCH_UBWC, 4),
+		SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12),
 };
 
 /* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index b1772ed..0e1ab51 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -945,6 +945,7 @@
 	}
 
 	sblk->format_list = sde_cfg->vig_formats;
+	sblk->virt_format_list = sde_cfg->dma_formats;
 }
 
 static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg,
@@ -997,6 +998,7 @@
 	}
 
 	sblk->format_list = sde_cfg->dma_formats;
+	sblk->virt_format_list = NULL;
 }
 
 static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg,
@@ -1010,6 +1012,7 @@
 	sblk->maxupscale = SSPP_UNITY_SCALE;
 	sblk->maxdwnscale = SSPP_UNITY_SCALE;
 	sblk->format_list = sde_cfg->cursor_formats;
+	sblk->virt_format_list = NULL;
 	sspp->id = SSPP_CURSOR0 + *cursor_count;
 	snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
 			sspp->id - SSPP_VIG0);
@@ -1025,6 +1028,7 @@
 	sblk->maxupscale = SSPP_UNITY_SCALE;
 	sblk->maxdwnscale = SSPP_UNITY_SCALE;
 	sblk->format_list = sde_cfg->dma_formats;
+	sblk->virt_format_list = sde_cfg->dma_formats;
 	sspp->id = SSPP_DMA0 + *dma_count;
 	sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count;
 	snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index db5a6b4..fa10a88 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -395,6 +395,7 @@
  * @danger_vblank: danger priority during vertical blanking
  * @pixel_ram_size: size of latency hiding and de-tiling buffer in bytes
  * @smart_dma_priority: hw priority of rect1 of multirect pipe
+ * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
  * @src_blk:
  * @scaler_blk:
  * @csc_blk:
@@ -403,7 +404,7 @@
  * @pcc_blk:
  * @igc_blk:
  * @format_list: Pointer to list of supported formats
- * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps
+ * @virt_format_list: Pointer to list of supported formats for virtual planes
  */
 struct sde_sspp_sub_blks {
 	u32 maxlinewidth;
@@ -425,6 +426,7 @@
 	struct sde_pp_blk igc_blk;
 
 	const struct sde_format_extended *format_list;
+	const struct sde_format_extended *virt_format_list;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 0b3432b..3b3854d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -357,6 +357,7 @@
 		SDE_REG_WRITE(c, CTL_LAYER(LM_0 + i), 0);
 		SDE_REG_WRITE(c, CTL_LAYER_EXT(LM_0 + i), 0);
 		SDE_REG_WRITE(c, CTL_LAYER_EXT2(LM_0 + i), 0);
+		SDE_REG_WRITE(c, CTL_LAYER_EXT3(LM_0 + i), 0);
 	}
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
index 8eebf89fc..0aa7650 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
@@ -682,9 +682,89 @@
 	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 7},
 	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 7},
 
-	/* irq_idx: 256-257 */
+	/* BEGIN MAP_RANGE: 256-287 AD4_0_INTR */
+	/* irq_idx: 256-259 */
 	{ SDE_IRQ_TYPE_AD4_BL_DONE, DSPP_0, SDE_INTR_BACKLIGHT_UPDATED, 8},
-	{ SDE_IRQ_TYPE_AD4_BL_DONE, DSPP_1, SDE_INTR_BACKLIGHT_UPDATED, 9}
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	/* irq_idx: 260-263 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	/* irq_idx: 264-267 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	/* irq_idx: 268-271 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	/* irq_idx: 272-275 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	/* irq_idx: 276-279 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	/* irq_idx: 280-283 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	/* irq_idx: 284-287 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 8},
+
+	/* BEGIN MAP_RANGE: 288-319 AD4_1_INTR */
+	/* irq_idx: 288-291 */
+	{ SDE_IRQ_TYPE_AD4_BL_DONE, DSPP_1, SDE_INTR_BACKLIGHT_UPDATED, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	/* irq_idx: 292-295 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	/* irq_idx: 296-299 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	/* irq_idx: 300-303 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	/* irq_idx: 304-307 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	/* irq_idx: 308-311 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	/* irq_idx: 312-315 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	/* irq_idx: 315-319 */
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
+	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 9},
 };
 
 static int sde_hw_intr_irqidx_lookup(enum sde_intr_type intr_type,
@@ -830,10 +910,9 @@
 	return 0;
 }
 
-static int sde_hw_intr_disable_irq(struct sde_hw_intr *intr, int irq_idx)
+static int sde_hw_intr_disable_irq_nolock(struct sde_hw_intr *intr, int irq_idx)
 {
 	int reg_idx;
-	unsigned long irq_flags;
 	const struct sde_intr_reg *reg;
 	const struct sde_irq_type *irq;
 	const char *dbgstr = NULL;
@@ -851,7 +930,6 @@
 	reg_idx = irq->reg_idx;
 	reg = &sde_intr_set[reg_idx];
 
-	spin_lock_irqsave(&intr->irq_lock, irq_flags);
 	cache_irq_mask = intr->cache_irq_mask[reg_idx];
 	if ((cache_irq_mask & irq->irq_mask) == 0) {
 		dbgstr = "SDE IRQ is already cleared:";
@@ -869,7 +947,6 @@
 
 		intr->cache_irq_mask[reg_idx] = cache_irq_mask;
 	}
-	spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
 
 	pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr,
 			irq->irq_mask, cache_irq_mask);
@@ -877,6 +954,25 @@
 	return 0;
 }
 
+static int sde_hw_intr_disable_irq(struct sde_hw_intr *intr, int irq_idx)
+{
+	unsigned long irq_flags;
+
+	if (!intr)
+		return -EINVAL;
+
+	if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) {
+		pr_err("invalid IRQ index: [%d]\n", irq_idx);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&intr->irq_lock, irq_flags);
+	sde_hw_intr_disable_irq_nolock(intr, irq_idx);
+	spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
+
+	return 0;
+}
+
 static int sde_hw_intr_clear_irqs(struct sde_hw_intr *intr)
 {
 	int i;
@@ -1061,6 +1157,7 @@
 	ops->irq_idx_lookup = sde_hw_intr_irqidx_lookup;
 	ops->enable_irq = sde_hw_intr_enable_irq;
 	ops->disable_irq = sde_hw_intr_disable_irq;
+	ops->disable_irq_nolock = sde_hw_intr_disable_irq_nolock;
 	ops->dispatch_irqs = sde_hw_intr_dispatch_irq;
 	ops->clear_all_irqs = sde_hw_intr_clear_irqs;
 	ops->disable_all_irqs = sde_hw_intr_disable_irqs;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
index ced4077..0635b82 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
@@ -139,6 +139,16 @@
 			int irq_idx);
 
 	/**
+	 * disable_irq_nolock - Disable IRQ based on IRQ index without lock
+	 * @intr:	HW interrupt handle
+	 * @irq_idx:	Lookup irq index return from irq_idx_lookup
+	 * @return:	0 for success, otherwise failure
+	 */
+	int (*disable_irq_nolock)(
+			struct sde_hw_intr *intr,
+			int irq_idx);
+
+	/**
 	 * clear_all_irqs - Clears all the interrupts (i.e. acknowledges
 	 *                  any asserted IRQs). Useful during reset.
 	 * @intr:	HW interrupt handle
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index e88f40f..ff796f7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -69,9 +69,13 @@
 static int sde_hw_pp_setup_te_config(struct sde_hw_pingpong *pp,
 		struct sde_hw_tear_check *te)
 {
-	struct sde_hw_blk_reg_map *c = &pp->hw;
+	struct sde_hw_blk_reg_map *c;
 	int cfg;
 
+	if (!pp || !te)
+		return -EINVAL;
+	c = &pp->hw;
+
 	cfg = BIT(19); /*VSYNC_COUNTER_EN */
 	if (te->hw_vsync_mode)
 		cfg |= BIT(20);
@@ -149,26 +153,38 @@
 
 static void sde_hw_pp_dsc_enable(struct sde_hw_pingpong *pp)
 {
-	struct sde_hw_blk_reg_map *c = &pp->hw;
+	struct sde_hw_blk_reg_map *c;
+
+	if (!pp)
+		return;
+	c = &pp->hw;
 
 	SDE_REG_WRITE(c, PP_DSC_MODE, 1);
 }
 
 static void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp)
 {
-	struct sde_hw_blk_reg_map *c = &pp->hw;
+	struct sde_hw_blk_reg_map *c;
+
+	if (!pp)
+		return;
+	c = &pp->hw;
 
 	SDE_REG_WRITE(c, PP_DSC_MODE, 0);
 }
 
 static int sde_hw_pp_setup_dsc(struct sde_hw_pingpong *pp)
 {
-	struct sde_hw_blk_reg_map *pp_c = &pp->hw;
+	struct sde_hw_blk_reg_map *c;
 	int data;
 
-	data = SDE_REG_READ(pp_c, PP_DCE_DATA_OUT_SWAP);
+	if (!pp)
+		return -EINVAL;
+	c = &pp->hw;
+
+	data = SDE_REG_READ(c, PP_DCE_DATA_OUT_SWAP);
 	data |= BIT(18); /* endian flip */
-	SDE_REG_WRITE(pp_c, PP_DCE_DATA_OUT_SWAP, data);
+	SDE_REG_WRITE(c, PP_DCE_DATA_OUT_SWAP, data);
 	return 0;
 }
 
@@ -225,7 +241,11 @@
 
 static int sde_hw_pp_enable_te(struct sde_hw_pingpong *pp, bool enable)
 {
-	struct sde_hw_blk_reg_map *c = &pp->hw;
+	struct sde_hw_blk_reg_map *c;
+
+	if (!pp)
+		return -EINVAL;
+	c = &pp->hw;
 
 	SDE_REG_WRITE(c, PP_TEAR_CHECK_EN, enable);
 	return 0;
@@ -257,9 +277,13 @@
 static int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp,
 		struct sde_hw_pp_vsync_info *info)
 {
-	struct sde_hw_blk_reg_map *c = &pp->hw;
+	struct sde_hw_blk_reg_map *c;
 	u32 val;
 
+	if (!pp || !info)
+		return -EINVAL;
+	c = &pp->hw;
+
 	val = SDE_REG_READ(c, PP_VSYNC_INIT_VAL);
 	info->rd_ptr_init_val = val & 0xffff;
 
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 8c9c4c7..4efddb4 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -1636,6 +1636,11 @@
 	sde_kms = to_sde_kms(kms);
 	dev = sde_kms->dev;
 
+	if (sde_kms_is_suspend_blocked(dev)) {
+		SDE_DEBUG("suspended, skip atomic_check\n");
+		return -EBUSY;
+	}
+
 	ret = drm_atomic_helper_check(dev, state);
 	if (ret)
 		return ret;
@@ -1674,6 +1679,170 @@
 		sde_kms->aspace[domain] : NULL;
 }
 
+static void _sde_kms_post_open(struct msm_kms *kms, struct drm_file *file)
+{
+	struct drm_device *dev = NULL;
+	struct sde_kms *sde_kms = NULL;
+
+	if (!kms) {
+		SDE_ERROR("invalid kms\n");
+		return;
+	}
+
+	sde_kms = to_sde_kms(kms);
+	dev = sde_kms->dev;
+
+	if (!dev) {
+		SDE_ERROR("invalid device\n");
+		return;
+	}
+
+	if (dev->mode_config.funcs->output_poll_changed)
+		dev->mode_config.funcs->output_poll_changed(dev);
+}
+
+static int sde_kms_pm_suspend(struct device *dev)
+{
+	struct drm_device *ddev;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_connector *conn;
+	struct drm_atomic_state *state;
+	struct sde_kms *sde_kms;
+	int ret = 0;
+
+	if (!dev)
+		return -EINVAL;
+
+	ddev = dev_get_drvdata(dev);
+	if (!ddev || !ddev_to_msm_kms(ddev))
+		return -EINVAL;
+
+	sde_kms = to_sde_kms(ddev_to_msm_kms(ddev));
+	SDE_EVT32(0);
+
+	/* disable hot-plug polling */
+	drm_kms_helper_poll_disable(ddev);
+
+	/* acquire modeset lock(s) */
+	drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+	ret = drm_modeset_lock_all_ctx(ddev, &ctx);
+	if (ret)
+		goto unlock;
+
+	/* save current state for resume */
+	if (sde_kms->suspend_state)
+		drm_atomic_state_free(sde_kms->suspend_state);
+	sde_kms->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx);
+	if (IS_ERR_OR_NULL(sde_kms->suspend_state)) {
+		DRM_ERROR("failed to back up suspend state\n");
+		sde_kms->suspend_state = NULL;
+		goto unlock;
+	}
+
+	/* create atomic state to disable all CRTCs */
+	state = drm_atomic_state_alloc(ddev);
+	if (IS_ERR_OR_NULL(state)) {
+		DRM_ERROR("failed to allocate crtc disable state\n");
+		goto unlock;
+	}
+
+	state->acquire_ctx = &ctx;
+	drm_for_each_connector(conn, ddev) {
+		struct drm_crtc_state *crtc_state;
+		uint64_t lp;
+
+		if (!conn->state || !conn->state->crtc ||
+				conn->dpms != DRM_MODE_DPMS_ON)
+			continue;
+
+		lp = sde_connector_get_lp(conn);
+		if (lp == SDE_MODE_DPMS_LP1) {
+			/* transition LP1->LP2 on pm suspend */
+			ret = sde_connector_set_property_for_commit(conn, state,
+					CONNECTOR_PROP_LP, SDE_MODE_DPMS_LP2);
+			if (ret) {
+				DRM_ERROR("failed to set lp2 for conn %d\n",
+						conn->base.id);
+				drm_atomic_state_free(state);
+				goto unlock;
+			}
+		} else if (lp != SDE_MODE_DPMS_LP2) {
+			/* force CRTC to be inactive */
+			crtc_state = drm_atomic_get_crtc_state(state,
+					conn->state->crtc);
+			if (IS_ERR_OR_NULL(crtc_state)) {
+				DRM_ERROR("failed to get crtc %d state\n",
+						conn->state->crtc->base.id);
+				drm_atomic_state_free(state);
+				goto unlock;
+			}
+			crtc_state->active = false;
+		}
+	}
+
+	/* commit the "disable all" state */
+	ret = drm_atomic_commit(state);
+	if (ret < 0) {
+		DRM_ERROR("failed to disable crtcs, %d\n", ret);
+		drm_atomic_state_free(state);
+	} else {
+		sde_kms->suspend_block = true;
+	}
+
+unlock:
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	return 0;
+}
+
+static int sde_kms_pm_resume(struct device *dev)
+{
+	struct drm_device *ddev;
+	struct sde_kms *sde_kms;
+	int ret;
+
+	if (!dev)
+		return -EINVAL;
+
+	ddev = dev_get_drvdata(dev);
+	if (!ddev || !ddev_to_msm_kms(ddev))
+		return -EINVAL;
+
+	sde_kms = to_sde_kms(ddev_to_msm_kms(ddev));
+
+	SDE_EVT32(sde_kms->suspend_state != NULL);
+
+	drm_mode_config_reset(ddev);
+
+	drm_modeset_lock_all(ddev);
+
+	sde_kms->suspend_block = false;
+
+	if (sde_kms->suspend_state) {
+		sde_kms->suspend_state->acquire_ctx =
+			ddev->mode_config.acquire_ctx;
+		ret = drm_atomic_commit(sde_kms->suspend_state);
+		if (ret < 0) {
+			DRM_ERROR("failed to restore state, %d\n", ret);
+			drm_atomic_state_free(sde_kms->suspend_state);
+		}
+		sde_kms->suspend_state = NULL;
+	}
+	drm_modeset_unlock_all(ddev);
+
+	/* enable hot-plug polling */
+	drm_kms_helper_poll_enable(ddev);
+
+	return 0;
+}
+
 static const struct msm_kms_funcs kms_funcs = {
 	.hw_init         = sde_kms_hw_init,
 	.postinit        = sde_kms_postinit,
@@ -1694,9 +1863,12 @@
 	.atomic_check = sde_kms_atomic_check,
 	.get_format      = sde_get_msm_format,
 	.round_pixclk    = sde_kms_round_pixclk,
+	.pm_suspend      = sde_kms_pm_suspend,
+	.pm_resume       = sde_kms_pm_resume,
 	.destroy         = sde_kms_destroy,
 	.register_events = _sde_kms_register_events,
 	.get_address_space = _sde_kms_get_address_space,
+	.postopen = _sde_kms_post_open,
 };
 
 /* the caller api needs to turn on clock before calling it */
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index 0cb7008..0ddfb30 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -198,6 +198,10 @@
 
 	struct sde_core_perf perf;
 
+	/* saved atomic state during system suspend */
+	struct drm_atomic_state *suspend_state;
+	bool suspend_block;
+
 	struct sde_rm rm;
 	bool rm_init;
 
@@ -228,6 +232,33 @@
 bool sde_is_custom_client(void);
 
 /**
+ * sde_kms_is_suspend_state - whether or not the system is pm suspended
+ * @dev: Pointer to drm device
+ * Return: Suspend status
+ */
+static inline bool sde_kms_is_suspend_state(struct drm_device *dev)
+{
+	if (!ddev_to_msm_kms(dev))
+		return false;
+
+	return to_sde_kms(ddev_to_msm_kms(dev))->suspend_state != NULL;
+}
+
+/**
+ * sde_kms_is_suspend_blocked - whether or not commits are blocked due to pm
+ *				suspend status
+ * @dev: Pointer to drm device
+ * Return: True if commits should be rejected due to pm suspend
+ */
+static inline bool sde_kms_is_suspend_blocked(struct drm_device *dev)
+{
+	if (!sde_kms_is_suspend_state(dev))
+		return false;
+
+	return to_sde_kms(ddev_to_msm_kms(dev))->suspend_block;
+}
+
+/**
  * Debugfs functions - extra helper functions for debugfs support
  *
  * Main debugfs documentation is located at,
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index ef799b4..40dad76 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -73,8 +73,6 @@
 	R_MAX
 };
 
-#define TX_MODE_BUFFER_LINE_THRES 2
-
 #define SDE_QSEED3_DEFAULT_PRELOAD_H 0x4
 #define SDE_QSEED3_DEFAULT_PRELOAD_V 0x3
 
@@ -2616,14 +2614,28 @@
 	struct sde_plane *sde_plane[R_MAX];
 	const struct sde_format *fmt[R_MAX];
 	bool q16_data = true;
-	int i, buffer_lines = TX_MODE_BUFFER_LINE_THRES;
+	int i, buffer_lines;
+	unsigned int max_tile_height = 1;
 	bool parallel_fetch_qualified = true;
+	bool has_tiled_rect = false;
 
 	for (i = 0; i < R_MAX; i++) {
 		const struct msm_format *msm_fmt;
-		int width_threshold;
 
 		drm_state[i] = i ? plane->r1 : plane->r0;
+		msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
+		fmt[i] = to_sde_format(msm_fmt);
+
+		if (SDE_FORMAT_IS_UBWC(fmt[i])) {
+			has_tiled_rect = true;
+			if (fmt[i]->tile_height > max_tile_height)
+				max_tile_height = fmt[i]->tile_height;
+		}
+	}
+
+	for (i = 0; i < R_MAX; i++) {
+		int width_threshold;
+
 		pstate[i] = to_sde_plane_state(drm_state[i]);
 		sde_plane[i] = to_sde_plane(drm_state[i]->plane);
 
@@ -2645,8 +2657,6 @@
 			return -EINVAL;
 		}
 
-		msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
-		fmt[i] = to_sde_format(msm_fmt);
 		if (SDE_FORMAT_IS_YUV(fmt[i])) {
 			SDE_ERROR_PLANE(sde_plane[i],
 				"Unsupported format for multirect mode\n");
@@ -2661,7 +2671,7 @@
 		 * width for tiled formats.
 		 */
 		width_threshold = sde_plane[i]->pipe_sblk->maxlinewidth;
-		if (SDE_FORMAT_IS_UBWC(fmt[i]))
+		if (has_tiled_rect)
 			width_threshold /= 2;
 
 		if (parallel_fetch_qualified && src[i].w > width_threshold)
@@ -2680,8 +2690,7 @@
 	}
 
 	/* TIME_MX Mode */
-	if (SDE_FORMAT_IS_UBWC(fmt[R0]))
-		buffer_lines = 2 * fmt[R0]->tile_height;
+	buffer_lines = 2 * max_tile_height;
 
 	if ((dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) ||
 		(dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines)) {
@@ -3240,7 +3249,7 @@
 		psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
 
 	/* force black color fill during suspend */
-	if (msm_is_suspend_state(plane->dev) && suspend_blank)
+	if (sde_kms_is_suspend_state(plane->dev) && suspend_blank)
 		_sde_plane_color_fill(psde, 0x0, 0x0);
 
 	/* flag h/w flush complete */
@@ -3714,7 +3723,6 @@
 		{SDE_DRM_FB_SEC_DIR_TRANS, "sec_direct_translation"},
 	};
 	const struct sde_format_extended *format_list;
-	struct sde_format_extended *virt_format_list = NULL;
 	struct sde_kms_info *info;
 	struct sde_plane *psde = to_sde_plane(plane);
 	int zpos_max = 255;
@@ -3857,29 +3865,10 @@
 		DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
 	sde_kms_info_reset(info);
 
-	format_list = psde->pipe_sblk->format_list;
-
-	if (master_plane_id) {
-		int index, array_size;
-
-		array_size = ARRAY_SIZE(plane_formats)
-					+ ARRAY_SIZE(rgb_10bit_formats);
-		virt_format_list = kcalloc(array_size,
-				sizeof(struct sde_format_extended), GFP_KERNEL);
-		if (!virt_format_list) {
-			SDE_ERROR(
-			"failed to allocate virtual pipe format list\n");
-			return;
-		}
-
-		index = sde_copy_formats(virt_format_list, array_size,
-				0, plane_formats, ARRAY_SIZE(plane_formats));
-		sde_copy_formats(virt_format_list, array_size,
-				index, rgb_10bit_formats,
-				ARRAY_SIZE(rgb_10bit_formats));
-
-		format_list = virt_format_list;
-
+	if (!master_plane_id) {
+		format_list = psde->pipe_sblk->format_list;
+	} else {
+		format_list = psde->pipe_sblk->virt_format_list;
 		sde_kms_info_add_keyint(info, "primary_smart_plane_id",
 						master_plane_id);
 	}
@@ -3916,7 +3905,6 @@
 			PLANE_PROP_INFO);
 
 	kfree(info);
-	kfree(virt_format_list);
 
 	if (psde->features & BIT(SDE_SSPP_MEMCOLOR)) {
 		snprintf(feature_name, sizeof(feature_name), "%s%d",
@@ -4664,7 +4652,6 @@
 {
 	struct drm_plane *plane = NULL, *master_plane = NULL;
 	const struct sde_format_extended *format_list;
-	struct sde_format_extended *virt_format_list = NULL;
 	struct sde_plane *psde;
 	struct msm_drm_private *priv;
 	struct sde_kms *kms;
@@ -4733,30 +4720,10 @@
 		goto clean_sspp;
 	}
 
-	format_list = psde->pipe_sblk->format_list;
-
-	if (master_plane_id) {
-		int index, array_size;
-
-		array_size = ARRAY_SIZE(plane_formats)
-					+ ARRAY_SIZE(rgb_10bit_formats);
-		virt_format_list = kcalloc(array_size,
-					sizeof(struct sde_format_extended),
-					GFP_KERNEL);
-		if (!virt_format_list) {
-			SDE_ERROR(
-			"failed to allocate virtual pipe format list\n");
-			goto clean_sspp;
-		}
-
-		index = sde_copy_formats(virt_format_list, array_size,
-				0, plane_formats, ARRAY_SIZE(plane_formats));
-		sde_copy_formats(virt_format_list, array_size,
-				index, rgb_10bit_formats,
-				ARRAY_SIZE(rgb_10bit_formats));
-
-		format_list = virt_format_list;
-	}
+	if (!master_plane_id)
+		format_list = psde->pipe_sblk->format_list;
+	else
+		format_list = psde->pipe_sblk->virt_format_list;
 
 	psde->nformats = sde_populate_formats(format_list,
 				psde->formats,
@@ -4805,6 +4772,5 @@
 clean_plane:
 	kfree(psde);
 exit:
-	kfree(virt_format_list);
 	return ERR_PTR(ret);
 }
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6426363..2dae758 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1451,6 +1451,10 @@
 	/* make sure ADRENO_DEVICE_STARTED is not set here */
 	BUG_ON(test_bit(ADRENO_DEVICE_STARTED, &adreno_dev->priv));
 
+	/* disallow l2pc during wake up to improve GPU wake up time */
+	kgsl_pwrctrl_update_l2pc(&adreno_dev->dev,
+			KGSL_L2PC_WAKEUP_TIMEOUT);
+
 	pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
 			pmqos_wakeup_vote);
 
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 01b877f..a4c189f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -397,6 +397,8 @@
  * @profile_buffer: Memdesc holding the drawobj profiling buffer
  * @profile_index: Index to store the start/stop ticks in the profiling
  * buffer
+ * @pwrup_reglist: Memdesc holding the power up register list
+ * which is used by CP during preemption and IFPC
  * @sp_local_gpuaddr: Base GPU virtual address for SP local memory
  * @sp_pvt_gpuaddr: Base GPU virtual address for SP private memory
  * @lm_fw: The LM firmware handle
@@ -453,6 +455,7 @@
 
 	struct kgsl_memdesc profile_buffer;
 	unsigned int profile_index;
+	struct kgsl_memdesc pwrup_reglist;
 	uint64_t sp_local_gpuaddr;
 	uint64_t sp_pvt_gpuaddr;
 	const struct firmware *lm_fw;
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 7e9482a..386c3a9 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -210,6 +210,40 @@
 	{ 0xA630, 0x0, 1 },
 };
 
+static struct reg_list_pair {
+	uint32_t offset;
+	uint32_t val;
+} a6xx_pwrup_reglist[] = {
+	{ A6XX_VSC_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_GRAS_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_RB_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_PC_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_HLSQ_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_VFD_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_VPC_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_UCHE_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_SP_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_TPL1_ADDR_MODE_CNTL, 0x0 },
+	{ A6XX_UCHE_WRITE_RANGE_MAX_LO, 0x0 },
+	{ A6XX_UCHE_WRITE_RANGE_MAX_HI, 0x0 },
+	{ A6XX_UCHE_TRAP_BASE_LO, 0x0 },
+	{ A6XX_UCHE_TRAP_BASE_HI, 0x0 },
+	{ A6XX_UCHE_WRITE_THRU_BASE_LO, 0x0 },
+	{ A6XX_UCHE_WRITE_THRU_BASE_HI, 0x0 },
+	{ A6XX_UCHE_GMEM_RANGE_MIN_LO, 0x0 },
+	{ A6XX_UCHE_GMEM_RANGE_MIN_HI, 0x0 },
+	{ A6XX_UCHE_GMEM_RANGE_MAX_LO, 0x0 },
+	{ A6XX_UCHE_GMEM_RANGE_MAX_HI, 0x0 },
+	{ A6XX_UCHE_FILTER_CNTL, 0x0 },
+	{ A6XX_UCHE_CACHE_WAYS, 0x0 },
+	{ A6XX_UCHE_MODE_CNTL, 0x0 },
+	{ A6XX_RB_NC_MODE_CNTL, 0x0 },
+	{ A6XX_TPL1_NC_MODE_CNTL, 0x0 },
+	{ A6XX_SP_NC_MODE_CNTL, 0x0 },
+	{ A6XX_PC_DBG_ECO_CNTL, 0x0 },
+	{ A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x0 },
+};
+
 static void a6xx_platform_setup(struct adreno_device *adreno_dev)
 {
 	uint64_t addr;
@@ -233,6 +267,21 @@
 		A6XX_CP_ALWAYS_ON_COUNTER_HI;
 }
 
+static void a6xx_pwrup_reglist_init(struct adreno_device *adreno_dev)
+{
+	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
+
+	if (kgsl_allocate_global(device, &adreno_dev->pwrup_reglist,
+		PAGE_SIZE, 0, KGSL_MEMDESC_PRIVILEGED,
+		"powerup_register_list")) {
+		adreno_dev->pwrup_reglist.gpuaddr = 0;
+		return;
+	}
+
+	kgsl_sharedmem_set(device, &adreno_dev->pwrup_reglist, 0, 0,
+		PAGE_SIZE);
+}
+
 static void a6xx_init(struct adreno_device *adreno_dev)
 {
 	a6xx_crashdump_init(adreno_dev);
@@ -243,6 +292,8 @@
 	 */
 	if (!kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev)))
 		_update_always_on_regs(adreno_dev);
+
+	a6xx_pwrup_reglist_init(adreno_dev);
 }
 
 /**
@@ -375,6 +426,22 @@
 	return adreno_dev->lm_limit;
 }
 
+static void a6xx_patch_pwrup_reglist(struct adreno_device *adreno_dev)
+{
+	uint32_t i;
+
+	/* Set up the register values */
+	for (i = 0; i < ARRAY_SIZE(a6xx_pwrup_reglist); i++) {
+		struct reg_list_pair *r = &a6xx_pwrup_reglist[i];
+
+		kgsl_regread(KGSL_DEVICE(adreno_dev), r->offset, &r->val);
+	}
+
+	/* Copy Preemption register/data pairs */
+	memcpy(adreno_dev->pwrup_reglist.hostptr, &a6xx_pwrup_reglist,
+		sizeof(a6xx_pwrup_reglist));
+}
+
 /*
  * a6xx_start() - Device start
  * @adreno_dev: Pointer to adreno device
@@ -386,6 +453,7 @@
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	unsigned int bit, mal, mode, glbl_inv;
 	unsigned int amsbc = 0;
+	static bool patch_reglist;
 
 	/* runtime adjust callbacks based on feature sets */
 	if (!kgsl_gmu_isenabled(device))
@@ -488,9 +556,9 @@
 	kgsl_regwrite(device, A6XX_UCHE_MODE_CNTL, (glbl_inv << 29) |
 						(mal << 23) | (bit << 21));
 
-	/* Set hang detection threshold to 4 million cycles (0x3FFFF*16) */
+	/* Set hang detection threshold to 0x1FFFFF * 16 cycles */
 	kgsl_regwrite(device, A6XX_RBBM_INTERFACE_HANG_INT_CNTL,
-					  (1 << 30) | 0x3ffff);
+					  (1 << 30) | 0x1fffff);
 
 	kgsl_regwrite(device, A6XX_UCHE_CLIENT_PF, 1);
 
@@ -503,6 +571,11 @@
 		kgsl_regwrite(device, A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE,
 			0x1);
 
+	if (!patch_reglist && (adreno_dev->pwrup_reglist.gpuaddr != 0)) {
+		a6xx_patch_pwrup_reglist(adreno_dev);
+		patch_reglist = true;
+	}
+
 	a6xx_preemption_start(adreno_dev);
 	a6xx_protect_init(adreno_dev);
 }
@@ -570,12 +643,16 @@
  */
 #define CP_INIT_OPERATION_MODE_MASK BIT(6)
 
+/* Register initialization list */
+#define CP_INIT_REGISTER_INIT_LIST BIT(7)
+
 #define CP_INIT_MASK (CP_INIT_MAX_CONTEXT | \
 		CP_INIT_ERROR_DETECTION_CONTROL | \
 		CP_INIT_HEADER_DUMP | \
 		CP_INIT_DEFAULT_RESET_STATE | \
 		CP_INIT_UCODE_WORKAROUND_MASK | \
-		CP_INIT_OPERATION_MODE_MASK)
+		CP_INIT_OPERATION_MODE_MASK | \
+		CP_INIT_REGISTER_INIT_LIST)
 
 static void _set_ordinals(struct adreno_device *adreno_dev,
 		unsigned int *cmds, unsigned int count)
@@ -611,6 +688,15 @@
 	if (CP_INIT_MASK & CP_INIT_OPERATION_MODE_MASK)
 		*cmds++ = 0x00000002;
 
+	if (CP_INIT_MASK & CP_INIT_REGISTER_INIT_LIST) {
+		uint64_t gpuaddr = adreno_dev->pwrup_reglist.gpuaddr;
+
+		*cmds++ = lower_32_bits(gpuaddr);
+		*cmds++ = upper_32_bits(gpuaddr);
+		/* Size is in dwords */
+		*cmds++ = sizeof(a6xx_pwrup_reglist) >> 2;
+	}
+
 	/* Pad rest of the cmds with 0's */
 	while ((unsigned int)(cmds - start) < count)
 		*cmds++ = 0x0;
@@ -629,13 +715,13 @@
 	unsigned int *cmds;
 	int ret;
 
-	cmds = adreno_ringbuffer_allocspace(rb, 9);
+	cmds = adreno_ringbuffer_allocspace(rb, 12);
 	if (IS_ERR(cmds))
 		return PTR_ERR(cmds);
 
-	*cmds++ = cp_type7_packet(CP_ME_INIT, 8);
+	*cmds++ = cp_type7_packet(CP_ME_INIT, 11);
 
-	_set_ordinals(adreno_dev, cmds, 8);
+	_set_ordinals(adreno_dev, cmds, 11);
 
 	ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000);
 	if (ret)
@@ -2207,7 +2293,9 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 
-	a6xx_preemption_trigger(adreno_dev);
+	if (adreno_is_preemption_enabled(adreno_dev))
+		a6xx_preemption_trigger(adreno_dev);
+
 	adreno_dispatcher_schedule(device);
 }
 
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 6264574..80c9a61 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -260,7 +260,7 @@
 	0x1F942, 0x1F944, 0x1F94C, 0x1F94D, 0x1F94F, 0x1F951, 0x1F954, 0x1F954,
 	0x1F957, 0x1F958, 0x1F95D, 0x1F95D, 0x1F962, 0x1F962, 0x1F964, 0x1F965,
 	0x1F980, 0x1F986, 0x1F990, 0x1F99E, 0x1F9C0, 0x1F9C0, 0x1F9C5, 0x1F9CC,
-	0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA03,
+	0x1F9E0, 0x1F9E2, 0x1F9F0, 0x1F9F0, 0x1FA00, 0x1FA01,
 	/* GPU RSCC */
 	0x2348C, 0x2348C, 0x23501, 0x23502, 0x23740, 0x23742, 0x23744, 0x23747,
 	0x2374C, 0x23787, 0x237EC, 0x237EF, 0x237F4, 0x2382F, 0x23894, 0x23897,
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 0a45d27..8fd8b88 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1464,7 +1464,9 @@
 
 	spin_unlock(&drawctxt->lock);
 
-	kgsl_pwrctrl_update_l2pc(&adreno_dev->dev);
+	if (device->pwrctrl.l2pc_update_queue)
+		kgsl_pwrctrl_update_l2pc(&adreno_dev->dev,
+				KGSL_L2PC_QUEUE_TIMEOUT);
 
 	/* Add the context to the dispatcher pending list */
 	dispatcher_queue_context(adreno_dev, drawctxt);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 6bad70b..2cc1869 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -85,7 +85,12 @@
 	{ KGSL_CONTEXT_NO_FAULT_TOLERANCE, "NO_FT" }, \
 	{ KGSL_CONTEXT_INVALIDATE_ON_FAULT, "INVALIDATE_ON_FAULT" }, \
 	{ KGSL_CONTEXT_PWR_CONSTRAINT, "PWR" }, \
-	{ KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" }
+	{ KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" }, \
+	{ KGSL_CONTEXT_IFH_NOP, "IFH_NOP" }, \
+	{ KGSL_CONTEXT_SECURE, "SECURE" }, \
+	{ KGSL_CONTEXT_NO_SNAPSHOT, "NO_SNAPSHOT" }, \
+	{ KGSL_CONTEXT_SPARSE, "SPARSE" }
+
 
 #define KGSL_CONTEXT_TYPES \
 	{ KGSL_CONTEXT_TYPE_ANY, "ANY" }, \
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 2999fb2..8cca248 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -44,13 +44,6 @@
 
 #define DEFAULT_BUS_P 25
 
-/*
- * The effective duration of qos request in usecs. After
- * timeout, qos request is cancelled automatically.
- * Kept 80ms default, inline with default GPU idle time.
- */
-#define KGSL_L2PC_CPU_TIMEOUT	(80 * 1000)
-
 /* Order deeply matters here because reasons. New entries go on the end */
 static const char * const clocks[] = {
 	"src_clk",
@@ -544,12 +537,14 @@
 /**
  * kgsl_pwrctrl_update_l2pc() - Update existing qos request
  * @device: Pointer to the kgsl_device struct
+ * @timeout_us: the effective duration of qos request in usecs.
  *
  * Updates an existing qos request to avoid L2PC on the
  * CPUs (which are selected through dtsi) on which GPU
  * thread is running. This would help for performance.
  */
-void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device)
+void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device,
+			unsigned long timeout_us)
 {
 	int cpu;
 
@@ -563,7 +558,7 @@
 		pm_qos_update_request_timeout(
 				&device->pwrctrl.l2pc_cpus_qos,
 				device->pwrctrl.pm_qos_cpu_mask_latency,
-				KGSL_L2PC_CPU_TIMEOUT);
+				timeout_us);
 	}
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_update_l2pc);
@@ -2194,6 +2189,10 @@
 	kgsl_property_read_u32(device, "qcom,l2pc-cpu-mask",
 			&pwr->l2pc_cpus_mask);
 
+	pwr->l2pc_update_queue = of_property_read_bool(
+				device->pdev->dev.of_node,
+				"qcom,l2pc-update-queue");
+
 	pm_runtime_enable(&pdev->dev);
 
 	ocmem_bus_node = of_find_node_by_name(
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 65e047d..53bb255 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -50,6 +50,19 @@
 #define KGSL_PWR_DEL_LIMIT 1
 #define KGSL_PWR_SET_LIMIT 2
 
+/*
+ * The effective duration of qos request in usecs at queue time.
+ * After timeout, qos request is cancelled automatically.
+ * Kept 80ms default, inline with default GPU idle time.
+ */
+#define KGSL_L2PC_QUEUE_TIMEOUT	(80 * 1000)
+
+/*
+ * The effective duration of qos request in usecs at wakeup time.
+ * After timeout, qos request is cancelled automatically.
+ */
+#define KGSL_L2PC_WAKEUP_TIMEOUT (10 * 1000)
+
 enum kgsl_pwrctrl_timer_type {
 	KGSL_PWR_IDLE_TIMER,
 };
@@ -127,6 +140,7 @@
  * @irq_name - resource name for the IRQ
  * @clk_stats - structure of clock statistics
  * @l2pc_cpus_mask - mask to avoid L2PC on masked CPUs
+ * @l2pc_update_queue - Boolean flag to avoid L2PC on masked CPUs at queue time
  * @l2pc_cpus_qos - qos structure to avoid L2PC on CPUs
  * @pm_qos_req_dma - the power management quality of service structure
  * @pm_qos_active_latency - allowed CPU latency in microseconds when active
@@ -180,6 +194,7 @@
 	const char *irq_name;
 	struct kgsl_clk_stats clk_stats;
 	unsigned int l2pc_cpus_mask;
+	bool l2pc_update_queue;
 	struct pm_qos_request l2pc_cpus_qos;
 	struct pm_qos_request pm_qos_req_dma;
 	unsigned int pm_qos_active_latency;
@@ -244,5 +259,6 @@
 void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy);
 void kgsl_pwrctrl_set_constraint(struct kgsl_device *device,
 			struct kgsl_pwr_constraint *pwrc, uint32_t id);
-void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device);
+void kgsl_pwrctrl_update_l2pc(struct kgsl_device *device,
+			unsigned long timeout_us);
 #endif /* __KGSL_PWRCTRL_H */
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index bf93b91..a06a6c7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -332,9 +332,17 @@
 	u32 value;
 };
 
+/*
+ * attach_count
+ *	The SMR and S2CR registers are only programmed when the number of
+ *	devices attached to the iommu using these registers is > 0. This
+ *	is required for the "SID switch" use case for secure display.
+ *	Protected by stream_map_mutex.
+ */
 struct arm_smmu_s2cr {
 	struct iommu_group		*group;
 	int				count;
+	int				attach_count;
 	enum arm_smmu_s2cr_type		type;
 	enum arm_smmu_s2cr_privcfg	privcfg;
 	u8				cbndx;
@@ -790,6 +798,28 @@
 	WARN_ON(msm_bus_scale_client_update_request(pwr->bus_client, 0));
 }
 
+static int arm_smmu_enable_regulators(struct arm_smmu_power_resources *pwr)
+{
+	struct regulator_bulk_data *consumers;
+	int num_consumers, ret;
+	int i;
+
+	num_consumers = pwr->num_gdscs;
+	consumers = pwr->gdscs;
+	for (i = 0; i < num_consumers; i++) {
+		ret = regulator_enable(consumers[i].consumer);
+		if (ret)
+			goto out;
+	}
+	return 0;
+
+out:
+	i -= 1;
+	for (; i >= 0; i--)
+		regulator_disable(consumers[i].consumer);
+	return ret;
+}
+
 static int arm_smmu_disable_regulators(struct arm_smmu_power_resources *pwr)
 {
 	struct regulator_bulk_data *consumers;
@@ -878,7 +908,7 @@
 	if (ret)
 		goto out_unlock;
 
-	ret = regulator_bulk_enable(pwr->num_gdscs, pwr->gdscs);
+	ret = arm_smmu_enable_regulators(pwr);
 	if (ret)
 		goto out_disable_bus;
 
@@ -1227,7 +1257,7 @@
 	phys_addr_t phys_soft;
 	u32 frsynra;
 	bool non_fatal_fault = !!(smmu_domain->attributes &
-					DOMAIN_ATTR_NON_FATAL_FAULTS);
+					(1 << DOMAIN_ATTR_NON_FATAL_FAULTS));
 
 	static DEFINE_RATELIMIT_STATE(_rs,
 				      DEFAULT_RATELIMIT_INTERVAL,
@@ -1988,11 +2018,9 @@
 	}
 	iommu_group_put(group);
 
-	/* It worked! Now, poke the actual hardware */
-	for_each_cfg_sme(fwspec, i, idx) {
-		arm_smmu_write_sme(smmu, idx);
+	/* It worked! Don't poke the actual hardware until we've attached */
+	for_each_cfg_sme(fwspec, i, idx)
 		smmu->s2crs[idx].group = group;
-	}
 
 	mutex_unlock(&smmu->stream_map_mutex);
 	return 0;
@@ -2021,6 +2049,33 @@
 	mutex_unlock(&smmu->stream_map_mutex);
 }
 
+static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
+					  struct iommu_fwspec *fwspec)
+{
+	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct arm_smmu_s2cr *s2cr = smmu->s2crs;
+	int i, idx;
+	const struct iommu_gather_ops *tlb;
+
+	tlb = smmu_domain->pgtbl_cfg.tlb;
+
+	mutex_lock(&smmu->stream_map_mutex);
+	for_each_cfg_sme(fwspec, i, idx) {
+		WARN_ON(s2cr[idx].attach_count == 0);
+		s2cr[idx].attach_count -= 1;
+
+		if (s2cr[idx].attach_count > 0)
+			continue;
+
+		writel_relaxed(0, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx));
+		writel_relaxed(0, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx));
+	}
+	mutex_unlock(&smmu->stream_map_mutex);
+
+	/* Ensure there are no stale mappings for this context bank */
+	tlb->tlb_flush_all(smmu_domain);
+}
+
 static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
 				      struct iommu_fwspec *fwspec)
 {
@@ -2030,15 +2085,17 @@
 	u8 cbndx = smmu_domain->cfg.cbndx;
 	int i, idx;
 
+	mutex_lock(&smmu->stream_map_mutex);
 	for_each_cfg_sme(fwspec, i, idx) {
-		if (type == s2cr[idx].type && cbndx == s2cr[idx].cbndx)
+		if (s2cr[idx].attach_count++ > 0)
 			continue;
 
 		s2cr[idx].type = type;
 		s2cr[idx].privcfg = S2CR_PRIVCFG_DEFAULT;
 		s2cr[idx].cbndx = cbndx;
-		arm_smmu_write_s2cr(smmu, idx);
+		arm_smmu_write_sme(smmu, idx);
 	}
+	mutex_unlock(&smmu->stream_map_mutex);
 
 	return 0;
 }
@@ -2048,6 +2105,7 @@
 {
 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
 	struct arm_smmu_device *smmu = smmu_domain->smmu;
+	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
 	int dynamic = smmu_domain->attributes & (1 << DOMAIN_ATTR_DYNAMIC);
 	int atomic_domain = smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC);
 
@@ -2059,6 +2117,8 @@
 		return;
 	}
 
+	arm_smmu_domain_remove_master(smmu_domain, fwspec);
+
 	/* Remove additional vote for atomic power */
 	if (atomic_domain) {
 		WARN_ON(arm_smmu_power_on_atomic(smmu->pwr));
@@ -4247,36 +4307,6 @@
 	u32				halt_count;
 };
 
-static int qsmmuv500_tbu_power_on_all(struct arm_smmu_device *smmu)
-{
-	struct qsmmuv500_tbu_device *tbu;
-	struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-	int ret = 0;
-
-	list_for_each_entry(tbu, &data->tbus, list) {
-		ret = arm_smmu_power_on(tbu->pwr);
-		if (ret)
-			break;
-	}
-	if (!ret)
-		return 0;
-
-	list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
-		arm_smmu_power_off(tbu->pwr);
-	}
-	return ret;
-}
-
-static void qsmmuv500_tbu_power_off_all(struct arm_smmu_device *smmu)
-{
-	struct qsmmuv500_tbu_device *tbu;
-	struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-
-	list_for_each_entry_reverse(tbu, &data->tbus, list) {
-		arm_smmu_power_off(tbu->pwr);
-	}
-}
-
 static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu)
 {
 	unsigned long flags;
@@ -4335,37 +4365,6 @@
 	spin_unlock_irqrestore(&tbu->halt_lock, flags);
 }
 
-static int qsmmuv500_halt_all(struct arm_smmu_device *smmu)
-{
-	struct qsmmuv500_tbu_device *tbu;
-	struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-	int ret = 0;
-
-	list_for_each_entry(tbu, &data->tbus, list) {
-		ret = qsmmuv500_tbu_halt(tbu);
-		if (ret)
-			break;
-	}
-
-	if (!ret)
-		return 0;
-
-	list_for_each_entry_continue_reverse(tbu, &data->tbus, list) {
-		qsmmuv500_tbu_resume(tbu);
-	}
-	return ret;
-}
-
-static void qsmmuv500_resume_all(struct arm_smmu_device *smmu)
-{
-	struct qsmmuv500_tbu_device *tbu;
-	struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-
-	list_for_each_entry(tbu, &data->tbus, list) {
-		qsmmuv500_tbu_resume(tbu);
-	}
-}
-
 static struct qsmmuv500_tbu_device *qsmmuv500_find_tbu(
 	struct arm_smmu_device *smmu, u32 sid)
 {
@@ -4380,24 +4379,6 @@
 	return NULL;
 }
 
-static void qsmmuv500_device_reset(struct arm_smmu_device *smmu)
-{
-	int i, ret;
-	struct arm_smmu_impl_def_reg *regs = smmu->impl_def_attach_registers;
-
-	ret = qsmmuv500_tbu_power_on_all(smmu);
-	if (ret)
-		return;
-
-	/* Program implementation defined registers */
-	qsmmuv500_halt_all(smmu);
-	for (i = 0; i < smmu->num_impl_def_attach_registers; ++i)
-		writel_relaxed(regs[i].value,
-			ARM_SMMU_GR0(smmu) + regs[i].offset);
-	qsmmuv500_resume_all(smmu);
-	qsmmuv500_tbu_power_off_all(smmu);
-}
-
 static int qsmmuv500_ecats_lock(struct arm_smmu_domain *smmu_domain,
 				struct qsmmuv500_tbu_device *tbu,
 				unsigned long *flags)
@@ -4635,7 +4616,6 @@
 
 struct arm_smmu_arch_ops qsmmuv500_arch_ops = {
 	.init = qsmmuv500_arch_init,
-	.device_reset = qsmmuv500_device_reset,
 	.iova_to_phys_hard = qsmmuv500_iova_to_phys_hard,
 };
 
diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c
index 2db06b0..04a9d7f 100644
--- a/drivers/iommu/io-pgtable-fast.c
+++ b/drivers/iommu/io-pgtable-fast.c
@@ -255,16 +255,17 @@
 	__av8l_fast_unmap(ptep, size, true);
 }
 
-/* upper layer must take care of TLB invalidation */
 static size_t av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova,
 			      size_t size)
 {
 	struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops);
+	struct io_pgtable *iop = &data->iop;
 	av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, iova);
 	unsigned long nptes = size >> AV8L_FAST_PAGE_SHIFT;
 
 	__av8l_fast_unmap(ptep, size, false);
 	dmac_clean_range(ptep, ptep + nptes);
+	io_pgtable_tlb_flush_all(iop);
 
 	return size;
 }
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 400839d..785d689 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -668,18 +668,9 @@
 	  LEDs in both PWM and light pattern generator (LPG) modes.  For older
 	  PMICs, it also supports WLEDs and flash LEDs.
 
-config LEDS_QPNP_FLASH
-	tristate "Support for QPNP Flash LEDs"
-	depends on LEDS_CLASS && SPMI
-	help
-	  This driver supports the flash LED functionality of Qualcomm
-	  Technologies, Inc. QPNP PMICs.  This driver supports PMICs up through
-	  PM8994.  It can configure the flash LED target current for several
-	  independent channels.
-
 config LEDS_QPNP_FLASH_V2
 	tristate "Support for QPNP V2 Flash LEDs"
-	depends on LEDS_CLASS && MFD_SPMI_PMIC && !LEDS_QPNP_FLASH
+	depends on LEDS_CLASS && MFD_SPMI_PMIC
 	help
 	  This driver supports the flash V2 LED functionality of Qualcomm
 	  Technologies, Inc. QPNP PMICs.  This driver supports PMICs starting
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index ba9bb8d..2ff9a7c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -72,7 +72,6 @@
 obj-$(CONFIG_LEDS_PM8058)		+= leds-pm8058.o
 obj-$(CONFIG_LEDS_MLXCPLD)		+= leds-mlxcpld.o
 obj-$(CONFIG_LEDS_QPNP)			+= leds-qpnp.o
-obj-$(CONFIG_LEDS_QPNP_FLASH)		+= leds-qpnp-flash.o
 obj-$(CONFIG_LEDS_QPNP_FLASH_V2)	+= leds-qpnp-flash-v2.o
 obj-$(CONFIG_LEDS_QPNP_WLED)		+= leds-qpnp-wled.o
 obj-$(CONFIG_LEDS_QPNP_HAPTICS)	+= leds-qpnp-haptics.o
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
deleted file mode 100644
index c27c059..0000000
--- a/drivers/leds/leds-qpnp-flash.c
+++ /dev/null
@@ -1,2649 +0,0 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/regmap.h>
-#include <linux/errno.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/of_device.h>
-#include <linux/spmi.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <linux/power_supply.h>
-#include <linux/leds-qpnp-flash.h>
-#include <linux/qpnp/qpnp-adc.h>
-#include <linux/qpnp/qpnp-revid.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include "leds.h"
-
-#define FLASH_LED_PERIPHERAL_SUBTYPE(base)			(base + 0x05)
-#define FLASH_SAFETY_TIMER(base)				(base + 0x40)
-#define FLASH_MAX_CURRENT(base)					(base + 0x41)
-#define FLASH_LED0_CURRENT(base)				(base + 0x42)
-#define FLASH_LED1_CURRENT(base)				(base + 0x43)
-#define	FLASH_CLAMP_CURRENT(base)				(base + 0x44)
-#define FLASH_MODULE_ENABLE_CTRL(base)				(base + 0x46)
-#define	FLASH_LED_STROBE_CTRL(base)				(base + 0x47)
-#define FLASH_LED_TMR_CTRL(base)				(base + 0x48)
-#define FLASH_HEADROOM(base)					(base + 0x4A)
-#define	FLASH_STARTUP_DELAY(base)				(base + 0x4B)
-#define FLASH_MASK_ENABLE(base)					(base + 0x4C)
-#define FLASH_VREG_OK_FORCE(base)				(base + 0x4F)
-#define FLASH_FAULT_DETECT(base)				(base + 0x51)
-#define	FLASH_THERMAL_DRATE(base)				(base + 0x52)
-#define	FLASH_CURRENT_RAMP(base)				(base + 0x54)
-#define	FLASH_VPH_PWR_DROOP(base)				(base + 0x5A)
-#define	FLASH_HDRM_SNS_ENABLE_CTRL0(base)			(base + 0x5C)
-#define	FLASH_HDRM_SNS_ENABLE_CTRL1(base)			(base + 0x5D)
-#define	FLASH_LED_UNLOCK_SECURE(base)				(base + 0xD0)
-#define FLASH_PERPH_RESET_CTRL(base)				(base + 0xDA)
-#define	FLASH_TORCH(base)					(base + 0xE4)
-
-#define FLASH_STATUS_REG_MASK					0xFF
-#define FLASH_LED_FAULT_STATUS(base)				(base + 0x08)
-#define INT_LATCHED_STS(base)					(base + 0x18)
-#define IN_POLARITY_HIGH(base)					(base + 0x12)
-#define INT_SET_TYPE(base)					(base + 0x11)
-#define INT_EN_SET(base)					(base + 0x15)
-#define INT_LATCHED_CLR(base)					(base + 0x14)
-
-#define	FLASH_HEADROOM_MASK					0x03
-#define FLASH_STARTUP_DLY_MASK					0x03
-#define	FLASH_VREG_OK_FORCE_MASK				0xC0
-#define	FLASH_FAULT_DETECT_MASK					0x80
-#define	FLASH_THERMAL_DERATE_MASK				0xBF
-#define FLASH_SECURE_MASK					0xFF
-#define FLASH_TORCH_MASK					0x03
-#define FLASH_CURRENT_MASK					0x7F
-#define FLASH_TMR_MASK						0x03
-#define FLASH_TMR_SAFETY					0x00
-#define FLASH_SAFETY_TIMER_MASK					0x7F
-#define FLASH_MODULE_ENABLE_MASK				0xE0
-#define FLASH_STROBE_MASK					0xC0
-#define FLASH_CURRENT_RAMP_MASK					0xBF
-#define FLASH_VPH_PWR_DROOP_MASK				0xF3
-#define FLASH_LED_HDRM_SNS_ENABLE_MASK				0x81
-#define	FLASH_MASK_MODULE_CONTRL_MASK				0xE0
-#define FLASH_FOLLOW_OTST2_RB_MASK				0x08
-
-#define FLASH_LED_TRIGGER_DEFAULT				"none"
-#define FLASH_LED_HEADROOM_DEFAULT_MV				500
-#define FLASH_LED_STARTUP_DELAY_DEFAULT_US			128
-#define FLASH_LED_CLAMP_CURRENT_DEFAULT_MA			200
-#define	FLASH_LED_THERMAL_DERATE_THRESHOLD_DEFAULT_C		80
-#define	FLASH_LED_RAMP_UP_STEP_DEFAULT_US			3
-#define	FLASH_LED_RAMP_DN_STEP_DEFAULT_US			3
-#define	FLASH_LED_VPH_PWR_DROOP_THRESHOLD_DEFAULT_MV		3200
-#define	FLASH_LED_VPH_PWR_DROOP_DEBOUNCE_TIME_DEFAULT_US	10
-#define FLASH_LED_THERMAL_DERATE_RATE_DEFAULT_PERCENT		2
-#define FLASH_RAMP_UP_DELAY_US_MIN				1000
-#define	FLASH_RAMP_UP_DELAY_US_MAX				1001
-#define FLASH_RAMP_DN_DELAY_US_MIN				2160
-#define	FLASH_RAMP_DN_DELAY_US_MAX				2161
-#define FLASH_BOOST_REGULATOR_PROBE_DELAY_MS			2000
-#define	FLASH_TORCH_MAX_LEVEL					0x0F
-#define	FLASH_MAX_LEVEL						0x4F
-#define	FLASH_LED_FLASH_HW_VREG_OK				0x40
-#define	FLASH_LED_FLASH_SW_VREG_OK				0x80
-#define FLASH_LED_STROBE_TYPE_HW				0x04
-#define	FLASH_DURATION_DIVIDER					10
-#define	FLASH_LED_HEADROOM_DIVIDER				100
-#define	FLASH_LED_HEADROOM_OFFSET				2
-#define	FLASH_LED_MAX_CURRENT_MA				1000
-#define	FLASH_LED_THERMAL_THRESHOLD_MIN				95
-#define	FLASH_LED_THERMAL_DEVIDER				10
-#define	FLASH_LED_VPH_DROOP_THRESHOLD_MIN_MV			2500
-#define	FLASH_LED_VPH_DROOP_THRESHOLD_DIVIDER			100
-#define	FLASH_LED_HDRM_SNS_ENABLE				0x81
-#define	FLASH_LED_HDRM_SNS_DISABLE				0x01
-#define	FLASH_LED_UA_PER_MA					1000
-#define	FLASH_LED_MASK_MODULE_MASK2_ENABLE			0x20
-#define	FLASH_LED_MASK3_ENABLE_SHIFT				7
-#define	FLASH_LED_MODULE_CTRL_DEFAULT				0x60
-#define	FLASH_LED_CURRENT_READING_DELAY_MIN			5000
-#define	FLASH_LED_CURRENT_READING_DELAY_MAX			5001
-#define	FLASH_LED_OPEN_FAULT_DETECTED				0xC
-
-#define FLASH_UNLOCK_SECURE					0xA5
-#define FLASH_LED_TORCH_ENABLE					0x00
-#define FLASH_LED_TORCH_DISABLE					0x03
-#define FLASH_MODULE_ENABLE					0x80
-#define FLASH_LED0_TRIGGER					0x80
-#define FLASH_LED1_TRIGGER					0x40
-#define FLASH_LED0_ENABLEMENT					0x40
-#define FLASH_LED1_ENABLEMENT					0x20
-#define FLASH_LED_DISABLE					0x00
-#define	FLASH_LED_MIN_CURRENT_MA				13
-#define FLASH_SUBTYPE_DUAL					0x01
-#define FLASH_SUBTYPE_SINGLE					0x02
-
-/*
- * ID represents physical LEDs for individual control purpose.
- */
-enum flash_led_id {
-	FLASH_LED_0 = 0,
-	FLASH_LED_1,
-	FLASH_LED_SWITCH,
-};
-
-enum flash_led_type {
-	FLASH = 0,
-	TORCH,
-	SWITCH,
-};
-
-enum thermal_derate_rate {
-	RATE_1_PERCENT = 0,
-	RATE_1P25_PERCENT,
-	RATE_2_PERCENT,
-	RATE_2P5_PERCENT,
-	RATE_5_PERCENT,
-};
-
-enum current_ramp_steps {
-	RAMP_STEP_0P2_US = 0,
-	RAMP_STEP_0P4_US,
-	RAMP_STEP_0P8_US,
-	RAMP_STEP_1P6_US,
-	RAMP_STEP_3P3_US,
-	RAMP_STEP_6P7_US,
-	RAMP_STEP_13P5_US,
-	RAMP_STEP_27US,
-};
-
-struct flash_regulator_data {
-	struct regulator	*regs;
-	const char		*reg_name;
-	u32			max_volt_uv;
-};
-
-/*
- * Configurations for each individual LED
- */
-struct flash_node_data {
-	struct platform_device		*pdev;
-	struct regmap			*regmap;
-	struct led_classdev		cdev;
-	struct work_struct		work;
-	struct flash_regulator_data	*reg_data;
-	u16				max_current;
-	u16				prgm_current;
-	u16				prgm_current2;
-	u16				duration;
-	u8				id;
-	u8				type;
-	u8				trigger;
-	u8				enable;
-	u8				num_regulators;
-	bool				flash_on;
-};
-
-/*
- * Flash LED configuration read from device tree
- */
-struct flash_led_platform_data {
-	unsigned int			temp_threshold_num;
-	unsigned int			temp_derate_curr_num;
-	unsigned int			*die_temp_derate_curr_ma;
-	unsigned int			*die_temp_threshold_degc;
-	u16				ramp_up_step;
-	u16				ramp_dn_step;
-	u16				vph_pwr_droop_threshold;
-	u16				headroom;
-	u16				clamp_current;
-	u8				thermal_derate_threshold;
-	u8				vph_pwr_droop_debounce_time;
-	u8				startup_dly;
-	u8				thermal_derate_rate;
-	bool				pmic_charger_support;
-	bool				self_check_en;
-	bool				thermal_derate_en;
-	bool				current_ramp_en;
-	bool				vph_pwr_droop_en;
-	bool				hdrm_sns_ch0_en;
-	bool				hdrm_sns_ch1_en;
-	bool				power_detect_en;
-	bool				mask3_en;
-	bool				follow_rb_disable;
-	bool				die_current_derate_en;
-};
-
-struct qpnp_flash_led_buffer {
-	size_t rpos;
-	size_t wpos;
-	size_t len;
-	char data[0];
-};
-
-/*
- * Flash LED data structure containing flash LED attributes
- */
-struct qpnp_flash_led {
-	struct pmic_revid_data		*revid_data;
-	struct platform_device		*pdev;
-	struct regmap			*regmap;
-	struct flash_led_platform_data	*pdata;
-	struct pinctrl			*pinctrl;
-	struct pinctrl_state		*gpio_state_active;
-	struct pinctrl_state		*gpio_state_suspend;
-	struct flash_node_data		*flash_node;
-	struct power_supply		*battery_psy;
-	struct workqueue_struct		*ordered_workq;
-	struct qpnp_vadc_chip		*vadc_dev;
-	struct mutex			flash_led_lock;
-	struct qpnp_flash_led_buffer	*log;
-	struct dentry			*dbgfs_root;
-	int				num_leds;
-	u32				buffer_cnt;
-	u16				base;
-	u16				current_addr;
-	u16				current2_addr;
-	u8				peripheral_type;
-	u8				fault_reg;
-	bool				gpio_enabled;
-	bool				charging_enabled;
-	bool				strobe_debug;
-	bool				dbg_feature_en;
-	bool				open_fault;
-};
-
-static u8 qpnp_flash_led_ctrl_dbg_regs[] = {
-	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
-	0x4A, 0x4B, 0x4C, 0x4F, 0x51, 0x52, 0x54, 0x55, 0x5A, 0x5C, 0x5D,
-};
-
-static int flash_led_dbgfs_file_open(struct qpnp_flash_led *led,
-					struct file *file)
-{
-	struct qpnp_flash_led_buffer *log;
-	size_t logbufsize = SZ_4K;
-
-	log = kzalloc(logbufsize, GFP_KERNEL);
-	if (!log)
-		return -ENOMEM;
-
-	log->rpos = 0;
-	log->wpos = 0;
-	log->len = logbufsize - sizeof(*log);
-	led->log = log;
-
-	led->buffer_cnt = 1;
-	file->private_data = led;
-
-	return 0;
-}
-
-static int flash_led_dfs_open(struct inode *inode, struct file *file)
-{
-	struct qpnp_flash_led *led = inode->i_private;
-
-	return flash_led_dbgfs_file_open(led, file);
-}
-
-static int flash_led_dfs_close(struct inode *inode, struct file *file)
-{
-	struct qpnp_flash_led *led = file->private_data;
-
-	if (led && led->log) {
-		file->private_data = NULL;
-		kfree(led->log);
-	}
-
-	return 0;
-}
-
-static int print_to_log(struct qpnp_flash_led_buffer *log,
-					const char *fmt, ...)
-{
-	va_list args;
-	int cnt;
-	char *log_buf = &log->data[log->wpos];
-	size_t size = log->len - log->wpos;
-
-	va_start(args, fmt);
-	cnt = vscnprintf(log_buf, size, fmt, args);
-	va_end(args);
-
-	log->wpos += cnt;
-	return cnt;
-}
-
-static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
-					size_t count, loff_t *ppos) {
-	struct qpnp_flash_led *led = fp->private_data;
-	struct qpnp_flash_led_buffer *log = led->log;
-	uint val;
-	int rc;
-	size_t len;
-	size_t ret;
-
-	if (log->rpos >= log->wpos && led->buffer_cnt == 0)
-		return 0;
-
-	rc = regmap_read(led->regmap, INT_LATCHED_STS(led->base), &val);
-	if (rc) {
-		dev_err(&led->pdev->dev,
-				"Unable to read from address %x, rc(%d)\n",
-				INT_LATCHED_STS(led->base), rc);
-		return -EINVAL;
-	}
-	led->buffer_cnt--;
-
-	rc = print_to_log(log, "0x%05X ", INT_LATCHED_STS(led->base));
-	if (rc == 0)
-		return rc;
-
-	rc = print_to_log(log, "0x%02X ", val);
-	if (rc == 0)
-		return rc;
-
-	if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
-		log->data[log->wpos - 1] = '\n';
-
-	len = min(count, log->wpos - log->rpos);
-
-	ret = copy_to_user(buf, &log->data[log->rpos], len);
-	if (ret) {
-		pr_err("error copy register value to user\n");
-		return -EFAULT;
-	}
-
-	len -= ret;
-	*ppos += len;
-	log->rpos += len;
-
-	return len;
-}
-
-static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
-					size_t count, loff_t *ppos) {
-	struct qpnp_flash_led *led = fp->private_data;
-	struct qpnp_flash_led_buffer *log = led->log;
-	int rc;
-	size_t len;
-	size_t ret;
-
-	if (log->rpos >= log->wpos && led->buffer_cnt == 0)
-		return 0;
-
-	led->buffer_cnt--;
-
-	rc = print_to_log(log, "0x%05X ", FLASH_LED_FAULT_STATUS(led->base));
-	if (rc == 0)
-		return rc;
-
-	rc = print_to_log(log, "0x%02X ", led->fault_reg);
-	if (rc == 0)
-		return rc;
-
-	if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
-		log->data[log->wpos - 1] = '\n';
-
-	len = min(count, log->wpos - log->rpos);
-
-	ret = copy_to_user(buf, &log->data[log->rpos], len);
-	if (ret) {
-		pr_err("error copy register value to user\n");
-		return -EFAULT;
-	}
-
-	len -= ret;
-	*ppos += len;
-	log->rpos += len;
-
-	return len;
-}
-
-static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
-			const char __user *buf, size_t count, loff_t *ppos) {
-
-	u8 *val;
-	int pos = 0;
-	int cnt = 0;
-	int data;
-	size_t ret = 0;
-
-	struct qpnp_flash_led *led = file->private_data;
-	char *kbuf = kmalloc(count + 1, GFP_KERNEL);
-
-	if (!kbuf)
-		return -ENOMEM;
-
-	ret = copy_from_user(kbuf, buf, count);
-	if (!ret) {
-		pr_err("failed to copy data from user\n");
-		ret = -EFAULT;
-		goto free_buf;
-	}
-
-	count -= ret;
-	*ppos += count;
-	kbuf[count] = '\0';
-	val = kbuf;
-	while (sscanf(kbuf + pos, "%i", &data) == 1) {
-		pos++;
-		val[cnt++] = data & 0xff;
-	}
-
-	if (!cnt)
-		goto free_buf;
-
-	ret = count;
-	if (*val == 1)
-		led->strobe_debug = true;
-	else
-		led->strobe_debug = false;
-
-free_buf:
-	kfree(kbuf);
-	return ret;
-}
-
-static ssize_t flash_led_dfs_dbg_enable(struct file *file,
-			const char __user *buf, size_t count, loff_t *ppos) {
-
-	u8 *val;
-	int pos = 0;
-	int cnt = 0;
-	int data;
-	size_t ret = 0;
-	struct qpnp_flash_led *led = file->private_data;
-	char *kbuf = kmalloc(count + 1, GFP_KERNEL);
-
-	if (!kbuf)
-		return -ENOMEM;
-
-	ret = copy_from_user(kbuf, buf, count);
-	if (ret == count) {
-		pr_err("failed to copy data from user\n");
-		ret = -EFAULT;
-		goto free_buf;
-	}
-	count -= ret;
-	*ppos += count;
-	kbuf[count] = '\0';
-	val = kbuf;
-	while (sscanf(kbuf + pos, "%i", &data) == 1) {
-		pos++;
-		val[cnt++] = data & 0xff;
-	}
-
-	if (!cnt)
-		goto free_buf;
-
-	ret = count;
-	if (*val == 1)
-		led->dbg_feature_en = true;
-	else
-		led->dbg_feature_en = false;
-
-free_buf:
-	kfree(kbuf);
-	return ret;
-}
-
-static const struct file_operations flash_led_dfs_latched_reg_fops = {
-	.open		= flash_led_dfs_open,
-	.release	= flash_led_dfs_close,
-	.read		= flash_led_dfs_latched_reg_read,
-};
-
-static const struct file_operations flash_led_dfs_strobe_reg_fops = {
-	.open		= flash_led_dfs_open,
-	.release	= flash_led_dfs_close,
-	.read		= flash_led_dfs_fault_reg_read,
-	.write		= flash_led_dfs_fault_reg_enable,
-};
-
-static const struct file_operations flash_led_dfs_dbg_feature_fops = {
-	.open		= flash_led_dfs_open,
-	.release	= flash_led_dfs_close,
-	.write		= flash_led_dfs_dbg_enable,
-};
-
-static int
-qpnp_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask, u8 val)
-{
-	int rc;
-
-	rc = regmap_update_bits(led->regmap, addr, mask, val);
-	if (rc)
-		dev_err(&led->pdev->dev,
-			"Unable to update_bits to addr=%x, rc(%d)\n", addr, rc);
-
-	dev_dbg(&led->pdev->dev, "Write 0x%02X to addr 0x%02X\n", val, addr);
-
-	return rc;
-}
-
-static int qpnp_flash_led_get_allowed_die_temp_curr(struct qpnp_flash_led *led,
-							int64_t die_temp_degc)
-{
-	int die_temp_curr_ma;
-
-	if (die_temp_degc >= led->pdata->die_temp_threshold_degc[0])
-		die_temp_curr_ma =  0;
-	else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[1])
-		die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[0];
-	else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[2])
-		die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[1];
-	else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[3])
-		die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[2];
-	else if (die_temp_degc >= led->pdata->die_temp_threshold_degc[4])
-		die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[3];
-	else
-		die_temp_curr_ma = led->pdata->die_temp_derate_curr_ma[4];
-
-	return die_temp_curr_ma;
-}
-
-static int64_t qpnp_flash_led_get_die_temp(struct qpnp_flash_led *led)
-{
-	struct qpnp_vadc_result die_temp_result;
-	int rc;
-
-	rc = qpnp_vadc_read(led->vadc_dev, SPARE2, &die_temp_result);
-	if (rc) {
-		pr_err("failed to read the die temp\n");
-		return -EINVAL;
-	}
-
-	return die_temp_result.physical;
-}
-
-static int qpnp_get_pmic_revid(struct qpnp_flash_led *led)
-{
-	struct device_node *revid_dev_node;
-
-	revid_dev_node = of_parse_phandle(led->pdev->dev.of_node,
-				"qcom,pmic-revid", 0);
-	if (!revid_dev_node) {
-		dev_err(&led->pdev->dev,
-			"qcom,pmic-revid property missing\n");
-		return -EINVAL;
-	}
-
-	led->revid_data = get_revid_data(revid_dev_node);
-	if (IS_ERR(led->revid_data)) {
-		pr_err("Couldn't get revid data rc = %ld\n",
-				PTR_ERR(led->revid_data));
-		return PTR_ERR(led->revid_data);
-	}
-
-	return 0;
-}
-
-static int
-qpnp_flash_led_get_max_avail_current(struct flash_node_data *flash_node,
-					struct qpnp_flash_led *led)
-{
-	union power_supply_propval prop;
-	int64_t chg_temp_milidegc, die_temp_degc;
-	int max_curr_avail_ma = 2000;
-	int allowed_die_temp_curr_ma = 2000;
-	int rc;
-
-	if (led->pdata->power_detect_en) {
-		if (!led->battery_psy) {
-			dev_err(&led->pdev->dev,
-				"Failed to query power supply\n");
-			return -EINVAL;
-		}
-
-		/*
-		 * When charging is enabled, enforce this new enablement
-		 * sequence to reduce fuel gauge reading resolution.
-		 */
-		if (led->charging_enabled) {
-			rc = qpnp_led_masked_write(led,
-				FLASH_MODULE_ENABLE_CTRL(led->base),
-				FLASH_MODULE_ENABLE, FLASH_MODULE_ENABLE);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-				"Module enable reg write failed\n");
-				return -EINVAL;
-			}
-
-			usleep_range(FLASH_LED_CURRENT_READING_DELAY_MIN,
-				FLASH_LED_CURRENT_READING_DELAY_MAX);
-		}
-
-		power_supply_get_property(led->battery_psy,
-				POWER_SUPPLY_PROP_FLASH_CURRENT_MAX, &prop);
-		if (!prop.intval) {
-			dev_err(&led->pdev->dev,
-				"battery too low for flash\n");
-			return -EINVAL;
-		}
-
-		max_curr_avail_ma = (prop.intval / FLASH_LED_UA_PER_MA);
-	}
-
-	/*
-	 * When thermal mitigation is available, this logic will execute to
-	 * derate current based upon the PMIC die temperature.
-	 */
-	if (led->pdata->die_current_derate_en) {
-		chg_temp_milidegc = qpnp_flash_led_get_die_temp(led);
-		if (chg_temp_milidegc < 0)
-			return -EINVAL;
-
-		die_temp_degc = div_s64(chg_temp_milidegc, 1000);
-		allowed_die_temp_curr_ma =
-			qpnp_flash_led_get_allowed_die_temp_curr(led,
-								die_temp_degc);
-		if (allowed_die_temp_curr_ma < 0)
-			return -EINVAL;
-	}
-
-	max_curr_avail_ma = (max_curr_avail_ma >= allowed_die_temp_curr_ma)
-				? allowed_die_temp_curr_ma : max_curr_avail_ma;
-
-	return max_curr_avail_ma;
-}
-
-static ssize_t qpnp_flash_led_die_temp_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	struct qpnp_flash_led *led;
-	struct flash_node_data *flash_node;
-	unsigned long val;
-	struct led_classdev *led_cdev = dev_get_drvdata(dev);
-	ssize_t ret;
-
-	ret = kstrtoul(buf, 10, &val);
-	if (ret)
-		return ret;
-
-	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-	led = dev_get_drvdata(&flash_node->pdev->dev);
-
-	/*'0' for disable die_temp feature; non-zero to enable feature*/
-	if (val == 0)
-		led->pdata->die_current_derate_en = false;
-	else
-		led->pdata->die_current_derate_en = true;
-
-	return count;
-}
-
-static ssize_t qpnp_led_strobe_type_store(struct device *dev,
-			struct device_attribute *attr,
-			const char *buf, size_t count)
-{
-	struct flash_node_data *flash_node;
-	unsigned long state;
-	struct led_classdev *led_cdev = dev_get_drvdata(dev);
-	ssize_t ret = -EINVAL;
-
-	ret = kstrtoul(buf, 10, &state);
-	if (ret)
-		return ret;
-
-	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-
-	/* '0' for sw strobe; '1' for hw strobe */
-	if (state == 1)
-		flash_node->trigger |= FLASH_LED_STROBE_TYPE_HW;
-	else
-		flash_node->trigger &= ~FLASH_LED_STROBE_TYPE_HW;
-
-	return count;
-}
-
-static ssize_t qpnp_flash_led_dump_regs_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	struct qpnp_flash_led *led;
-	struct flash_node_data *flash_node;
-	struct led_classdev *led_cdev = dev_get_drvdata(dev);
-	int rc, i, count = 0;
-	u16 addr;
-	uint val;
-
-	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-	led = dev_get_drvdata(&flash_node->pdev->dev);
-	for (i = 0; i < ARRAY_SIZE(qpnp_flash_led_ctrl_dbg_regs); i++) {
-		addr = led->base + qpnp_flash_led_ctrl_dbg_regs[i];
-		rc = regmap_read(led->regmap, addr, &val);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"Unable to read from addr=%x, rc(%d)\n",
-				addr, rc);
-			return -EINVAL;
-		}
-
-		count += snprintf(buf + count, PAGE_SIZE - count,
-				"REG_0x%x = 0x%02x\n", addr, val);
-
-		if (count >= PAGE_SIZE)
-			return PAGE_SIZE - 1;
-	}
-
-	return count;
-}
-
-static ssize_t qpnp_flash_led_current_derate_store(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf, size_t count)
-{
-	struct qpnp_flash_led *led;
-	struct flash_node_data *flash_node;
-	unsigned long val;
-	struct led_classdev *led_cdev = dev_get_drvdata(dev);
-	ssize_t ret;
-
-	ret = kstrtoul(buf, 10, &val);
-	if (ret)
-		return ret;
-
-	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-	led = dev_get_drvdata(&flash_node->pdev->dev);
-
-	/*'0' for disable derate feature; non-zero to enable derate feature */
-	if (val == 0)
-		led->pdata->power_detect_en = false;
-	else
-		led->pdata->power_detect_en = true;
-
-	return count;
-}
-
-static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
-			struct device_attribute *attr, char *buf)
-{
-	struct qpnp_flash_led *led;
-	struct flash_node_data *flash_node;
-	struct led_classdev *led_cdev = dev_get_drvdata(dev);
-	int max_curr_avail_ma = 0;
-
-	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-	led = dev_get_drvdata(&flash_node->pdev->dev);
-
-	if (led->flash_node[0].flash_on)
-		max_curr_avail_ma += led->flash_node[0].max_current;
-	if (led->flash_node[1].flash_on)
-		max_curr_avail_ma += led->flash_node[1].max_current;
-
-	if (led->pdata->power_detect_en ||
-			led->pdata->die_current_derate_en) {
-		max_curr_avail_ma =
-			qpnp_flash_led_get_max_avail_current(flash_node, led);
-
-		if (max_curr_avail_ma < 0)
-			return -EINVAL;
-	}
-
-	return snprintf(buf, PAGE_SIZE, "%u\n", max_curr_avail_ma);
-}
-
-static struct device_attribute qpnp_flash_led_attrs[] = {
-	__ATTR(strobe, 0664, NULL, qpnp_led_strobe_type_store),
-	__ATTR(reg_dump, 0664, qpnp_flash_led_dump_regs_show, NULL),
-	__ATTR(enable_current_derate, 0664, NULL,
-		qpnp_flash_led_current_derate_store),
-	__ATTR(max_allowed_current, 0664, qpnp_flash_led_max_current_show,
-		NULL),
-	__ATTR(enable_die_temp_current_derate, 0664, NULL,
-		qpnp_flash_led_die_temp_store),
-};
-
-static int qpnp_flash_led_get_thermal_derate_rate(const char *rate)
-{
-	/*
-	 * return 5% derate as default value if user specifies
-	 * a value un-supported
-	 */
-	if (strcmp(rate, "1_PERCENT") == 0)
-		return RATE_1_PERCENT;
-	else if (strcmp(rate, "1P25_PERCENT") == 0)
-		return RATE_1P25_PERCENT;
-	else if (strcmp(rate, "2_PERCENT") == 0)
-		return RATE_2_PERCENT;
-	else if (strcmp(rate, "2P5_PERCENT") == 0)
-		return RATE_2P5_PERCENT;
-	else if (strcmp(rate, "5_PERCENT") == 0)
-		return RATE_5_PERCENT;
-	else
-		return RATE_5_PERCENT;
-}
-
-static int qpnp_flash_led_get_ramp_step(const char *step)
-{
-	/*
-	 * return 27 us as default value if user specifies
-	 * a value un-supported
-	 */
-	if (strcmp(step, "0P2_US") == 0)
-		return RAMP_STEP_0P2_US;
-	else if (strcmp(step, "0P4_US") == 0)
-		return RAMP_STEP_0P4_US;
-	else if (strcmp(step, "0P8_US") == 0)
-		return RAMP_STEP_0P8_US;
-	else if (strcmp(step, "1P6_US") == 0)
-		return RAMP_STEP_1P6_US;
-	else if (strcmp(step, "3P3_US") == 0)
-		return RAMP_STEP_3P3_US;
-	else if (strcmp(step, "6P7_US") == 0)
-		return RAMP_STEP_6P7_US;
-	else if (strcmp(step, "13P5_US") == 0)
-		return RAMP_STEP_13P5_US;
-	else
-		return RAMP_STEP_27US;
-}
-
-static u8 qpnp_flash_led_get_droop_debounce_time(u8 val)
-{
-	/*
-	 * return 10 us as default value if user specifies
-	 * a value un-supported
-	 */
-	switch (val) {
-	case 0:
-		return 0;
-	case 10:
-		return 1;
-	case 32:
-		return 2;
-	case 64:
-		return 3;
-	default:
-		return 1;
-	}
-}
-
-static u8 qpnp_flash_led_get_startup_dly(u8 val)
-{
-	/*
-	 * return 128 us as default value if user specifies
-	 * a value un-supported
-	 */
-	switch (val) {
-	case 10:
-		return 0;
-	case 32:
-		return 1;
-	case 64:
-		return 2;
-	case 128:
-		return 3;
-	default:
-		return 3;
-	}
-}
-
-static int
-qpnp_flash_led_get_peripheral_type(struct qpnp_flash_led *led)
-{
-	int rc;
-	uint val;
-
-	rc = regmap_read(led->regmap,
-			 FLASH_LED_PERIPHERAL_SUBTYPE(led->base), &val);
-	if (rc) {
-		dev_err(&led->pdev->dev,
-				"Unable to read peripheral subtype\n");
-		return -EINVAL;
-	}
-
-	return val;
-}
-
-static int qpnp_flash_led_module_disable(struct qpnp_flash_led *led,
-				struct flash_node_data *flash_node)
-{
-	union power_supply_propval psy_prop;
-	int rc;
-	uint val, tmp;
-
-	rc = regmap_read(led->regmap, FLASH_LED_STROBE_CTRL(led->base), &val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Unable to read strobe reg\n");
-		return -EINVAL;
-	}
-
-	tmp = (~flash_node->trigger) & val;
-	if (!tmp) {
-		if (flash_node->type == TORCH) {
-			rc = qpnp_led_masked_write(led,
-				FLASH_LED_UNLOCK_SECURE(led->base),
-				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Secure reg write failed\n");
-				return -EINVAL;
-			}
-
-			rc = qpnp_led_masked_write(led,
-				FLASH_TORCH(led->base),
-				FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Torch reg write failed\n");
-				return -EINVAL;
-			}
-		}
-
-		if (led->battery_psy &&
-			led->revid_data->pmic_subtype == PMI8996_SUBTYPE &&
-						!led->revid_data->rev3) {
-			psy_prop.intval = false;
-			rc = power_supply_set_property(led->battery_psy,
-					POWER_SUPPLY_PROP_FLASH_TRIGGER,
-							&psy_prop);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-				"Failed to enble charger i/p current limit\n");
-				return -EINVAL;
-			}
-		}
-
-		rc = qpnp_led_masked_write(led,
-				FLASH_MODULE_ENABLE_CTRL(led->base),
-				FLASH_MODULE_ENABLE_MASK,
-				FLASH_LED_MODULE_CTRL_DEFAULT);
-		if (rc) {
-			dev_err(&led->pdev->dev, "Module disable failed\n");
-			return -EINVAL;
-		}
-
-		if (led->pinctrl) {
-			rc = pinctrl_select_state(led->pinctrl,
-					led->gpio_state_suspend);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"failed to disable GPIO\n");
-				return -EINVAL;
-			}
-			led->gpio_enabled = false;
-		}
-
-		if (led->battery_psy) {
-			psy_prop.intval = false;
-			rc = power_supply_set_property(led->battery_psy,
-						POWER_SUPPLY_PROP_FLASH_ACTIVE,
-							&psy_prop);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-				"Failed to setup OTG pulse skip enable\n");
-				return -EINVAL;
-			}
-		}
-	}
-
-	if (flash_node->trigger & FLASH_LED0_TRIGGER) {
-		rc = qpnp_led_masked_write(led,
-				led->current_addr,
-				FLASH_CURRENT_MASK, 0x00);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"current register write failed\n");
-			return -EINVAL;
-		}
-	}
-
-	if (flash_node->trigger & FLASH_LED1_TRIGGER) {
-		rc = qpnp_led_masked_write(led,
-				led->current2_addr,
-				FLASH_CURRENT_MASK, 0x00);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"current register write failed\n");
-			return -EINVAL;
-		}
-	}
-
-	if (flash_node->id == FLASH_LED_SWITCH)
-		flash_node->trigger &= FLASH_LED_STROBE_TYPE_HW;
-
-	return 0;
-}
-
-static enum
-led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev)
-{
-	return led_cdev->brightness;
-}
-
-static int flash_regulator_parse_dt(struct qpnp_flash_led *led,
-					struct flash_node_data *flash_node) {
-
-	int i = 0, rc;
-	struct device_node *node = flash_node->cdev.dev->of_node;
-	struct device_node *temp = NULL;
-	const char *temp_string;
-	u32 val;
-
-	flash_node->reg_data = devm_kzalloc(&led->pdev->dev,
-					sizeof(struct flash_regulator_data *) *
-						flash_node->num_regulators,
-						GFP_KERNEL);
-	if (!flash_node->reg_data) {
-		dev_err(&led->pdev->dev,
-				"Unable to allocate memory\n");
-		return -ENOMEM;
-	}
-
-	for_each_child_of_node(node, temp) {
-		rc = of_property_read_string(temp, "regulator-name",
-							&temp_string);
-		if (!rc)
-			flash_node->reg_data[i].reg_name = temp_string;
-		else {
-			dev_err(&led->pdev->dev,
-					"Unable to read regulator name\n");
-			return rc;
-		}
-
-		rc = of_property_read_u32(temp, "max-voltage", &val);
-		if (!rc) {
-			flash_node->reg_data[i].max_volt_uv = val;
-		} else if (rc != -EINVAL) {
-			dev_err(&led->pdev->dev,
-					"Unable to read max voltage\n");
-			return rc;
-		}
-
-		i++;
-	}
-
-	return 0;
-}
-
-static int flash_regulator_setup(struct qpnp_flash_led *led,
-				struct flash_node_data *flash_node, bool on)
-{
-	int i, rc = 0;
-
-	if (on == false) {
-		i = flash_node->num_regulators;
-		goto error_regulator_setup;
-	}
-
-	for (i = 0; i < flash_node->num_regulators; i++) {
-		flash_node->reg_data[i].regs =
-			regulator_get(flash_node->cdev.dev,
-					flash_node->reg_data[i].reg_name);
-		if (IS_ERR(flash_node->reg_data[i].regs)) {
-			rc = PTR_ERR(flash_node->reg_data[i].regs);
-			dev_err(&led->pdev->dev,
-					"Failed to get regulator\n");
-			goto error_regulator_setup;
-		}
-
-		if (regulator_count_voltages(flash_node->reg_data[i].regs)
-									> 0) {
-			rc = regulator_set_voltage(flash_node->reg_data[i].regs,
-					flash_node->reg_data[i].max_volt_uv,
-					flash_node->reg_data[i].max_volt_uv);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"regulator set voltage failed\n");
-				regulator_put(flash_node->reg_data[i].regs);
-				goto error_regulator_setup;
-			}
-		}
-	}
-
-	return rc;
-
-error_regulator_setup:
-	while (i--) {
-		if (regulator_count_voltages(flash_node->reg_data[i].regs)
-									> 0) {
-			regulator_set_voltage(flash_node->reg_data[i].regs,
-				0, flash_node->reg_data[i].max_volt_uv);
-		}
-
-		regulator_put(flash_node->reg_data[i].regs);
-	}
-
-	return rc;
-}
-
-static int flash_regulator_enable(struct qpnp_flash_led *led,
-				struct flash_node_data *flash_node, bool on)
-{
-	int i, rc = 0;
-
-	if (on == false) {
-		i = flash_node->num_regulators;
-		goto error_regulator_enable;
-	}
-
-	for (i = 0; i < flash_node->num_regulators; i++) {
-		rc = regulator_enable(flash_node->reg_data[i].regs);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-					"regulator enable failed\n");
-			goto error_regulator_enable;
-		}
-	}
-
-	return rc;
-
-error_regulator_enable:
-	while (i--)
-		regulator_disable(flash_node->reg_data[i].regs);
-
-	return rc;
-}
-
-int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
-					int *max_current)
-{
-	struct led_classdev *led_cdev = trigger_to_lcdev(trig);
-	struct flash_node_data *flash_node;
-	struct qpnp_flash_led *led;
-	int rc;
-
-	if (!led_cdev) {
-		pr_err("Invalid led_trigger provided\n");
-		return -EINVAL;
-	}
-
-	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-	led = dev_get_drvdata(&flash_node->pdev->dev);
-
-	if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
-		dev_err(&led->pdev->dev, "Invalid options %d\n", options);
-		return -EINVAL;
-	}
-
-	if (options & ENABLE_REGULATOR) {
-		rc = flash_regulator_enable(led, flash_node, true);
-		if (rc < 0) {
-			dev_err(&led->pdev->dev,
-				"enable regulator failed, rc=%d\n", rc);
-			return rc;
-		}
-	}
-
-	if (options & DISABLE_REGULATOR) {
-		rc = flash_regulator_enable(led, flash_node, false);
-		if (rc < 0) {
-			dev_err(&led->pdev->dev,
-				"disable regulator failed, rc=%d\n", rc);
-			return rc;
-		}
-	}
-
-	if (options & QUERY_MAX_CURRENT) {
-		rc = qpnp_flash_led_get_max_avail_current(flash_node, led);
-		if (rc < 0) {
-			dev_err(&led->pdev->dev,
-				"query max current failed, rc=%d\n", rc);
-			return rc;
-		}
-		*max_current = rc;
-	}
-
-	return 0;
-}
-
-static void qpnp_flash_led_work(struct work_struct *work)
-{
-	struct flash_node_data *flash_node = container_of(work,
-				struct flash_node_data, work);
-	struct qpnp_flash_led *led = dev_get_drvdata(&flash_node->pdev->dev);
-	union power_supply_propval psy_prop;
-	int rc, brightness = flash_node->cdev.brightness;
-	int max_curr_avail_ma = 0;
-	int total_curr_ma = 0;
-	int i;
-	u8 val;
-	uint temp;
-
-	mutex_lock(&led->flash_led_lock);
-
-	if (!brightness)
-		goto turn_off;
-
-	if (led->open_fault) {
-		dev_err(&led->pdev->dev, "Open fault detected\n");
-		mutex_unlock(&led->flash_led_lock);
-		return;
-	}
-
-	if (!flash_node->flash_on && flash_node->num_regulators > 0) {
-		rc = flash_regulator_enable(led, flash_node, true);
-		if (rc) {
-			mutex_unlock(&led->flash_led_lock);
-			return;
-		}
-	}
-
-	if (!led->gpio_enabled && led->pinctrl) {
-		rc = pinctrl_select_state(led->pinctrl,
-						led->gpio_state_active);
-		if (rc) {
-			dev_err(&led->pdev->dev, "failed to enable GPIO\n");
-			goto error_enable_gpio;
-		}
-		led->gpio_enabled = true;
-	}
-
-	if (led->dbg_feature_en) {
-		rc = qpnp_led_masked_write(led,
-						INT_SET_TYPE(led->base),
-						FLASH_STATUS_REG_MASK, 0x1F);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-					"INT_SET_TYPE write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		rc = qpnp_led_masked_write(led,
-					IN_POLARITY_HIGH(led->base),
-					FLASH_STATUS_REG_MASK, 0x1F);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-					"IN_POLARITY_HIGH write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		rc = qpnp_led_masked_write(led,
-					INT_EN_SET(led->base),
-					FLASH_STATUS_REG_MASK, 0x1F);
-		if (rc) {
-			dev_err(&led->pdev->dev, "INT_EN_SET write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		rc = qpnp_led_masked_write(led,
-					INT_LATCHED_CLR(led->base),
-					FLASH_STATUS_REG_MASK, 0x1F);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-					"INT_LATCHED_CLR write failed\n");
-			goto exit_flash_led_work;
-		}
-	}
-
-	if (led->flash_node[led->num_leds - 1].id == FLASH_LED_SWITCH &&
-					flash_node->id != FLASH_LED_SWITCH) {
-		led->flash_node[led->num_leds - 1].trigger |=
-						(0x80 >> flash_node->id);
-		if (flash_node->id == FLASH_LED_0)
-			led->flash_node[led->num_leds - 1].prgm_current =
-						flash_node->prgm_current;
-		else if (flash_node->id == FLASH_LED_1)
-			led->flash_node[led->num_leds - 1].prgm_current2 =
-						flash_node->prgm_current;
-	}
-
-	if (flash_node->type == TORCH) {
-		rc = qpnp_led_masked_write(led,
-			FLASH_LED_UNLOCK_SECURE(led->base),
-			FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
-		if (rc) {
-			dev_err(&led->pdev->dev, "Secure reg write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		rc = qpnp_led_masked_write(led,
-			FLASH_TORCH(led->base),
-			FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE);
-		if (rc) {
-			dev_err(&led->pdev->dev, "Torch reg write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		if (flash_node->id == FLASH_LED_SWITCH) {
-			val = (u8)(flash_node->prgm_current *
-						FLASH_TORCH_MAX_LEVEL
-						/ flash_node->max_current);
-			rc = qpnp_led_masked_write(led,
-						led->current_addr,
-						FLASH_CURRENT_MASK, val);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Torch reg write failed\n");
-				goto exit_flash_led_work;
-			}
-
-			val = (u8)(flash_node->prgm_current2 *
-						FLASH_TORCH_MAX_LEVEL
-						/ flash_node->max_current);
-			rc = qpnp_led_masked_write(led,
-					led->current2_addr,
-					FLASH_CURRENT_MASK, val);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Torch reg write failed\n");
-				goto exit_flash_led_work;
-			}
-		} else {
-			val = (u8)(flash_node->prgm_current *
-						FLASH_TORCH_MAX_LEVEL /
-						flash_node->max_current);
-			if (flash_node->id == FLASH_LED_0) {
-				rc = qpnp_led_masked_write(led,
-						led->current_addr,
-						FLASH_CURRENT_MASK, val);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-						"current reg write failed\n");
-					goto exit_flash_led_work;
-				}
-			} else {
-				rc = qpnp_led_masked_write(led,
-						led->current2_addr,
-						FLASH_CURRENT_MASK, val);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-						"current reg write failed\n");
-					goto exit_flash_led_work;
-				}
-			}
-		}
-
-		rc = qpnp_led_masked_write(led,
-			FLASH_MAX_CURRENT(led->base),
-			FLASH_CURRENT_MASK, FLASH_TORCH_MAX_LEVEL);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-					"Max current reg write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		rc = qpnp_led_masked_write(led,
-			FLASH_MODULE_ENABLE_CTRL(led->base),
-			FLASH_MODULE_ENABLE_MASK, FLASH_MODULE_ENABLE);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"Module enable reg write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		if (led->pdata->hdrm_sns_ch0_en ||
-						led->pdata->hdrm_sns_ch1_en) {
-			if (flash_node->id == FLASH_LED_SWITCH) {
-				rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					flash_node->trigger &
-					FLASH_LED0_TRIGGER ?
-					FLASH_LED_HDRM_SNS_ENABLE :
-					FLASH_LED_HDRM_SNS_DISABLE);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"Headroom sense enable failed\n");
-					goto exit_flash_led_work;
-				}
-
-				rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					flash_node->trigger &
-					FLASH_LED1_TRIGGER ?
-					FLASH_LED_HDRM_SNS_ENABLE :
-					FLASH_LED_HDRM_SNS_DISABLE);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"Headroom sense enable failed\n");
-					goto exit_flash_led_work;
-				}
-			} else if (flash_node->id == FLASH_LED_0) {
-				rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					FLASH_LED_HDRM_SNS_ENABLE);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"Headroom sense disable failed\n");
-					goto exit_flash_led_work;
-				}
-			} else if (flash_node->id == FLASH_LED_1) {
-				rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					FLASH_LED_HDRM_SNS_ENABLE);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"Headroom sense disable failed\n");
-					goto exit_flash_led_work;
-				}
-			}
-		}
-
-		rc = qpnp_led_masked_write(led,
-			FLASH_LED_STROBE_CTRL(led->base),
-			(flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
-						| FLASH_LED_STROBE_TYPE_HW
-							: flash_node->trigger |
-						FLASH_LED_STROBE_TYPE_HW),
-							flash_node->trigger);
-		if (rc) {
-			dev_err(&led->pdev->dev, "Strobe reg write failed\n");
-			goto exit_flash_led_work;
-		}
-	} else if (flash_node->type == FLASH) {
-		if (flash_node->trigger & FLASH_LED0_TRIGGER)
-			max_curr_avail_ma += flash_node->max_current;
-		if (flash_node->trigger & FLASH_LED1_TRIGGER)
-			max_curr_avail_ma += flash_node->max_current;
-
-		psy_prop.intval = true;
-		rc = power_supply_set_property(led->battery_psy,
-						POWER_SUPPLY_PROP_FLASH_ACTIVE,
-								&psy_prop);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"Failed to setup OTG pulse skip enable\n");
-			goto exit_flash_led_work;
-		}
-
-		if (led->pdata->power_detect_en ||
-					led->pdata->die_current_derate_en) {
-			if (led->battery_psy) {
-				power_supply_get_property(led->battery_psy,
-					POWER_SUPPLY_PROP_STATUS,
-					&psy_prop);
-				if (psy_prop.intval < 0) {
-					dev_err(&led->pdev->dev,
-						"Invalid battery status\n");
-					goto exit_flash_led_work;
-				}
-
-				if (psy_prop.intval ==
-						POWER_SUPPLY_STATUS_CHARGING)
-					led->charging_enabled = true;
-				else if (psy_prop.intval ==
-					POWER_SUPPLY_STATUS_DISCHARGING
-					|| psy_prop.intval ==
-					POWER_SUPPLY_STATUS_NOT_CHARGING)
-					led->charging_enabled = false;
-			}
-			max_curr_avail_ma =
-				qpnp_flash_led_get_max_avail_current
-							(flash_node, led);
-			if (max_curr_avail_ma < 0) {
-				dev_err(&led->pdev->dev,
-					"Failed to get max avail curr\n");
-				goto exit_flash_led_work;
-			}
-		}
-
-		if (flash_node->id == FLASH_LED_SWITCH) {
-			if (flash_node->trigger & FLASH_LED0_TRIGGER)
-				total_curr_ma += flash_node->prgm_current;
-			if (flash_node->trigger & FLASH_LED1_TRIGGER)
-				total_curr_ma += flash_node->prgm_current2;
-
-			if (max_curr_avail_ma < total_curr_ma) {
-				flash_node->prgm_current =
-					(flash_node->prgm_current *
-					max_curr_avail_ma) / total_curr_ma;
-				flash_node->prgm_current2 =
-					(flash_node->prgm_current2 *
-					max_curr_avail_ma) / total_curr_ma;
-			}
-
-			val = (u8)(flash_node->prgm_current *
-				FLASH_MAX_LEVEL / flash_node->max_current);
-			rc = qpnp_led_masked_write(led,
-				led->current_addr, FLASH_CURRENT_MASK, val);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Current register write failed\n");
-				goto exit_flash_led_work;
-			}
-
-			val = (u8)(flash_node->prgm_current2 *
-				FLASH_MAX_LEVEL / flash_node->max_current);
-			rc = qpnp_led_masked_write(led,
-				led->current2_addr, FLASH_CURRENT_MASK, val);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Current register write failed\n");
-				goto exit_flash_led_work;
-			}
-		} else {
-			if (max_curr_avail_ma < flash_node->prgm_current) {
-				dev_err(&led->pdev->dev,
-					"battery only supprots %d mA\n",
-					max_curr_avail_ma);
-				flash_node->prgm_current =
-					 (u16)max_curr_avail_ma;
-			}
-
-			val = (u8)(flash_node->prgm_current *
-					 FLASH_MAX_LEVEL
-					/ flash_node->max_current);
-			if (flash_node->id == FLASH_LED_0) {
-				rc = qpnp_led_masked_write(
-					led,
-					led->current_addr,
-					FLASH_CURRENT_MASK, val);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-						"current reg write failed\n");
-					goto exit_flash_led_work;
-				}
-			} else if (flash_node->id == FLASH_LED_1) {
-				rc = qpnp_led_masked_write(
-					led,
-					led->current2_addr,
-					FLASH_CURRENT_MASK, val);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-						"current reg write failed\n");
-					goto exit_flash_led_work;
-				}
-			}
-		}
-
-		val = (u8)((flash_node->duration - FLASH_DURATION_DIVIDER)
-						/ FLASH_DURATION_DIVIDER);
-		rc = qpnp_led_masked_write(led,
-			FLASH_SAFETY_TIMER(led->base),
-			FLASH_SAFETY_TIMER_MASK, val);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"Safety timer reg write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		rc = qpnp_led_masked_write(led,
-			FLASH_MAX_CURRENT(led->base),
-			FLASH_CURRENT_MASK, FLASH_MAX_LEVEL);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"Max current reg write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		if (!led->charging_enabled) {
-			rc = qpnp_led_masked_write(led,
-				FLASH_MODULE_ENABLE_CTRL(led->base),
-				FLASH_MODULE_ENABLE, FLASH_MODULE_ENABLE);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Module enable reg write failed\n");
-				goto exit_flash_led_work;
-			}
-
-			usleep_range(FLASH_RAMP_UP_DELAY_US_MIN,
-						FLASH_RAMP_UP_DELAY_US_MAX);
-		}
-
-		if (led->revid_data->pmic_subtype == PMI8996_SUBTYPE &&
-						!led->revid_data->rev3) {
-			rc = power_supply_set_property(led->battery_psy,
-						POWER_SUPPLY_PROP_FLASH_TRIGGER,
-							&psy_prop);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-				"Failed to disable charger i/p curr limit\n");
-				goto exit_flash_led_work;
-			}
-		}
-
-		if (led->pdata->hdrm_sns_ch0_en ||
-					led->pdata->hdrm_sns_ch1_en) {
-			if (flash_node->id == FLASH_LED_SWITCH) {
-				rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					(flash_node->trigger &
-					FLASH_LED0_TRIGGER ?
-					FLASH_LED_HDRM_SNS_ENABLE :
-					FLASH_LED_HDRM_SNS_DISABLE));
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"Headroom sense enable failed\n");
-					goto exit_flash_led_work;
-				}
-
-				rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					(flash_node->trigger &
-					FLASH_LED1_TRIGGER ?
-					FLASH_LED_HDRM_SNS_ENABLE :
-					FLASH_LED_HDRM_SNS_DISABLE));
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"Headroom sense enable failed\n");
-					goto exit_flash_led_work;
-				}
-			} else if (flash_node->id == FLASH_LED_0) {
-				rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					FLASH_LED_HDRM_SNS_ENABLE);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"Headroom sense disable failed\n");
-					goto exit_flash_led_work;
-				}
-			} else if (flash_node->id == FLASH_LED_1) {
-				rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					FLASH_LED_HDRM_SNS_ENABLE);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"Headroom sense disable failed\n");
-					goto exit_flash_led_work;
-				}
-			}
-		}
-
-		rc = qpnp_led_masked_write(led,
-			FLASH_LED_STROBE_CTRL(led->base),
-			(flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
-						| FLASH_LED_STROBE_TYPE_HW
-							: flash_node->trigger |
-						FLASH_LED_STROBE_TYPE_HW),
-							flash_node->trigger);
-		if (rc) {
-			dev_err(&led->pdev->dev, "Strobe reg write failed\n");
-			goto exit_flash_led_work;
-		}
-
-		if (led->strobe_debug && led->dbg_feature_en) {
-			udelay(2000);
-			rc = regmap_read(led->regmap,
-					 FLASH_LED_FAULT_STATUS(led->base),
-					 &temp);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-				"Unable to read from addr= %x, rc(%d)\n",
-				FLASH_LED_FAULT_STATUS(led->base), rc);
-				goto exit_flash_led_work;
-			}
-			led->fault_reg = temp;
-		}
-	} else {
-		pr_err("Both Torch and Flash cannot be select at same time\n");
-		for (i = 0; i < led->num_leds; i++)
-			led->flash_node[i].flash_on = false;
-		goto turn_off;
-	}
-
-	flash_node->flash_on = true;
-	mutex_unlock(&led->flash_led_lock);
-
-	return;
-
-turn_off:
-	if (led->flash_node[led->num_leds - 1].id == FLASH_LED_SWITCH &&
-					flash_node->id != FLASH_LED_SWITCH)
-		led->flash_node[led->num_leds - 1].trigger &=
-						~(0x80 >> flash_node->id);
-	if (flash_node->type == TORCH) {
-		/*
-		 * Checking LED fault status detects hardware open fault.
-		 * If fault occurs, all subsequent LED enablement requests
-		 * will be rejected to protect hardware.
-		 */
-		rc = regmap_read(led->regmap,
-			FLASH_LED_FAULT_STATUS(led->base), &temp);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"Failed to read out fault status register\n");
-			goto exit_flash_led_work;
-		}
-
-		led->open_fault |= (val & FLASH_LED_OPEN_FAULT_DETECTED);
-	}
-
-	rc = qpnp_led_masked_write(led,
-			FLASH_LED_STROBE_CTRL(led->base),
-			(flash_node->id == FLASH_LED_SWITCH ? FLASH_STROBE_MASK
-						| FLASH_LED_STROBE_TYPE_HW
-						: flash_node->trigger
-						| FLASH_LED_STROBE_TYPE_HW),
-						FLASH_LED_DISABLE);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Strobe disable failed\n");
-		goto exit_flash_led_work;
-	}
-
-	usleep_range(FLASH_RAMP_DN_DELAY_US_MIN, FLASH_RAMP_DN_DELAY_US_MAX);
-exit_flash_hdrm_sns:
-	if (led->pdata->hdrm_sns_ch0_en) {
-		if (flash_node->id == FLASH_LED_0 ||
-				flash_node->id == FLASH_LED_SWITCH) {
-			rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL0(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					FLASH_LED_HDRM_SNS_DISABLE);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Headroom sense disable failed\n");
-				goto exit_flash_hdrm_sns;
-			}
-		}
-	}
-
-	if (led->pdata->hdrm_sns_ch1_en) {
-		if (flash_node->id == FLASH_LED_1 ||
-				flash_node->id == FLASH_LED_SWITCH) {
-			rc = qpnp_led_masked_write(led,
-					FLASH_HDRM_SNS_ENABLE_CTRL1(led->base),
-					FLASH_LED_HDRM_SNS_ENABLE_MASK,
-					FLASH_LED_HDRM_SNS_DISABLE);
-			if (rc) {
-				dev_err(&led->pdev->dev,
-					"Headroom sense disable failed\n");
-				goto exit_flash_hdrm_sns;
-			}
-		}
-	}
-exit_flash_led_work:
-	rc = qpnp_flash_led_module_disable(led, flash_node);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Module disable failed\n");
-		goto exit_flash_led_work;
-	}
-error_enable_gpio:
-	if (flash_node->flash_on && flash_node->num_regulators > 0)
-		flash_regulator_enable(led, flash_node, false);
-
-	flash_node->flash_on = false;
-	mutex_unlock(&led->flash_led_lock);
-}
-
-static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
-						enum led_brightness value)
-{
-	struct flash_node_data *flash_node;
-	struct qpnp_flash_led *led;
-
-	flash_node = container_of(led_cdev, struct flash_node_data, cdev);
-	led = dev_get_drvdata(&flash_node->pdev->dev);
-
-	if (value < LED_OFF) {
-		pr_err("Invalid brightness value\n");
-		return;
-	}
-
-	if (value > flash_node->cdev.max_brightness)
-		value = flash_node->cdev.max_brightness;
-
-	flash_node->cdev.brightness = value;
-	if (led->flash_node[led->num_leds - 1].id ==
-						FLASH_LED_SWITCH) {
-		if (flash_node->type == TORCH)
-			led->flash_node[led->num_leds - 1].type = TORCH;
-		else if (flash_node->type == FLASH)
-			led->flash_node[led->num_leds - 1].type = FLASH;
-
-		led->flash_node[led->num_leds - 1].max_current
-						= flash_node->max_current;
-
-		if (flash_node->id == FLASH_LED_0 ||
-					 flash_node->id == FLASH_LED_1) {
-			if (value < FLASH_LED_MIN_CURRENT_MA && value != 0)
-				value = FLASH_LED_MIN_CURRENT_MA;
-
-			flash_node->prgm_current = value;
-			flash_node->flash_on = value ? true : false;
-		} else if (flash_node->id == FLASH_LED_SWITCH) {
-			if (!value) {
-				flash_node->prgm_current = 0;
-				flash_node->prgm_current2 = 0;
-			}
-		}
-	} else {
-		if (value < FLASH_LED_MIN_CURRENT_MA && value != 0)
-			value = FLASH_LED_MIN_CURRENT_MA;
-		flash_node->prgm_current = value;
-	}
-
-	queue_work(led->ordered_workq, &flash_node->work);
-}
-
-static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
-{
-	int rc;
-	u8 val, temp_val;
-	uint val_int;
-
-	rc = qpnp_led_masked_write(led,
-			FLASH_MODULE_ENABLE_CTRL(led->base),
-			FLASH_MODULE_ENABLE_MASK,
-			FLASH_LED_MODULE_CTRL_DEFAULT);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Module disable failed\n");
-		return rc;
-	}
-
-	rc = qpnp_led_masked_write(led,
-			FLASH_LED_STROBE_CTRL(led->base),
-			FLASH_STROBE_MASK, FLASH_LED_DISABLE);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Strobe disable failed\n");
-		return rc;
-	}
-
-	rc = qpnp_led_masked_write(led,
-					FLASH_LED_TMR_CTRL(led->base),
-					FLASH_TMR_MASK, FLASH_TMR_SAFETY);
-	if (rc) {
-		dev_err(&led->pdev->dev,
-			"LED timer ctrl reg write failed(%d)\n", rc);
-		return rc;
-	}
-
-	val = (u8)(led->pdata->headroom / FLASH_LED_HEADROOM_DIVIDER -
-						FLASH_LED_HEADROOM_OFFSET);
-	rc = qpnp_led_masked_write(led,
-						FLASH_HEADROOM(led->base),
-						FLASH_HEADROOM_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Headroom reg write failed\n");
-		return rc;
-	}
-
-	val = qpnp_flash_led_get_startup_dly(led->pdata->startup_dly);
-
-	rc = qpnp_led_masked_write(led,
-					FLASH_STARTUP_DELAY(led->base),
-						FLASH_STARTUP_DLY_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Startup delay reg write failed\n");
-		return rc;
-	}
-
-	val = (u8)(led->pdata->clamp_current * FLASH_MAX_LEVEL /
-						FLASH_LED_MAX_CURRENT_MA);
-	rc = qpnp_led_masked_write(led,
-					FLASH_CLAMP_CURRENT(led->base),
-						FLASH_CURRENT_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Clamp current reg write failed\n");
-		return rc;
-	}
-
-	if (led->pdata->pmic_charger_support)
-		val = FLASH_LED_FLASH_HW_VREG_OK;
-	else
-		val = FLASH_LED_FLASH_SW_VREG_OK;
-	rc = qpnp_led_masked_write(led,
-					FLASH_VREG_OK_FORCE(led->base),
-						FLASH_VREG_OK_FORCE_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "VREG OK force reg write failed\n");
-		return rc;
-	}
-
-	if (led->pdata->self_check_en)
-		val = FLASH_MODULE_ENABLE;
-	else
-		val = FLASH_LED_DISABLE;
-	rc = qpnp_led_masked_write(led,
-					FLASH_FAULT_DETECT(led->base),
-						FLASH_FAULT_DETECT_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Fault detect reg write failed\n");
-		return rc;
-	}
-
-	val = 0x0;
-	val |= led->pdata->mask3_en << FLASH_LED_MASK3_ENABLE_SHIFT;
-	val |= FLASH_LED_MASK_MODULE_MASK2_ENABLE;
-	rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base),
-				FLASH_MASK_MODULE_CONTRL_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Mask module enable failed\n");
-		return rc;
-	}
-
-	rc = regmap_read(led->regmap, FLASH_PERPH_RESET_CTRL(led->base),
-			&val_int);
-	if (rc) {
-		dev_err(&led->pdev->dev,
-			"Unable to read from address %x, rc(%d)\n",
-			FLASH_PERPH_RESET_CTRL(led->base), rc);
-		return -EINVAL;
-	}
-	val = (u8)val_int;
-
-	if (led->pdata->follow_rb_disable) {
-		rc = qpnp_led_masked_write(led,
-				FLASH_LED_UNLOCK_SECURE(led->base),
-				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
-		if (rc) {
-			dev_err(&led->pdev->dev, "Secure reg write failed\n");
-			return -EINVAL;
-		}
-
-		val |= FLASH_FOLLOW_OTST2_RB_MASK;
-		rc = qpnp_led_masked_write(led,
-				FLASH_PERPH_RESET_CTRL(led->base),
-				FLASH_FOLLOW_OTST2_RB_MASK, val);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"failed to reset OTST2_RB bit\n");
-			return rc;
-		}
-	} else {
-		rc = qpnp_led_masked_write(led,
-				FLASH_LED_UNLOCK_SECURE(led->base),
-				FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
-		if (rc) {
-			dev_err(&led->pdev->dev, "Secure reg write failed\n");
-			return -EINVAL;
-		}
-
-		val &= ~FLASH_FOLLOW_OTST2_RB_MASK;
-		rc = qpnp_led_masked_write(led,
-				FLASH_PERPH_RESET_CTRL(led->base),
-				FLASH_FOLLOW_OTST2_RB_MASK, val);
-		if (rc) {
-			dev_err(&led->pdev->dev,
-				"failed to reset OTST2_RB bit\n");
-			return rc;
-		}
-	}
-
-	if (!led->pdata->thermal_derate_en)
-		val = 0x0;
-	else {
-		val = led->pdata->thermal_derate_en << 7;
-		val |= led->pdata->thermal_derate_rate << 3;
-		val |= (led->pdata->thermal_derate_threshold -
-				FLASH_LED_THERMAL_THRESHOLD_MIN) /
-				FLASH_LED_THERMAL_DEVIDER;
-	}
-	rc = qpnp_led_masked_write(led,
-					FLASH_THERMAL_DRATE(led->base),
-					FLASH_THERMAL_DERATE_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Thermal derate reg write failed\n");
-		return rc;
-	}
-
-	if (!led->pdata->current_ramp_en)
-		val = 0x0;
-	else {
-		val = led->pdata->current_ramp_en << 7;
-		val |= led->pdata->ramp_up_step << 3;
-		val |= led->pdata->ramp_dn_step;
-	}
-	rc = qpnp_led_masked_write(led,
-						FLASH_CURRENT_RAMP(led->base),
-						FLASH_CURRENT_RAMP_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "Current ramp reg write failed\n");
-		return rc;
-	}
-
-	if (!led->pdata->vph_pwr_droop_en)
-		val = 0x0;
-	else {
-		val = led->pdata->vph_pwr_droop_en << 7;
-		val |= ((led->pdata->vph_pwr_droop_threshold -
-				FLASH_LED_VPH_DROOP_THRESHOLD_MIN_MV) /
-				FLASH_LED_VPH_DROOP_THRESHOLD_DIVIDER) << 4;
-		temp_val =
-			qpnp_flash_led_get_droop_debounce_time(
-				led->pdata->vph_pwr_droop_debounce_time);
-		if (temp_val == 0xFF) {
-			dev_err(&led->pdev->dev, "Invalid debounce time\n");
-			return temp_val;
-		}
-
-		val |= temp_val;
-	}
-	rc = qpnp_led_masked_write(led,
-						FLASH_VPH_PWR_DROOP(led->base),
-						FLASH_VPH_PWR_DROOP_MASK, val);
-	if (rc) {
-		dev_err(&led->pdev->dev, "VPH PWR droop reg write failed\n");
-		return rc;
-	}
-
-	led->battery_psy = power_supply_get_by_name("battery");
-	if (!led->battery_psy) {
-		dev_err(&led->pdev->dev,
-			"Failed to get battery power supply\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
-					struct flash_node_data *flash_node)
-{
-	const char *temp_string;
-	struct device_node *node = flash_node->cdev.dev->of_node;
-	struct device_node *temp = NULL;
-	int rc = 0, num_regs = 0;
-	u32 val;
-
-	rc = of_property_read_string(node, "label", &temp_string);
-	if (!rc) {
-		if (strcmp(temp_string, "flash") == 0)
-			flash_node->type = FLASH;
-		else if (strcmp(temp_string, "torch") == 0)
-			flash_node->type = TORCH;
-		else if (strcmp(temp_string, "switch") == 0)
-			flash_node->type = SWITCH;
-		else {
-			dev_err(&led->pdev->dev, "Wrong flash LED type\n");
-			return -EINVAL;
-		}
-	} else if (rc < 0) {
-		dev_err(&led->pdev->dev, "Unable to read flash type\n");
-		return rc;
-	}
-
-	rc = of_property_read_u32(node, "qcom,current", &val);
-	if (!rc) {
-		if (val < FLASH_LED_MIN_CURRENT_MA)
-			val = FLASH_LED_MIN_CURRENT_MA;
-		flash_node->prgm_current = val;
-	} else if (rc != -EINVAL) {
-		dev_err(&led->pdev->dev, "Unable to read current\n");
-		return rc;
-	}
-
-	rc = of_property_read_u32(node, "qcom,id", &val);
-	if (!rc)
-		flash_node->id = (u8)val;
-	else if (rc != -EINVAL) {
-		dev_err(&led->pdev->dev, "Unable to read led ID\n");
-		return rc;
-	}
-
-	if (flash_node->type == SWITCH || flash_node->type == FLASH) {
-		rc = of_property_read_u32(node, "qcom,duration", &val);
-		if (!rc)
-			flash_node->duration = (u16)val;
-		else if (rc != -EINVAL) {
-			dev_err(&led->pdev->dev, "Unable to read duration\n");
-			return rc;
-		}
-	}
-
-	switch (led->peripheral_type) {
-	case FLASH_SUBTYPE_SINGLE:
-		flash_node->trigger = FLASH_LED0_TRIGGER;
-		break;
-	case FLASH_SUBTYPE_DUAL:
-		if (flash_node->id == FLASH_LED_0)
-			flash_node->trigger = FLASH_LED0_TRIGGER;
-		else if (flash_node->id == FLASH_LED_1)
-			flash_node->trigger = FLASH_LED1_TRIGGER;
-		break;
-	default:
-		dev_err(&led->pdev->dev, "Invalid peripheral type\n");
-	}
-
-	while ((temp = of_get_next_child(node, temp))) {
-		if (of_find_property(temp, "regulator-name", NULL))
-			num_regs++;
-	}
-
-	if (num_regs)
-		flash_node->num_regulators = num_regs;
-
-	return rc;
-}
-
-static int qpnp_flash_led_parse_common_dt(
-				struct qpnp_flash_led *led,
-						struct device_node *node)
-{
-	int rc;
-	u32 val, temp_val;
-	const char *temp;
-
-	led->pdata->headroom = FLASH_LED_HEADROOM_DEFAULT_MV;
-	rc = of_property_read_u32(node, "qcom,headroom", &val);
-	if (!rc)
-		led->pdata->headroom = (u16)val;
-	else if (rc != -EINVAL) {
-		dev_err(&led->pdev->dev, "Unable to read headroom\n");
-		return rc;
-	}
-
-	led->pdata->startup_dly = FLASH_LED_STARTUP_DELAY_DEFAULT_US;
-	rc = of_property_read_u32(node, "qcom,startup-dly", &val);
-	if (!rc)
-		led->pdata->startup_dly = (u8)val;
-	else if (rc != -EINVAL) {
-		dev_err(&led->pdev->dev, "Unable to read startup delay\n");
-		return rc;
-	}
-
-	led->pdata->clamp_current = FLASH_LED_CLAMP_CURRENT_DEFAULT_MA;
-	rc = of_property_read_u32(node, "qcom,clamp-current", &val);
-	if (!rc) {
-		if (val < FLASH_LED_MIN_CURRENT_MA)
-			val = FLASH_LED_MIN_CURRENT_MA;
-		led->pdata->clamp_current = (u16)val;
-	} else if (rc != -EINVAL) {
-		dev_err(&led->pdev->dev, "Unable to read clamp current\n");
-		return rc;
-	}
-
-	led->pdata->pmic_charger_support =
-			of_property_read_bool(node,
-						"qcom,pmic-charger-support");
-
-	led->pdata->self_check_en =
-			of_property_read_bool(node, "qcom,self-check-enabled");
-
-	led->pdata->thermal_derate_en =
-			of_property_read_bool(node,
-						"qcom,thermal-derate-enabled");
-
-	if (led->pdata->thermal_derate_en) {
-		led->pdata->thermal_derate_rate =
-				FLASH_LED_THERMAL_DERATE_RATE_DEFAULT_PERCENT;
-		rc = of_property_read_string(node, "qcom,thermal-derate-rate",
-									&temp);
-		if (!rc) {
-			temp_val =
-				qpnp_flash_led_get_thermal_derate_rate(temp);
-			if (temp_val < 0) {
-				dev_err(&led->pdev->dev,
-					"Invalid thermal derate rate\n");
-				return -EINVAL;
-			}
-
-			led->pdata->thermal_derate_rate = (u8)temp_val;
-		} else {
-			dev_err(&led->pdev->dev,
-				"Unable to read thermal derate rate\n");
-			return -EINVAL;
-		}
-
-		led->pdata->thermal_derate_threshold =
-				FLASH_LED_THERMAL_DERATE_THRESHOLD_DEFAULT_C;
-		rc = of_property_read_u32(node, "qcom,thermal-derate-threshold",
-									&val);
-		if (!rc)
-			led->pdata->thermal_derate_threshold = (u8)val;
-		else if (rc != -EINVAL) {
-			dev_err(&led->pdev->dev,
-				"Unable to read thermal derate threshold\n");
-			return rc;
-		}
-	}
-
-	led->pdata->current_ramp_en =
-			of_property_read_bool(node,
-						"qcom,current-ramp-enabled");
-	if (led->pdata->current_ramp_en) {
-		led->pdata->ramp_up_step = FLASH_LED_RAMP_UP_STEP_DEFAULT_US;
-		rc = of_property_read_string(node, "qcom,ramp_up_step", &temp);
-		if (!rc) {
-			temp_val = qpnp_flash_led_get_ramp_step(temp);
-			if (temp_val < 0) {
-				dev_err(&led->pdev->dev,
-					"Invalid ramp up step values\n");
-				return -EINVAL;
-			}
-			led->pdata->ramp_up_step = (u8)temp_val;
-		} else if (rc != -EINVAL) {
-			dev_err(&led->pdev->dev,
-					"Unable to read ramp up steps\n");
-			return rc;
-		}
-
-		led->pdata->ramp_dn_step = FLASH_LED_RAMP_DN_STEP_DEFAULT_US;
-		rc = of_property_read_string(node, "qcom,ramp_dn_step", &temp);
-		if (!rc) {
-			temp_val = qpnp_flash_led_get_ramp_step(temp);
-			if (temp_val < 0) {
-				dev_err(&led->pdev->dev,
-					"Invalid ramp down step values\n");
-				return rc;
-			}
-			led->pdata->ramp_dn_step = (u8)temp_val;
-		} else if (rc != -EINVAL) {
-			dev_err(&led->pdev->dev,
-					"Unable to read ramp down steps\n");
-			return rc;
-		}
-	}
-
-	led->pdata->vph_pwr_droop_en = of_property_read_bool(node,
-						"qcom,vph-pwr-droop-enabled");
-	if (led->pdata->vph_pwr_droop_en) {
-		led->pdata->vph_pwr_droop_threshold =
-				FLASH_LED_VPH_PWR_DROOP_THRESHOLD_DEFAULT_MV;
-		rc = of_property_read_u32(node,
-					"qcom,vph-pwr-droop-threshold", &val);
-		if (!rc) {
-			led->pdata->vph_pwr_droop_threshold = (u16)val;
-		} else if (rc != -EINVAL) {
-			dev_err(&led->pdev->dev,
-				"Unable to read VPH PWR droop threshold\n");
-			return rc;
-		}
-
-		led->pdata->vph_pwr_droop_debounce_time =
-			FLASH_LED_VPH_PWR_DROOP_DEBOUNCE_TIME_DEFAULT_US;
-		rc = of_property_read_u32(node,
-				"qcom,vph-pwr-droop-debounce-time", &val);
-		if (!rc)
-			led->pdata->vph_pwr_droop_debounce_time = (u8)val;
-		else if (rc != -EINVAL) {
-			dev_err(&led->pdev->dev,
-				"Unable to read VPH PWR droop debounce time\n");
-			return rc;
-		}
-	}
-
-	led->pdata->hdrm_sns_ch0_en = of_property_read_bool(node,
-						"qcom,headroom-sense-ch0-enabled");
-
-	led->pdata->hdrm_sns_ch1_en = of_property_read_bool(node,
-						"qcom,headroom-sense-ch1-enabled");
-
-	led->pdata->power_detect_en = of_property_read_bool(node,
-						"qcom,power-detect-enabled");
-
-	led->pdata->mask3_en = of_property_read_bool(node,
-						"qcom,otst2-module-enabled");
-
-	led->pdata->follow_rb_disable = of_property_read_bool(node,
-						"qcom,follow-otst2-rb-disabled");
-
-	led->pdata->die_current_derate_en = of_property_read_bool(node,
-					"qcom,die-current-derate-enabled");
-
-	if (led->pdata->die_current_derate_en) {
-		led->vadc_dev = qpnp_get_vadc(&led->pdev->dev, "die-temp");
-		if (IS_ERR(led->vadc_dev)) {
-			pr_err("VADC channel property Missing\n");
-			return -EINVAL;
-		}
-
-		if (of_find_property(node, "qcom,die-temp-threshold",
-				&led->pdata->temp_threshold_num)) {
-			if (led->pdata->temp_threshold_num > 0) {
-				led->pdata->die_temp_threshold_degc =
-				devm_kzalloc(&led->pdev->dev,
-						led->pdata->temp_threshold_num,
-						GFP_KERNEL);
-
-				if (led->pdata->die_temp_threshold_degc
-								== NULL) {
-					dev_err(&led->pdev->dev,
-					"failed to allocate die temp array\n");
-					return -ENOMEM;
-				}
-				led->pdata->temp_threshold_num /=
-							sizeof(unsigned int);
-
-				rc = of_property_read_u32_array(node,
-						"qcom,die-temp-threshold",
-				led->pdata->die_temp_threshold_degc,
-						led->pdata->temp_threshold_num);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"couldn't read temp threshold rc=%d\n",
-								rc);
-					return rc;
-				}
-			}
-		}
-
-		if (of_find_property(node, "qcom,die-temp-derate-current",
-					&led->pdata->temp_derate_curr_num)) {
-			if (led->pdata->temp_derate_curr_num > 0) {
-				led->pdata->die_temp_derate_curr_ma =
-					devm_kzalloc(&led->pdev->dev,
-					led->pdata->temp_derate_curr_num,
-					GFP_KERNEL);
-				if (led->pdata->die_temp_derate_curr_ma
-								== NULL) {
-					dev_err(&led->pdev->dev,
-						"failed to allocate die derate current array\n");
-					return -ENOMEM;
-				}
-				led->pdata->temp_derate_curr_num /=
-						sizeof(unsigned int);
-
-				rc = of_property_read_u32_array(node,
-						"qcom,die-temp-derate-current",
-				led->pdata->die_temp_derate_curr_ma,
-				led->pdata->temp_derate_curr_num);
-				if (rc) {
-					dev_err(&led->pdev->dev,
-					"couldn't read temp limits rc =%d\n",
-								rc);
-					return rc;
-				}
-			}
-		}
-		if (led->pdata->temp_threshold_num !=
-					led->pdata->temp_derate_curr_num) {
-			pr_err("Both array size are not same\n");
-			return -EINVAL;
-		}
-	}
-
-	led->pinctrl = devm_pinctrl_get(&led->pdev->dev);
-	if (IS_ERR_OR_NULL(led->pinctrl)) {
-		dev_err(&led->pdev->dev, "Unable to acquire pinctrl\n");
-		led->pinctrl = NULL;
-		return 0;
-	}
-
-	led->gpio_state_active = pinctrl_lookup_state(led->pinctrl,
-							"flash_led_enable");
-	if (IS_ERR_OR_NULL(led->gpio_state_active)) {
-		dev_err(&led->pdev->dev, "Cannot lookup LED active state\n");
-		devm_pinctrl_put(led->pinctrl);
-		led->pinctrl = NULL;
-		return PTR_ERR(led->gpio_state_active);
-	}
-
-	led->gpio_state_suspend = pinctrl_lookup_state(led->pinctrl,
-							"flash_led_disable");
-	if (IS_ERR_OR_NULL(led->gpio_state_suspend)) {
-		dev_err(&led->pdev->dev, "Cannot lookup LED disable state\n");
-		devm_pinctrl_put(led->pinctrl);
-		led->pinctrl = NULL;
-		return PTR_ERR(led->gpio_state_suspend);
-	}
-
-	return 0;
-}
-
-static int qpnp_flash_led_probe(struct platform_device *pdev)
-{
-	struct qpnp_flash_led *led;
-	unsigned int base;
-	struct device_node *node, *temp;
-	struct dentry *root, *file;
-	int rc, i = 0, j, num_leds = 0;
-	u32 val;
-
-	root = NULL;
-	node = pdev->dev.of_node;
-	if (node == NULL) {
-		dev_info(&pdev->dev, "No flash device defined\n");
-		return -ENODEV;
-	}
-
-	rc = of_property_read_u32(pdev->dev.of_node, "reg", &base);
-	if (rc < 0) {
-		dev_err(&pdev->dev,
-			"Couldn't find reg in node = %s rc = %d\n",
-			pdev->dev.of_node->full_name, rc);
-		return rc;
-	}
-
-	led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
-	if (!led)
-		return -ENOMEM;
-
-	led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
-	if (!led->regmap) {
-		dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
-		return -EINVAL;
-	}
-
-	led->base = base;
-	led->pdev = pdev;
-	led->current_addr = FLASH_LED0_CURRENT(led->base);
-	led->current2_addr = FLASH_LED1_CURRENT(led->base);
-
-	led->pdata = devm_kzalloc(&pdev->dev, sizeof(*led->pdata), GFP_KERNEL);
-	if (!led->pdata)
-		return -ENOMEM;
-
-	led->peripheral_type = (u8)qpnp_flash_led_get_peripheral_type(led);
-	if (led->peripheral_type < 0) {
-		dev_err(&pdev->dev, "Failed to get peripheral type\n");
-		return rc;
-	}
-
-	rc = qpnp_flash_led_parse_common_dt(led, node);
-	if (rc) {
-		dev_err(&pdev->dev,
-			"Failed to get common config for flash LEDs\n");
-		return rc;
-	}
-
-	rc = qpnp_flash_led_init_settings(led);
-	if (rc) {
-		dev_err(&pdev->dev, "Failed to initialize flash LED\n");
-		return rc;
-	}
-
-	rc = qpnp_get_pmic_revid(led);
-	if (rc)
-		return rc;
-
-	temp = NULL;
-	while ((temp = of_get_next_child(node, temp)))
-		num_leds++;
-
-	if (!num_leds)
-		return -ECHILD;
-
-	led->flash_node = devm_kzalloc(&pdev->dev,
-			(sizeof(struct flash_node_data) * num_leds),
-			GFP_KERNEL);
-	if (!led->flash_node) {
-		dev_err(&pdev->dev, "Unable to allocate memory\n");
-		return -ENOMEM;
-	}
-
-	mutex_init(&led->flash_led_lock);
-
-	led->ordered_workq = alloc_ordered_workqueue("flash_led_workqueue", 0);
-	if (!led->ordered_workq) {
-		dev_err(&pdev->dev, "Failed to allocate ordered workqueue\n");
-		return -ENOMEM;
-	}
-
-	for_each_child_of_node(node, temp) {
-		led->flash_node[i].cdev.brightness_set =
-						qpnp_flash_led_brightness_set;
-		led->flash_node[i].cdev.brightness_get =
-						qpnp_flash_led_brightness_get;
-		led->flash_node[i].pdev = pdev;
-
-		INIT_WORK(&led->flash_node[i].work, qpnp_flash_led_work);
-		rc = of_property_read_string(temp, "qcom,led-name",
-						&led->flash_node[i].cdev.name);
-		if (rc < 0) {
-			dev_err(&led->pdev->dev,
-					"Unable to read flash name\n");
-			return rc;
-		}
-
-		rc = of_property_read_string(temp, "qcom,default-led-trigger",
-				&led->flash_node[i].cdev.default_trigger);
-		if (rc < 0) {
-			dev_err(&led->pdev->dev,
-					"Unable to read trigger name\n");
-			return rc;
-		}
-
-		rc = of_property_read_u32(temp, "qcom,max-current", &val);
-		if (!rc) {
-			if (val < FLASH_LED_MIN_CURRENT_MA)
-				val = FLASH_LED_MIN_CURRENT_MA;
-			led->flash_node[i].max_current = (u16)val;
-			led->flash_node[i].cdev.max_brightness = val;
-		} else {
-			dev_err(&led->pdev->dev,
-					"Unable to read max current\n");
-			return rc;
-		}
-		rc = led_classdev_register(&pdev->dev,
-						&led->flash_node[i].cdev);
-		if (rc) {
-			dev_err(&pdev->dev, "Unable to register led\n");
-			goto error_led_register;
-		}
-
-		led->flash_node[i].cdev.dev->of_node = temp;
-
-		rc = qpnp_flash_led_parse_each_led_dt(led, &led->flash_node[i]);
-		if (rc) {
-			dev_err(&pdev->dev,
-				"Failed to parse config for each LED\n");
-			goto error_led_register;
-		}
-
-		if (led->flash_node[i].num_regulators) {
-			rc = flash_regulator_parse_dt(led, &led->flash_node[i]);
-			if (rc) {
-				dev_err(&pdev->dev,
-					"Unable to parse regulator data\n");
-				goto error_led_register;
-			}
-
-			rc = flash_regulator_setup(led, &led->flash_node[i],
-									true);
-			if (rc) {
-				dev_err(&pdev->dev,
-					"Unable to set up regulator\n");
-				goto error_led_register;
-			}
-		}
-
-		for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
-			rc =
-			sysfs_create_file(&led->flash_node[i].cdev.dev->kobj,
-					&qpnp_flash_led_attrs[j].attr);
-			if (rc)
-				goto error_led_register;
-		}
-
-		i++;
-	}
-
-	led->num_leds = i;
-
-	root = debugfs_create_dir("flashLED", NULL);
-	if (IS_ERR_OR_NULL(root)) {
-		pr_err("Error creating top level directory err%ld",
-			(long)root);
-		if (PTR_ERR(root) == -ENODEV)
-			pr_err("debugfs is not enabled in kernel");
-		goto error_led_debugfs;
-	}
-
-	led->dbgfs_root = root;
-	file = debugfs_create_file("enable_debug", 0600, root, led,
-					&flash_led_dfs_dbg_feature_fops);
-	if (!file) {
-		pr_err("error creating 'enable_debug' entry\n");
-		goto error_led_debugfs;
-	}
-
-	file = debugfs_create_file("latched", 0600, root, led,
-					&flash_led_dfs_latched_reg_fops);
-	if (!file) {
-		pr_err("error creating 'latched' entry\n");
-		goto error_led_debugfs;
-	}
-
-	file = debugfs_create_file("strobe", 0600, root, led,
-					&flash_led_dfs_strobe_reg_fops);
-	if (!file) {
-		pr_err("error creating 'strobe' entry\n");
-		goto error_led_debugfs;
-	}
-
-	dev_set_drvdata(&pdev->dev, led);
-
-	return 0;
-
-error_led_debugfs:
-	i = led->num_leds - 1;
-	j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
-error_led_register:
-	for (; i >= 0; i--) {
-		for (; j >= 0; j--)
-			sysfs_remove_file(&led->flash_node[i].cdev.dev->kobj,
-						&qpnp_flash_led_attrs[j].attr);
-		j = ARRAY_SIZE(qpnp_flash_led_attrs) - 1;
-		led_classdev_unregister(&led->flash_node[i].cdev);
-	}
-	debugfs_remove_recursive(root);
-	mutex_destroy(&led->flash_led_lock);
-	destroy_workqueue(led->ordered_workq);
-
-	return rc;
-}
-
-static int qpnp_flash_led_remove(struct platform_device *pdev)
-{
-	struct qpnp_flash_led *led  = dev_get_drvdata(&pdev->dev);
-	int i, j;
-
-	for (i = led->num_leds - 1; i >= 0; i--) {
-		if (led->flash_node[i].reg_data) {
-			if (led->flash_node[i].flash_on)
-				flash_regulator_enable(led,
-						&led->flash_node[i], false);
-			flash_regulator_setup(led, &led->flash_node[i],
-								false);
-		}
-		for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
-			sysfs_remove_file(&led->flash_node[i].cdev.dev->kobj,
-						&qpnp_flash_led_attrs[j].attr);
-		led_classdev_unregister(&led->flash_node[i].cdev);
-	}
-	debugfs_remove_recursive(led->dbgfs_root);
-	mutex_destroy(&led->flash_led_lock);
-	destroy_workqueue(led->ordered_workq);
-
-	return 0;
-}
-
-static const struct of_device_id spmi_match_table[] = {
-	{ .compatible = "qcom,qpnp-flash-led",},
-	{ },
-};
-
-static struct platform_driver qpnp_flash_led_driver = {
-	.driver		= {
-		.name		= "qcom,qpnp-flash-led",
-		.of_match_table	= spmi_match_table,
-	},
-	.probe		= qpnp_flash_led_probe,
-	.remove		= qpnp_flash_led_remove,
-};
-
-static int __init qpnp_flash_led_init(void)
-{
-	return platform_driver_register(&qpnp_flash_led_driver);
-}
-late_initcall(qpnp_flash_led_init);
-
-static void __exit qpnp_flash_led_exit(void)
-{
-	platform_driver_unregister(&qpnp_flash_led_driver);
-}
-module_exit(qpnp_flash_led_exit);
-
-MODULE_DESCRIPTION("QPNP Flash LED driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("leds:leds-qpnp-flash");
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index f18022b..568c9f9 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -537,6 +537,11 @@
 {
 	int i, rc;
 	u8 reg;
+	u16 low_limit = WLED_MAX_LEVEL_4095 * 4 / 1000;
+
+	/* WLED's lower limit of operation is 0.4% */
+	if (level > 0 && level < low_limit)
+		level = low_limit;
 
 	/* set brightness registers */
 	for (i = 0; i < wled->max_strings; i++) {
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index 68ce696f..a315268 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -18,6 +18,7 @@
 #include <linux/timer.h>
 #include <media/cam_icp.h>
 #include <linux/iopoll.h>
+#include <soc/qcom/socinfo.h>
 
 #include "cam_io_util.h"
 #include "hfi_reg.h"
@@ -38,6 +39,9 @@
 #define HFI_VERSION_INFO_STEP_BMSK   0xFF
 #define HFI_VERSION_INFO_STEP_SHFT  0
 
+#define SOC_VERSION_HW1             0x10000
+#define SOC_VERSION_HW2             0x20000
+
 static struct hfi_info *g_hfi;
 unsigned int g_icp_mmu_hdl;
 static DEFINE_MUTEX(hfi_cmd_q_mutex);
@@ -350,7 +354,7 @@
 	struct hfi_qtbl *qtbl;
 	struct hfi_qtbl_hdr *qtbl_hdr;
 	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
-	uint32_t hw_version, fw_version, status = 0;
+	uint32_t hw_version, soc_version, fw_version, status = 0;
 
 	mutex_lock(&hfi_cmd_q_mutex);
 	mutex_lock(&hfi_msg_q_mutex);
@@ -370,7 +374,7 @@
 
 	memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map));
 	g_hfi->hfi_state = HFI_DEINIT;
-
+	soc_version = socinfo_get_version();
 	if (debug) {
 		cam_io_w_mb(
 		(uint32_t)(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN |
@@ -382,7 +386,9 @@
 		icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	} else {
 		cam_io_w((uint32_t)ICP_FLAG_CSR_A5_EN |
-			ICP_FLAG_CSR_WAKE_UP_EN | ICP_CSR_EN_CLKGATE_WFI,
+			ICP_FLAG_CSR_WAKE_UP_EN |
+			((soc_version == SOC_VERSION_HW1) ?
+			(ICP_CSR_EN_CLKGATE_WFI) : (0x0)),
 			icp_base + HFI_REG_A5_CSR_A5_CONTROL);
 	}
 
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index f878403..5055e8d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -652,9 +652,7 @@
 		return -ENOMEM;
 
 	abort_cmd.size =
-		sizeof(struct hfi_cmd_ipebps_async) +
-		sizeof(struct hfi_cmd_abort_destroy) -
-		sizeof(abort_cmd.payload.direct);
+		sizeof(struct hfi_cmd_ipebps_async);
 	abort_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT;
 	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
 		abort_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_ABORT;
@@ -706,9 +704,7 @@
 		return -ENOMEM;
 
 	destroy_cmd.size =
-		sizeof(struct hfi_cmd_ipebps_async) +
-		sizeof(struct ipe_bps_destroy) -
-		sizeof(destroy_cmd.payload.direct);
+		sizeof(struct hfi_cmd_ipebps_async);
 	destroy_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT;
 	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
 		destroy_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY;
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 5d7a1b9..c041eef 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
@@ -36,6 +36,9 @@
 #define CAM_VFE_RDI_BUS_DEFAULT_WIDTH           0xFF01
 #define CAM_VFE_RDI_BUS_DEFAULT_STRIDE          0xFF01
 
+#define ALIGNUP(value, alignment) \
+	((value + alignment - 1) / alignment * alignment)
+
 #define MAX_BUF_UPDATE_REG_NUM   \
 	(sizeof(struct cam_vfe_bus_ver2_reg_offset_bus_client)/4)
 #define MAX_REG_VAL_PAIR_SIZE    \
@@ -732,9 +735,22 @@
 		rsrc_data->index == 7 || rsrc_data->index == 8) {
 		/* Write master 3, 4 - for Full OUT , 7-8  FD OUT */
 		switch (rsrc_data->format) {
-		case CAM_FORMAT_UBWC_NV12:
 		case CAM_FORMAT_UBWC_NV12_4R:
 			rsrc_data->en_ubwc = 1;
+			rsrc_data->width = ALIGNUP(rsrc_data->width, 64);
+			switch (plane) {
+			case PLANE_C:
+				rsrc_data->height /= 2;
+				break;
+			case PLANE_Y:
+				break;
+			default:
+				CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+				return -EINVAL;
+			}
+			break;
+		case CAM_FORMAT_UBWC_NV12:
+			rsrc_data->en_ubwc = 1;
 			/* Fall through for NV12 */
 		case CAM_FORMAT_NV21:
 		case CAM_FORMAT_NV12:
@@ -751,9 +767,22 @@
 			break;
 		case CAM_FORMAT_UBWC_TP10:
 			rsrc_data->en_ubwc = 1;
-			/* Fall through for LINEAR TP10 */
+			rsrc_data->width =
+				ALIGNUP(rsrc_data->width, 48) * 4 / 3;
+			switch (plane) {
+			case PLANE_C:
+				rsrc_data->height /= 2;
+				break;
+			case PLANE_Y:
+				break;
+			default:
+				CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+				return -EINVAL;
+			}
+			break;
 		case CAM_FORMAT_TP10:
-			rsrc_data->width = rsrc_data->width * 4 / 3;
+			rsrc_data->width =
+				ALIGNUP(rsrc_data->width, 3) * 4 / 3;
 			switch (plane) {
 			case PLANE_C:
 				rsrc_data->height /= 2;
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 b0fe8db..0704602 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -915,6 +915,44 @@
 }
 
 /*
+ * sde_rotator_req_wait_for_idle - wait for hw for a request to be idle
+ * @mgr: Pointer to rotator manager
+ * @req: Pointer to rotation request
+ */
+static void sde_rotator_req_wait_for_idle(struct sde_rot_mgr *mgr,
+		struct sde_rot_entry_container *req)
+{
+	struct sde_rot_queue *queue;
+	struct sde_rot_hw_resource *hw;
+	int i, ret;
+
+	if (!mgr || !req) {
+		SDEROT_ERR("invalid params\n");
+		return;
+	}
+
+	for (i = 0; i < req->count; i++) {
+		queue = req->entries[i].commitq;
+		if (!queue || !queue->hw)
+			continue;
+		hw = queue->hw;
+		while (atomic_read(&hw->num_active) > 1) {
+			sde_rot_mgr_unlock(mgr);
+			ret = wait_event_timeout(hw->wait_queue,
+				atomic_read(&hw->num_active) <= 1,
+				msecs_to_jiffies(mgr->hwacquire_timeout));
+			sde_rot_mgr_lock(mgr);
+			if (!ret) {
+				SDEROT_ERR(
+					"timeout waiting for hw idle, a:%d\n",
+					atomic_read(&hw->num_active));
+				return;
+			}
+		}
+	}
+}
+
+/*
  * sde_rotator_get_hw_resource - block waiting for hw availability or timeout
  * @queue: Pointer to rotator queue
  * @entry: Pointer to rotation entry
@@ -1220,6 +1258,11 @@
 		return;
 	}
 
+	if (!req->entries) {
+		SDEROT_DBG("no entries in request\n");
+		return;
+	}
+
 	for (i = 0; i < req->count; i++) {
 		entry = req->entries + i;
 		queue = entry->commitq;
@@ -1542,10 +1585,23 @@
 		goto error;
 	}
 
+	if (entry->item.ts)
+		entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get();
+
+	ret = sde_rotator_req_wait_start(mgr, request);
+	if (ret) {
+		SDEROT_WARN("timeout waiting for inline start\n");
+		SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
+				SDE_ROT_EVTLOG_ERROR);
+		goto kickoff_error;
+	}
+
 	ret = mgr->ops_kickoff_entry(hw, entry);
 	if (ret) {
 		SDEROT_ERR("fail to do kickoff %d\n", ret);
-		goto error;
+		SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
+				SDE_ROT_EVTLOG_ERROR);
+		goto kickoff_error;
 	}
 
 	if (entry->item.ts)
@@ -1556,6 +1612,13 @@
 	kthread_queue_work(&entry->doneq->rot_kw, &entry->done_work);
 	sde_rot_mgr_unlock(mgr);
 	return;
+kickoff_error:
+	/*
+	 * Wait for any pending operations to complete before cancelling this
+	 * one so that the system is left in a consistent state.
+	 */
+	sde_rotator_req_wait_for_idle(mgr, request);
+	mgr->ops_cancel_hw(hw, entry);
 error:
 	sde_smmu_ctrl(0);
 smmu_error:
@@ -1609,18 +1672,6 @@
 		entry->item.flags,
 		entry->dnsc_factor_w, entry->dnsc_factor_h);
 
-	ret = wait_for_completion_timeout(
-			&entry->item.inline_start,
-			msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS));
-	if (!ret) {
-		SDEROT_WARN("timeout waiting for inline start\n");
-		SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id,
-				SDE_ROT_EVTLOG_ERROR);
-	}
-
-	if (entry->item.ts)
-		entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get();
-
 	SDEROT_EVTLOG(entry->item.session_id, 0);
 	ret = mgr->ops_wait_for_entry(hw, entry);
 	if (ret) {
@@ -2164,34 +2215,6 @@
 	return ret;
 }
 
-/*
- * sde_rotator_commit_request - commit the request to hardware
- * @mgr: pointer to rotator manager
- * @private: pointer to per file context
- * @req: pointer to rotation request
- *
- * This differs from sde_rotator_queue_request in that this
- * function will wait until request is committed to hardware.
- */
-void sde_rotator_commit_request(struct sde_rot_mgr *mgr,
-	struct sde_rot_file_private *ctx,
-	struct sde_rot_entry_container *req)
-{
-	int i;
-
-	if (!mgr || !ctx || !req || !req->entries) {
-		SDEROT_ERR("null parameters\n");
-		return;
-	}
-
-	sde_rotator_queue_request(mgr, ctx, req);
-
-	sde_rot_mgr_unlock(mgr);
-	for (i = 0; i < req->count; i++)
-		kthread_flush_work(&req->entries[i].commit_work);
-	sde_rot_mgr_lock(mgr);
-}
-
 static int sde_rotator_open_session(struct sde_rot_mgr *mgr,
 	struct sde_rot_file_private *private, u32 session_id)
 {
@@ -2408,26 +2431,67 @@
 	return req;
 }
 
-void sde_rotator_req_reset_start(struct sde_rot_entry_container *req)
+void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr,
+		struct sde_rot_entry_container *req)
 {
 	int i;
 
-	if (!req)
+	if (!mgr || !req)
 		return;
 
 	for (i = 0; i < req->count; i++)
 		reinit_completion(&req->entries[i].item.inline_start);
 }
 
-void sde_rotator_req_set_start(struct sde_rot_entry_container *req)
+void sde_rotator_req_set_start(struct sde_rot_mgr *mgr,
+		struct sde_rot_entry_container *req)
 {
+	struct kthread_work *commit_work;
 	int i;
 
-	if (!req)
+	if (!mgr || !req || !req->entries)
 		return;
 
+	/* signal ready to start */
 	for (i = 0; i < req->count; i++)
 		complete_all(&req->entries[i].item.inline_start);
+
+	for (i = 0; i < req->count; i++) {
+		commit_work = &req->entries[i].commit_work;
+
+		SDEROT_EVTLOG(i, req->count);
+
+		sde_rot_mgr_unlock(mgr);
+		kthread_flush_work(commit_work);
+		sde_rot_mgr_lock(mgr);
+	}
+}
+
+int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr,
+		struct sde_rot_entry_container *req)
+{
+	struct completion *inline_start;
+	int i, ret;
+
+	if (!mgr || !req || !req->entries)
+		return -EINVAL;
+
+	/* only wait for sbuf mode */
+	if (!mgr->sbuf_ctx || !req->count ||
+			mgr->sbuf_ctx != req->entries[0].private)
+		return 0;
+
+	for (i = 0; i < req->count; i++) {
+		inline_start = &req->entries[i].item.inline_start;
+
+		sde_rot_mgr_unlock(mgr);
+		ret = wait_for_completion_timeout(inline_start,
+			msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS));
+		sde_rot_mgr_lock(mgr);
+	}
+
+	/* wait call returns zero on timeout */
+	return ret ? 0 : -EBUSY;
 }
 
 void sde_rotator_req_finish(struct sde_rot_mgr *mgr,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 3d368a1..eb8cb88 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -115,8 +115,8 @@
 	SDE_ROTATOR_TS_FENCE,		/* wait for source buffer fence */
 	SDE_ROTATOR_TS_QUEUE,		/* wait for h/w resource */
 	SDE_ROTATOR_TS_COMMIT,		/* prepare h/w command */
+	SDE_ROTATOR_TS_START,		/* wait for h/w kickoff rdy (inline) */
 	SDE_ROTATOR_TS_FLUSH,		/* initiate h/w processing */
-	SDE_ROTATOR_TS_START,		/* h/w triggered (if inline) */
 	SDE_ROTATOR_TS_DONE,		/* receive h/w completion */
 	SDE_ROTATOR_TS_RETIRE,		/* signal destination buffer fence */
 	SDE_ROTATOR_TS_SRCDQB,		/* dequeue source buffer */
@@ -448,6 +448,8 @@
 
 	int (*ops_config_hw)(struct sde_rot_hw_resource *hw,
 			struct sde_rot_entry *entry);
+	int (*ops_cancel_hw)(struct sde_rot_hw_resource *hw,
+			struct sde_rot_entry *entry);
 	int (*ops_kickoff_entry)(struct sde_rot_hw_resource *hw,
 			struct sde_rot_entry *entry);
 	int (*ops_wait_for_entry)(struct sde_rot_hw_resource *hw,
@@ -622,20 +624,33 @@
  *	indicator that allows the rotator to delay its rotator
  *	timeout waiting until such time as the inline rotation has
  *	really started.
+ * @mgr: Pointer to rotator manager
  * @req: Pointer to rotation request
  */
-void sde_rotator_req_reset_start(struct sde_rot_entry_container *req);
+void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr,
+		struct sde_rot_entry_container *req);
 
 /*
  * sde_rotator_req_set_start - set inline h/w 'start' indicator
+ * @mgr: Pointer to rotator manager
  * @req: Pointer to rotation request
  */
-void sde_rotator_req_set_start(struct sde_rot_entry_container *req);
+void sde_rotator_req_set_start(struct sde_rot_mgr *mgr,
+		struct sde_rot_entry_container *req);
+
+/*
+ * sde_rotator_req_wait_start - wait for inline h/w 'start' indicator
+ * @mgr: Pointer to rotator manager
+ * @req: Pointer to rotation request
+ * return: Zero on success
+ */
+int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr,
+		struct sde_rot_entry_container *req);
 
 /*
  * sde_rotator_req_finish - notify manager that client is finished with the
  *	given request and manager can release the request as required
- * @rot_dev: Pointer to rotator device
+ * @mgr: Pointer to rotator manager
  * @private: Pointer to rotator manager per file context
  * @req: Pointer to rotation request
  * return: none
@@ -668,18 +683,6 @@
 	struct sde_rot_entry_container *req);
 
 /*
- * sde_rotator_commit_request - queue/schedule the given request and wait
- *	until h/w commit
- * @rot_dev: Pointer to rotator device
- * @private: Pointer to rotator manager per file context
- * @req: Pointer to rotation request
- * return: 0 if success; error code otherwise
- */
-void sde_rotator_commit_request(struct sde_rot_mgr *mgr,
-	struct sde_rot_file_private *ctx,
-	struct sde_rot_entry_container *req);
-
-/*
  * sde_rotator_verify_config_all - verify given rotation configuration
  * @rot_dev: Pointer to rotator device
  * @config: Pointer to rotator configuration
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index 2a9573d..46f64d2 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -793,7 +793,7 @@
 					start_time));
 
 		seq_printf(s,
-			"s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld fl:%lld st:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n",
+			"s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld st:%lld fl:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n",
 			i,
 			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FENCE],
 					ts[SDE_ROTATOR_TS_SRCQB])),
@@ -803,12 +803,12 @@
 					ts[SDE_ROTATOR_TS_FENCE])),
 			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_COMMIT],
 					ts[SDE_ROTATOR_TS_QUEUE])),
-			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
-					ts[SDE_ROTATOR_TS_COMMIT])),
 			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_START],
-					ts[SDE_ROTATOR_TS_FLUSH])),
-			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DONE],
+					ts[SDE_ROTATOR_TS_COMMIT])),
+			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH],
 					ts[SDE_ROTATOR_TS_START])),
+			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DONE],
+					ts[SDE_ROTATOR_TS_FLUSH])),
 			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_RETIRE],
 					ts[SDE_ROTATOR_TS_DONE])),
 			ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_SRCDQB],
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index acd4b7d..4ad960d8 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -1686,9 +1686,9 @@
 			goto error_handle_request;
 		}
 
-		sde_rotator_req_reset_start(req);
+		sde_rotator_req_reset_start(rot_dev->mgr, req);
 
-		sde_rotator_commit_request(rot_dev->mgr, ctx->private, req);
+		sde_rotator_queue_request(rot_dev->mgr, ctx->private, req);
 
 		request->committed = true;
 
@@ -1703,7 +1703,7 @@
 		}
 
 		request = cmd->priv_handle;
-		sde_rotator_req_set_start(request->req);
+		sde_rotator_req_set_start(rot_dev->mgr, request->req);
 	} else if (cmd_type == SDE_ROTATOR_INLINE_CMD_CLEANUP) {
 		if (!cmd->priv_handle) {
 			ret = -EINVAL;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
index 1b4913b..89ad438 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
@@ -343,6 +343,12 @@
 	return ret;
 }
 
+static int sde_rotator_cancel_hw(struct sde_rot_hw_resource *hw,
+	struct sde_rot_entry *entry)
+{
+	return 0;
+}
+
 static int sde_rotator_kickoff_entry(struct sde_rot_hw_resource *hw,
 	struct sde_rot_entry *entry)
 {
@@ -684,6 +690,7 @@
 
 	mgr->hw_data = hw_data;
 	mgr->ops_config_hw = sde_rotator_config_hw;
+	mgr->ops_cancel_hw = sde_rotator_cancel_hw;
 	mgr->ops_kickoff_entry = sde_rotator_kickoff_entry;
 	mgr->ops_wait_for_entry = sde_rotator_wait_for_entry;
 	mgr->ops_hw_alloc = sde_rotator_hw_alloc_ext;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 3c47dd7..2f2a439 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -2522,6 +2522,55 @@
 }
 
 /*
+ * sde_hw_rotator_cancel - cancel hw configuration for the given rotation entry
+ * @hw: Pointer to rotator resource
+ * @entry: Pointer to rotation entry
+ *
+ * This function cancels a previously configured rotation entry.
+ */
+static int sde_hw_rotator_cancel(struct sde_rot_hw_resource *hw,
+		struct sde_rot_entry *entry)
+{
+	struct sde_hw_rotator *rot;
+	struct sde_hw_rotator_resource_info *resinfo;
+	struct sde_hw_rotator_context *ctx;
+	unsigned long flags;
+
+	if (!hw || !entry) {
+		SDEROT_ERR("null hw resource/entry\n");
+		return -EINVAL;
+	}
+
+	resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw);
+	rot = resinfo->rot;
+
+	/* Lookup rotator context from session-id */
+	ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id,
+			entry->item.sequence_id, hw->wb_id);
+	if (!ctx) {
+		SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n",
+				entry->item.session_id);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&rot->rotisr_lock, flags);
+	sde_hw_rotator_update_swts(rot, ctx, ctx->timestamp);
+	spin_unlock_irqrestore(&rot->rotisr_lock, flags);
+
+	SDEROT_EVTLOG(entry->item.session_id, ctx->timestamp);
+
+	if (rot->dbgmem) {
+		sde_hw_rotator_unmap_vaddr(&ctx->src_dbgbuf);
+		sde_hw_rotator_unmap_vaddr(&ctx->dst_dbgbuf);
+	}
+
+	/* Current rotator context job is finished, time to free up */
+	sde_hw_rotator_free_rotctx(rot, ctx);
+
+	return 0;
+}
+
+/*
  * sde_hw_rotator_kickoff - kickoff processing on the given entry
  * @hw: Pointer to rotator resource
  * @entry: Pointer to rotation entry
@@ -3331,6 +3380,7 @@
 	mgr->ops_hw_alloc = sde_hw_rotator_alloc_ext;
 	mgr->ops_hw_free = sde_hw_rotator_free_ext;
 	mgr->ops_config_hw = sde_hw_rotator_config;
+	mgr->ops_cancel_hw = sde_hw_rotator_cancel;
 	mgr->ops_kickoff_entry = sde_hw_rotator_kickoff;
 	mgr->ops_wait_for_entry = sde_hw_rotator_wait4done;
 	mgr->ops_hw_validate_entry = sde_hw_rotator_validate_entry;
@@ -3349,8 +3399,11 @@
 		goto error_parse_dt;
 
 	rot->irq_num = platform_get_irq(mgr->pdev, 0);
-	if (rot->irq_num < 0) {
-		SDEROT_ERR("fail to get rotator irq\n");
+	if (rot->irq_num == -EPROBE_DEFER) {
+		SDEROT_INFO("irq master master not ready, defer probe\n");
+		return -EPROBE_DEFER;
+	} else if (rot->irq_num < 0) {
+		SDEROT_ERR("fail to get rotator irq, fallback to polling\n");
 	} else {
 		if (rot->mode == ROT_REGDMA_OFF)
 			ret = devm_request_threaded_irq(&mgr->pdev->dev,
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index b6c0d57..85db6f0 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1605,6 +1605,9 @@
 				HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION;
 		hfi = (struct hfi_vpe_color_space_conversion *)
 			&pkt->rg_property_data[1];
+
+		hfi->input_color_primaries = hal->input_color_primaries;
+		hfi->custom_matrix_enabled = hal->custom_matrix_enabled;
 		memcpy(hfi->csc_matrix, hal->csc_matrix,
 				sizeof(hfi->csc_matrix));
 		memcpy(hfi->csc_bias, hal->csc_bias, sizeof(hfi->csc_bias));
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 0eb6d39..dfb2ad5 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -42,25 +42,6 @@
 #define MIN_NUM_ENC_OUTPUT_BUFFERS 4
 #define MIN_NUM_ENC_CAPTURE_BUFFERS 5
 
-/*
- * Default 601 to 709 conversion coefficients for resolution: 176x144 negative
- * coeffs are converted to s4.9 format (e.g. -22 converted to ((1 << 13) - 22)
- * 3x3 transformation matrix coefficients in s4.9 fixed point format
- */
-static u32 vpe_csc_601_to_709_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = {
-	470, 8170, 8148, 0, 490, 50, 0, 34, 483
-};
-
-/* offset coefficients in s9 fixed point format */
-static u32 vpe_csc_601_to_709_bias_coeff[HAL_MAX_BIAS_COEFFS] = {
-	34, 0, 4
-};
-
-/* clamping value for Y/U/V([min,max] for Y/U/V) */
-static u32 vpe_csc_601_to_709_limit_coeff[HAL_MAX_LIMIT_COEFFS] = {
-	16, 235, 16, 240, 16, 240
-};
-
 static const char *const mpeg_video_rate_control[] = {
 	"No Rate Control",
 	"VBR VFR",
@@ -1046,6 +1027,15 @@
 		.default_value = 0,
 		.step = 1,
 	},
+	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX,
+		.name = "Enable/Disable CSC Custom Matrix",
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 0,
+		.step = 1,
+	},
 
 };
 
@@ -1124,7 +1114,8 @@
 	},
 };
 
-static int msm_venc_set_csc(struct msm_vidc_inst *inst);
+static int msm_venc_set_csc(struct msm_vidc_inst *inst,
+					u32 color_primaries, u32 custom_matrix);
 
 static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers)
 {
@@ -1198,6 +1189,7 @@
 	struct hal_video_signal_info signal_info = {0};
 	struct hal_vui_timing_info vui_timing_info = {0};
 	enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT;
+	u32 color_primaries, custom_matrix;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
@@ -1898,11 +1890,23 @@
 		break;
 	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC:
-		if (ctrl->val == V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE) {
-			rc = msm_venc_set_csc(inst);
-			if (rc)
-				dprintk(VIDC_ERR, "fail to set csc: %d\n", rc);
-		}
+		if (ctrl->val != V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_ENABLE)
+			break;
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+		color_primaries = temp_ctrl->val;
+		temp_ctrl =
+		   TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX);
+		custom_matrix = temp_ctrl->val;
+		rc = msm_venc_set_csc(inst, color_primaries, custom_matrix);
+		if (rc)
+			dprintk(VIDC_ERR, "fail to set csc: %d\n", rc);
+		break;
+	case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX:
+		temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE);
+		color_primaries = temp_ctrl->val;
+		rc = msm_venc_set_csc(inst, color_primaries, ctrl->val);
+		if (rc)
+			dprintk(VIDC_ERR, "fail to set csc: %d\n", rc);
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE:
 	{
@@ -2291,22 +2295,42 @@
 	return rc;
 }
 
-static int msm_venc_set_csc(struct msm_vidc_inst *inst)
+static int msm_venc_set_csc(struct msm_vidc_inst *inst,
+					u32 color_primaries, u32 custom_matrix)
 {
 	int rc = 0;
 	int count = 0;
 	struct hal_vpe_color_space_conversion vpe_csc;
+	struct msm_vidc_platform_resources *resources;
+	u32 *bias_coeff = NULL;
+	u32 *csc_limit = NULL;
+	u32 *csc_matrix = NULL;
 
-	while (count < HAL_MAX_MATRIX_COEFFS) {
-		if (count < HAL_MAX_BIAS_COEFFS)
-			vpe_csc.csc_bias[count] =
-				vpe_csc_601_to_709_bias_coeff[count];
-		if (count < HAL_MAX_LIMIT_COEFFS)
-			vpe_csc.csc_limit[count] =
-				vpe_csc_601_to_709_limit_coeff[count];
-		vpe_csc.csc_matrix[count] =
-			vpe_csc_601_to_709_matrix_coeff[count];
-		count = count + 1;
+	resources = &(inst->core->resources);
+	bias_coeff =
+		resources->csc_coeff_data->vpe_csc_custom_bias_coeff;
+	csc_limit =
+		resources->csc_coeff_data->vpe_csc_custom_limit_coeff;
+	csc_matrix =
+		resources->csc_coeff_data->vpe_csc_custom_matrix_coeff;
+
+	vpe_csc.input_color_primaries = color_primaries;
+	/* Custom bias, matrix & limit */
+	vpe_csc.custom_matrix_enabled = custom_matrix;
+
+	if (vpe_csc.custom_matrix_enabled && bias_coeff != NULL
+			&& csc_limit != NULL && csc_matrix != NULL) {
+		while (count < HAL_MAX_MATRIX_COEFFS) {
+			if (count < HAL_MAX_BIAS_COEFFS)
+				vpe_csc.csc_bias[count] =
+					bias_coeff[count];
+			if (count < HAL_MAX_LIMIT_COEFFS)
+				vpe_csc.csc_limit[count] =
+					csc_limit[count];
+			vpe_csc.csc_matrix[count] =
+				csc_matrix[count];
+			count = count + 1;
+		}
 	}
 	rc = msm_comm_try_set_prop(inst,
 			HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, &vpe_csc);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 5f372c7..920e91a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1026,6 +1026,14 @@
 		goto stream_start_failed;
 	}
 
+	rc = msm_vidc_send_pending_eos_buffers(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"Failed : Send pending EOS buffs for Inst = %pK, %d\n",
+				inst, rc);
+		goto stream_start_failed;
+	}
+
 stream_start_failed:
 	if (rc) {
 		struct msm_vidc_buffer *temp, *next;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 6e8e1ed..8fd1dd1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2935,6 +2935,8 @@
 	}
 	core->state = VIDC_CORE_INIT;
 	core->smmu_fault_handled = false;
+	core->trigger_ssr = false;
+
 core_already_inited:
 	change_inst_state(inst, MSM_VIDC_CORE_INIT);
 	mutex_unlock(&core->lock);
@@ -3763,6 +3765,42 @@
 	return rc;
 }
 
+int msm_vidc_send_pending_eos_buffers(struct msm_vidc_inst *inst)
+{
+	struct vidc_frame_data data = {0};
+	struct hfi_device *hdev;
+	struct eos_buf *binfo = NULL, *temp = NULL;
+	int rc = 0;
+
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&inst->eosbufs.lock);
+	list_for_each_entry_safe(binfo, temp, &inst->eosbufs.list, list) {
+		data.alloc_len = binfo->smem.size;
+		data.device_addr = binfo->smem.device_addr;
+		data.clnt_data = data.device_addr;
+		data.buffer_type = HAL_BUFFER_INPUT;
+		data.filled_len = 0;
+		data.offset = 0;
+		data.flags = HAL_BUFFERFLAG_EOS;
+		data.timestamp = LLONG_MAX;
+		data.extradata_addr = data.device_addr;
+		data.extradata_size = 0;
+		dprintk(VIDC_DBG, "Queueing EOS buffer %pK\n",
+				(void *)(u64)data.device_addr);
+		hdev = inst->core->device;
+
+		rc = call_hfi_op(hdev, session_etb, inst->session,
+				&data);
+	}
+	mutex_unlock(&inst->eosbufs.lock);
+
+	return rc;
+}
+
 int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd)
 {
 	struct msm_vidc_inst *inst = instance;
@@ -3835,9 +3873,7 @@
 	}
 	case V4L2_DEC_CMD_STOP:
 	{
-		struct vidc_frame_data data = {0};
-		struct hfi_device *hdev;
-		struct eos_buf *binfo;
+		struct eos_buf *binfo = NULL;
 		u32 smem_flags = 0;
 
 		get_inst(inst->core, inst);
@@ -3864,6 +3900,7 @@
 		if (rc) {
 			dprintk(VIDC_ERR,
 				"Failed to allocate output memory\n");
+			rc = -ENOMEM;
 			goto exit;
 		}
 
@@ -3871,22 +3908,14 @@
 		list_add_tail(&binfo->list, &inst->eosbufs.list);
 		mutex_unlock(&inst->eosbufs.lock);
 
-		data.alloc_len = binfo->smem.size;
-		data.device_addr = binfo->smem.device_addr;
-		data.clnt_data = data.device_addr;
-		data.buffer_type = HAL_BUFFER_INPUT;
-		data.filled_len = 0;
-		data.offset = 0;
-		data.flags = HAL_BUFFERFLAG_EOS;
-		data.timestamp = LLONG_MAX;
-		data.extradata_addr = data.device_addr;
-		data.extradata_size = 0;
-		dprintk(VIDC_DBG, "Queueing EOS buffer %pK\n",
-			(void *)(u64)data.device_addr);
-		hdev = inst->core->device;
+		if (inst->state != MSM_VIDC_START_DONE) {
+			dprintk(VIDC_DBG,
+				"Inst = %pK is not ready for EOS\n", inst);
+			goto exit;
+		}
 
-		rc = call_hfi_op(hdev, session_etb, inst->session,
-				&data);
+		rc = msm_vidc_send_pending_eos_buffers(inst);
+
 exit:
 		put_inst(inst);
 		break;
@@ -5247,11 +5276,14 @@
 		 * to know if fatal error is due to SSR or not. Handle
 		 * user SSR as non-fatal.
 		 */
-		mutex_lock(&core->lock);
-		core->resources.debug_timeout = false;
-		mutex_unlock(&core->lock);
+		core->trigger_ssr = true;
 		rc = call_hfi_op(hdev, core_trigger_ssr,
 				hdev->hfi_device_data, type);
+		if (rc) {
+			dprintk(VIDC_ERR, "%s: trigger_ssr failed\n",
+				__func__);
+			core->trigger_ssr = false;
+		}
 	}
 
 	return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index a272a10..05e2b91 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -107,6 +107,7 @@
 int msm_comm_get_v4l2_profile(int fourcc, int profile);
 int msm_comm_get_v4l2_level(int fourcc, int level);
 int msm_comm_session_continue(void *instance);
+int msm_vidc_send_pending_eos_buffers(struct msm_vidc_inst *inst);
 enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc);
 u32 get_frame_size_nv12(int plane, u32 height, u32 width);
 u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 5be1ee2..98120ac 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -29,7 +29,6 @@
 bool msm_vidc_sys_idle_indicator = !true;
 bool msm_vidc_thermal_mitigation_disabled = !true;
 bool msm_vidc_clock_scaling = true;
-bool msm_vidc_debug_timeout = !true;
 bool msm_vidc_syscache_disable = !true;
 
 #define MAX_DBG_BUF_SIZE 4096
@@ -208,8 +207,6 @@
 			&msm_vidc_thermal_mitigation_disabled) &&
 	__debugfs_create(bool, "clock_scaling",
 			&msm_vidc_clock_scaling) &&
-	__debugfs_create(bool, "debug_timeout",
-			&msm_vidc_debug_timeout) &&
 	__debugfs_create(bool, "disable_video_syscache",
 			&msm_vidc_syscache_disable);
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 9a798b5..7a73a50 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -61,7 +61,6 @@
 extern bool msm_vidc_sys_idle_indicator;
 extern bool msm_vidc_thermal_mitigation_disabled;
 extern bool msm_vidc_clock_scaling;
-extern bool msm_vidc_debug_timeout;
 extern bool msm_vidc_syscache_disable;
 
 #define VIDC_MSG_PRIO2STRING(__level) ({ \
@@ -184,7 +183,18 @@
 {
 	bool enable_fatal;
 
-	enable_fatal = msm_vidc_debug_timeout;
+	enable_fatal = core->resources.debug_timeout;
+
+	/*
+	 * In current implementation user-initiated SSR triggers
+	 * a fatal error from hardware. However, there is no way
+	 * to know if fatal error is due to SSR or not. Handle
+	 * user SSR as non-fatal.
+	 */
+	if (core->trigger_ssr) {
+		core->trigger_ssr = false;
+		enable_fatal = false;
+	}
 
 	/* Video driver can decide FATAL handling of HW errors
 	 * based on multiple factors. This condition check will
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 1ad28ba..ba05059 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -169,6 +169,12 @@
 	enum buffer_owner buffer_ownership;
 };
 
+struct msm_vidc_csc_coeff {
+	u32 *vpe_csc_custom_matrix_coeff;
+	u32 *vpe_csc_custom_bias_coeff;
+	u32 *vpe_csc_custom_limit_coeff;
+};
+
 struct msm_vidc_common_data {
 	char key[128];
 	int value;
@@ -187,6 +193,7 @@
 	unsigned int common_data_length;
 	struct msm_vidc_codec_data *codec_data;
 	unsigned int codec_data_length;
+	struct msm_vidc_csc_coeff csc_data;
 };
 
 struct msm_vidc_format {
@@ -317,6 +324,7 @@
 	struct msm_vidc_capability *capabilities;
 	struct delayed_work fw_unload_work;
 	bool smmu_fault_handled;
+	bool trigger_ssr;
 	unsigned long min_freq;
 	unsigned long curr_freq;
 	struct vidc_bus_vote_data *vote_data;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index 7ca6ab0..0fe09e2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -52,6 +52,26 @@
 	CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200),
 };
 
+/*
+ * Custom conversion coefficients for resolution: 176x144 negative
+ * coeffs are converted to s4.9 format
+ * (e.g. -22 converted to ((1 << 13) - 22)
+ * 3x3 transformation matrix coefficients in s4.9 fixed point format
+ */
+static u32 vpe_csc_custom_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = {
+	470, 8170, 8148, 0, 490, 50, 0, 34, 483
+};
+
+/* offset coefficients in s9 fixed point format */
+static u32 vpe_csc_custom_bias_coeff[HAL_MAX_BIAS_COEFFS] = {
+	34, 0, 4
+};
+
+/* clamping value for Y/U/V([min,max] for Y/U/V) */
+static u32 vpe_csc_custom_limit_coeff[HAL_MAX_LIMIT_COEFFS] = {
+	16, 235, 16, 240, 16, 240
+};
+
 static struct msm_vidc_common_data default_common_data[] = {
 	{
 		.key = "qcom,never-unload-fw",
@@ -104,6 +124,10 @@
 		.key = "qcom,hw-resp-timeout",
 		.value = 250,
 	},
+	{
+		.key = "qcom,debug-timeout",
+		.value = 0,
+	},
 };
 
 
@@ -112,6 +136,9 @@
 	.codec_data_length =  ARRAY_SIZE(default_codec_data),
 	.common_data = default_common_data,
 	.common_data_length =  ARRAY_SIZE(default_common_data),
+	.csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
+	.csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
+	.csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
 };
 
 static struct msm_vidc_platform_data sdm845_data = {
@@ -119,6 +146,9 @@
 	.codec_data_length =  ARRAY_SIZE(sdm845_codec_data),
 	.common_data = sdm845_common_data,
 	.common_data_length =  ARRAY_SIZE(sdm845_common_data),
+	.csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
+	.csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
+	.csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
 };
 
 static const struct of_device_id msm_vidc_dt_match[] = {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 46fb75f..f343939 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -765,8 +765,6 @@
 	res->debug_timeout = find_key_value(platform_data,
 			"qcom,debug-timeout");
 
-	res->debug_timeout |= msm_vidc_debug_timeout;
-
 	res->pm_qos_latency_us = find_key_value(platform_data,
 			"qcom,pm-qos-latency-us");
 
@@ -788,6 +786,8 @@
 	res->non_fatal_pagefaults = find_key_value(platform_data,
 			"qcom,domain-attr-non-fatal-faults");
 
+	res->csc_coeff_data = &platform_data->csc_data;
+
 	return rc;
 
 }
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 31d5a42..8309fce 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -192,6 +192,7 @@
 	bool non_fatal_pagefaults;
 	struct msm_vidc_codec_data *codec_data;
 	int codec_data_count;
+	struct msm_vidc_csc_coeff *csc_coeff_data;
 };
 
 static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 82c3ffc..47ff1db 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -4110,7 +4110,9 @@
 
 	dprintk(VIDC_PROF, "Resumed from power collapse\n");
 exit:
-	device->skip_pc_count = 0;
+	/* Don't reset skip_pc_count for SYS_PC_PREP cmd */
+	if (device->last_packet_type != HFI_CMD_SYS_PC_PREP)
+		device->skip_pc_count = 0;
 	return rc;
 err_reset_core:
 	__tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 8e9e51f..e899af3 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -226,8 +226,6 @@
 	(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
 #define HFI_PROPERTY_PARAM_VPE_OX_START					\
 	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
-#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION			\
-	(HFI_PROPERTY_PARAM_VPE_OX_START + 0x001)
 
 #define HFI_PROPERTY_CONFIG_VPE_OX_START				\
 	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index a4b7276..13ea3f4 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -876,6 +876,8 @@
 };
 
 struct hal_vpe_color_space_conversion {
+	u32 input_color_primaries;
+	u32 custom_matrix_enabled;
 	u32 csc_matrix[HAL_MAX_MATRIX_COEFFS];
 	u32 csc_bias[HAL_MAX_BIAS_COEFFS];
 	u32 csc_limit[HAL_MAX_LIMIT_COEFFS];
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index fec1517..001ca39 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -355,6 +355,8 @@
 	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000)
 #define HFI_PROPERTY_PARAM_VPE_ROTATION				\
 	(HFI_PROPERTY_PARAM_VPE_COMMON_START + 0x001)
+#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION		\
+	(HFI_PROPERTY_PARAM_VPE_COMMON_START + 0x002)
 
 #define HFI_PROPERTY_CONFIG_VPE_COMMON_START				\
 	(HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000)
@@ -712,6 +714,8 @@
 };
 
 struct hfi_vpe_color_space_conversion {
+	u32 input_color_primaries;
+	u32 custom_matrix_enabled;
 	u32 csc_matrix[HFI_MAX_MATRIX_COEFFS];
 	u32 csc_bias[HFI_MAX_BIAS_COEFFS];
 	u32 csc_limit[HFI_MAX_LIMIT_COEFFS];
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index a12d5ca..176d3dc 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -592,6 +592,7 @@
 {
 	device_init_wakeup(wcd9xxx->dev, false);
 	wcd9xxx_irq_exit(&wcd9xxx->core_res);
+	mfd_remove_devices(wcd9xxx->dev);
 	wcd9xxx_bringdown(wcd9xxx->dev);
 	wcd9xxx_reset_low(wcd9xxx->dev);
 	wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 092f446..cb98083 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -52,6 +52,8 @@
 	struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
 static unsigned int wcd9xxx_irq_get_upstream_irq(
 	struct wcd9xxx_core_resource *wcd9xxx_res);
+static void wcd9xxx_irq_put_downstream_irq(
+	struct wcd9xxx_core_resource *wcd9xxx_res);
 static void wcd9xxx_irq_put_upstream_irq(
 	struct wcd9xxx_core_resource *wcd9xxx_res);
 static int wcd9xxx_map_irq(
@@ -632,6 +634,7 @@
 		disable_irq_wake(wcd9xxx_res->irq);
 		free_irq(wcd9xxx_res->irq, wcd9xxx_res);
 		wcd9xxx_res->irq = 0;
+		wcd9xxx_irq_put_downstream_irq(wcd9xxx_res);
 		wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
 	}
 	mutex_destroy(&wcd9xxx_res->irq_lock);
@@ -754,6 +757,29 @@
 	return data->irq;
 }
 
+static void wcd9xxx_irq_put_downstream_irq(
+			struct wcd9xxx_core_resource *wcd9xxx_res)
+{
+	int irq, virq, ret;
+
+	/*
+	 * IRQ migration hits error if the chip data and handles
+	 * are not made NULL. make associated data and handles
+	 * to NULL at irq_exit
+	 */
+	for (irq = 0; irq < wcd9xxx_res->num_irqs; irq++) {
+		virq = wcd9xxx_map_irq(wcd9xxx_res, irq);
+		pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
+		ret = irq_set_chip_data(virq, NULL);
+		if (ret) {
+			pr_err("%s: Failed to configure irq %d (%d)\n",
+				__func__, irq, ret);
+			return;
+		}
+		irq_set_chip_and_handler(virq, NULL, NULL);
+	}
+}
+
 static void wcd9xxx_irq_put_upstream_irq(
 			struct wcd9xxx_core_resource *wcd9xxx_res)
 {
@@ -821,7 +847,6 @@
 	wmb();
 	irq_domain_remove(data->domain);
 	kfree(data);
-	domain->host_data = NULL;
 
 	return 0;
 }
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index d092d34..e2e9603 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -122,5 +122,6 @@
 	 support.
 
 source "drivers/net/wireless/cnss_utils/Kconfig"
+source "drivers/net/wireless/cnss_genl/Kconfig"
 
 endif # WLAN
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 005523c..7a75193 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -29,3 +29,4 @@
 obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
 
 obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
+obj-$(CONFIG_CNSS_GENL) += cnss_genl/
diff --git a/drivers/net/wireless/cnss_genl/Kconfig b/drivers/net/wireless/cnss_genl/Kconfig
new file mode 100644
index 0000000..f1b8a58
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/Kconfig
@@ -0,0 +1,7 @@
+config CNSS_GENL
+	tristate "CNSS Generic Netlink Socket Driver"
+	---help---
+	  This module creates generic netlink family "CLD80211". This can be
+	  used by cld driver and userspace utilities to communicate over
+	  netlink sockets. This module creates different multicast groups to
+	  facilitate the same.
diff --git a/drivers/net/wireless/cnss_genl/Makefile b/drivers/net/wireless/cnss_genl/Makefile
new file mode 100644
index 0000000..9431c9e
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CNSS_GENL) := cnss_nl.o
diff --git a/drivers/net/wireless/cnss_genl/cnss_nl.c b/drivers/net/wireless/cnss_genl/cnss_nl.c
new file mode 100644
index 0000000..fafd9ce
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/cnss_nl.c
@@ -0,0 +1,204 @@
+/* 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 <net/genetlink.h>
+#include <net/cnss_nl.h>
+#include <linux/module.h>
+
+#define CLD80211_GENL_NAME "cld80211"
+
+#define CLD80211_MULTICAST_GROUP_SVC_MSGS       "svc_msgs"
+#define CLD80211_MULTICAST_GROUP_HOST_LOGS      "host_logs"
+#define CLD80211_MULTICAST_GROUP_FW_LOGS        "fw_logs"
+#define CLD80211_MULTICAST_GROUP_PER_PKT_STATS  "per_pkt_stats"
+#define CLD80211_MULTICAST_GROUP_DIAG_EVENTS    "diag_events"
+#define CLD80211_MULTICAST_GROUP_FATAL_EVENTS   "fatal_events"
+#define CLD80211_MULTICAST_GROUP_OEM_MSGS       "oem_msgs"
+
+static const struct genl_multicast_group nl_mcgrps[] = {
+	[CLD80211_MCGRP_SVC_MSGS] = { .name =
+			CLD80211_MULTICAST_GROUP_SVC_MSGS},
+	[CLD80211_MCGRP_HOST_LOGS] = { .name =
+			CLD80211_MULTICAST_GROUP_HOST_LOGS},
+	[CLD80211_MCGRP_FW_LOGS] = { .name =
+			CLD80211_MULTICAST_GROUP_FW_LOGS},
+	[CLD80211_MCGRP_PER_PKT_STATS] = { .name =
+			CLD80211_MULTICAST_GROUP_PER_PKT_STATS},
+	[CLD80211_MCGRP_DIAG_EVENTS] = { .name =
+			CLD80211_MULTICAST_GROUP_DIAG_EVENTS},
+	[CLD80211_MCGRP_FATAL_EVENTS] = { .name =
+			CLD80211_MULTICAST_GROUP_FATAL_EVENTS},
+	[CLD80211_MCGRP_OEM_MSGS] = { .name =
+			CLD80211_MULTICAST_GROUP_OEM_MSGS},
+};
+
+struct cld_ops {
+	cld80211_cb cb;
+	void *cb_ctx;
+};
+
+struct cld80211_nl_data {
+	struct cld_ops cld_ops[CLD80211_MAX_COMMANDS];
+};
+
+static struct cld80211_nl_data nl_data;
+
+static inline struct cld80211_nl_data *get_local_ctx(void)
+{
+	return &nl_data;
+}
+
+static struct genl_ops nl_ops[CLD80211_MAX_COMMANDS];
+
+/* policy for the attributes */
+static const struct nla_policy cld80211_policy[CLD80211_ATTR_MAX + 1] = {
+	[CLD80211_ATTR_VENDOR_DATA] = { .type = NLA_NESTED },
+	[CLD80211_ATTR_DATA] = { .type = NLA_BINARY,
+				 .len = CLD80211_MAX_NL_DATA },
+};
+
+static int cld80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
+			     struct genl_info *info)
+{
+	u8 cmd_id = ops->cmd;
+	struct cld80211_nl_data *nl = get_local_ctx();
+
+	if (cmd_id < 1 || cmd_id > CLD80211_MAX_COMMANDS) {
+		pr_err("CLD80211: Command Not supported: %u\n", cmd_id);
+		return -EOPNOTSUPP;
+	}
+	info->user_ptr[0] = nl->cld_ops[cmd_id - 1].cb;
+	info->user_ptr[1] = nl->cld_ops[cmd_id - 1].cb_ctx;
+
+	return 0;
+}
+
+/* The netlink family */
+static struct genl_family cld80211_fam = {
+	.id = GENL_ID_GENERATE,
+	.name = CLD80211_GENL_NAME,
+	.hdrsize = 0,			/* no private header */
+	.version = 1,			/* no particular meaning now */
+	.maxattr = CLD80211_ATTR_MAX,
+	.netnsok = true,
+	.pre_doit = cld80211_pre_doit,
+	.post_doit = NULL,
+};
+
+int register_cld_cmd_cb(u8 cmd_id, cld80211_cb func, void *cb_ctx)
+{
+	struct cld80211_nl_data *nl = get_local_ctx();
+
+	pr_debug("CLD80211: Registering command: %d\n", cmd_id);
+	if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
+		pr_debug("CLD80211: invalid command: %d\n", cmd_id);
+		return -EINVAL;
+	}
+
+	nl->cld_ops[cmd_id - 1].cb = func;
+	nl->cld_ops[cmd_id - 1].cb_ctx = cb_ctx;
+
+	return 0;
+}
+EXPORT_SYMBOL(register_cld_cmd_cb);
+
+int deregister_cld_cmd_cb(u8 cmd_id)
+{
+	struct cld80211_nl_data *nl = get_local_ctx();
+
+	pr_debug("CLD80211: De-registering command: %d\n", cmd_id);
+	if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
+		pr_debug("CLD80211: invalid command: %d\n", cmd_id);
+		return -EINVAL;
+	}
+
+	nl->cld_ops[cmd_id - 1].cb = NULL;
+	nl->cld_ops[cmd_id - 1].cb_ctx = NULL;
+
+	return 0;
+}
+EXPORT_SYMBOL(deregister_cld_cmd_cb);
+
+struct genl_family *cld80211_get_genl_family(void)
+{
+	return &cld80211_fam;
+}
+EXPORT_SYMBOL(cld80211_get_genl_family);
+
+static int cld80211_doit(struct sk_buff *skb, struct genl_info *info)
+{
+	cld80211_cb cld_cb;
+	void *cld_ctx;
+
+	cld_cb = info->user_ptr[0];
+
+	if (!cld_cb) {
+		pr_err("CLD80211: Not supported\n");
+		return -EOPNOTSUPP;
+	}
+	cld_ctx = info->user_ptr[1];
+
+	if (info->attrs[CLD80211_ATTR_VENDOR_DATA]) {
+		cld_cb(nla_data(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
+		       nla_len(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
+		       cld_ctx, info->snd_portid);
+	} else {
+		pr_err("CLD80211: No CLD80211_ATTR_VENDOR_DATA\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int __cld80211_init(void)
+{
+	int err, i;
+
+	memset(&nl_ops[0], 0, sizeof(nl_ops));
+
+	pr_info("CLD80211: Initializing\n");
+	for (i = 0; i < CLD80211_MAX_COMMANDS; i++) {
+		nl_ops[i].cmd = i + 1;
+		nl_ops[i].doit = cld80211_doit;
+		nl_ops[i].flags = GENL_ADMIN_PERM;
+		nl_ops[i].policy = cld80211_policy;
+	}
+
+	err = genl_register_family_with_ops_groups(&cld80211_fam, nl_ops,
+						   nl_mcgrps);
+	if (err) {
+		pr_err("CLD80211: Failed to register cld80211 family: %d\n",
+		       err);
+	}
+
+	return err;
+}
+
+static void __cld80211_exit(void)
+{
+	genl_unregister_family(&cld80211_fam);
+}
+
+static int __init cld80211_init(void)
+{
+	return __cld80211_init();
+}
+
+static void __exit cld80211_exit(void)
+{
+	__cld80211_exit();
+}
+
+module_init(cld80211_init);
+module_exit(cld80211_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS generic netlink module");
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 4d4e993..d1766dd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -4298,12 +4298,12 @@
 	ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
 }
 
-static int ipa3_trigger_fw_loading_mdms(void)
+static int ipa3_manual_load_ipa_fws(void)
 {
 	int result;
 	const struct firmware *fw;
 
-	IPADBG("FW loading process initiated\n");
+	IPADBG("Manual FW loading process initiated\n");
 
 	result = request_firmware(&fw, IPA_FWS_PATH, ipa3_ctx->dev);
 	if (result < 0) {
@@ -4319,7 +4319,7 @@
 
 	result = ipa3_load_fws(fw, ipa3_res.transport_mem_base);
 	if (result) {
-		IPAERR("IPA FWs loading has failed\n");
+		IPAERR("Manual IPA FWs loading has failed\n");
 		release_firmware(fw);
 		return result;
 	}
@@ -4335,15 +4335,15 @@
 
 	release_firmware(fw);
 
-	IPADBG("FW loading process is complete\n");
+	IPADBG("Manual FW loading process is complete\n");
 	return 0;
 }
 
-static int ipa3_trigger_fw_loading_msms(void)
+static int ipa3_pil_load_ipa_fws(void)
 {
 	void *subsystem_get_retval = NULL;
 
-	IPADBG("FW loading process initiated\n");
+	IPADBG("PIL FW loading process initiated\n");
 
 	subsystem_get_retval = subsystem_get(IPA_SUBSYSTEM_NAME);
 	if (IS_ERR_OR_NULL(subsystem_get_retval)) {
@@ -4351,7 +4351,7 @@
 		return -EINVAL;
 	}
 
-	IPADBG("FW loading process is complete\n");
+	IPADBG("PIL FW loading process is complete\n");
 	return 0;
 }
 
@@ -4377,11 +4377,8 @@
 	if (ipa3_is_ready())
 		return count;
 
-	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-
-	if (ipa3_is_msm_device()) {
-		result = ipa3_trigger_fw_loading_msms();
-	} else {
+	/* Check MHI configuration on MDM devices */
+	if (!ipa3_is_msm_device()) {
 		if (!strcasecmp(dbg_buff, "MHI")) {
 			ipa3_ctx->ipa_config_is_mhi = true;
 			pr_info(
@@ -4390,19 +4387,26 @@
 			pr_info(
 			"IPA is loading with non MHI configuration\n");
 		}
-		result = ipa3_trigger_fw_loading_mdms();
 	}
-	/* No IPAv3.x chipsets that don't support FW loading */
+
+	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+	if (ipa3_is_msm_device() || (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))
+		result = ipa3_pil_load_ipa_fws();
+	else
+		result = ipa3_manual_load_ipa_fws();
 
 	IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
 
 	if (result) {
-		IPAERR("FW loading process has failed\n");
-			return result;
-	} else {
-			queue_work(ipa3_ctx->transport_power_mgmt_wq,
-				&ipa3_post_init_work);
+		IPAERR("IPA FW loading process has failed\n");
+		return result;
 	}
+
+	queue_work(ipa3_ctx->transport_power_mgmt_wq,
+		&ipa3_post_init_work);
+	pr_info("IPA FW loaded successfully\n");
+
 	return count;
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 9486b0a..153548b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -540,6 +540,12 @@
 	if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE)
 		pr_err("ether_type:%x ", attrib->ether_type);
 
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN)
+		pr_err("tcp syn ");
+
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP)
+		pr_err("tcp syn l2tp ");
+
 	pr_err("\n");
 	return 0;
 }
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
index b6427d0..f821dd2 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c
@@ -204,6 +204,7 @@
 	struct ipa_mem_buffer cmd;
 	struct Ipa3HwNtnSetUpCmdData_t *Ntn_params;
 	struct IpaHwOffloadSetUpCmdData_t *cmd_data;
+	struct IpaHwOffloadSetUpCmdData_t_v4_0 *cmd_data_v4_0;
 
 	if (ntn_info == NULL) {
 		IPAERR("invalid input\n");
@@ -225,8 +226,10 @@
 	IPADBG("num_buffers = %d\n", ntn_info->num_buffers);
 	IPADBG("data_buff_size = %d\n", ntn_info->data_buff_size);
 	IPADBG("tail_ptr_base_pa = 0x%pa\n", &ntn_info->ntn_reg_base_ptr_pa);
-
-	cmd.size = sizeof(*cmd_data);
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+		cmd.size = sizeof(*cmd_data_v4_0);
+	else
+		cmd.size = sizeof(*cmd_data);
 	cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
 			&cmd.phys_base, GFP_KERNEL);
 	if (cmd.base == NULL) {
@@ -234,10 +237,17 @@
 		return -ENOMEM;
 	}
 
-	cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
-	cmd_data->protocol = IPA_HW_FEATURE_NTN;
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		cmd_data_v4_0 = (struct IpaHwOffloadSetUpCmdData_t_v4_0 *)
+			cmd.base;
+		cmd_data_v4_0->protocol = IPA_HW_FEATURE_NTN;
+		Ntn_params = &cmd_data_v4_0->SetupCh_params.NtnSetupCh_params;
+	} else {
+		cmd_data = (struct IpaHwOffloadSetUpCmdData_t *)cmd.base;
+		cmd_data->protocol = IPA_HW_FEATURE_NTN;
+		Ntn_params = &cmd_data->SetupCh_params.NtnSetupCh_params;
+	}
 
-	Ntn_params = &cmd_data->SetupCh_params.NtnSetupCh_params;
 	Ntn_params->ring_base_pa = ntn_info->ring_base_pa;
 	Ntn_params->buff_pool_base_pa = ntn_info->buff_pool_base_pa;
 	Ntn_params->ntn_ring_size = ntn_info->ntn_ring_size;
@@ -372,6 +382,7 @@
 	struct ipa_mem_buffer cmd;
 	struct ipa3_ep_context *ep_ul, *ep_dl;
 	struct IpaHwOffloadCommonChCmdData_t *cmd_data;
+	struct IpaHwOffloadCommonChCmdData_t_v4_0 *cmd_data_v4_0;
 	union Ipa3HwNtnCommonChCmdData_t *tear;
 	int result = 0;
 
@@ -388,7 +399,10 @@
 		return -EFAULT;
 	}
 
-	cmd.size = sizeof(*cmd_data);
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+		cmd.size = sizeof(*cmd_data_v4_0);
+	else
+		cmd.size = sizeof(*cmd_data);
 	cmd.base = dma_alloc_coherent(ipa3_ctx->uc_pdev, cmd.size,
 		&cmd.phys_base, GFP_KERNEL);
 	if (cmd.base == NULL) {
@@ -397,9 +411,16 @@
 	}
 
 	IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-	cmd_data = (struct IpaHwOffloadCommonChCmdData_t *)cmd.base;
-	cmd_data->protocol = IPA_HW_FEATURE_NTN;
-	tear = &cmd_data->CommonCh_params.NtnCommonCh_params;
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		cmd_data_v4_0 = (struct IpaHwOffloadCommonChCmdData_t_v4_0 *)
+			cmd.base;
+		cmd_data_v4_0->protocol = IPA_HW_FEATURE_NTN;
+		tear = &cmd_data_v4_0->CommonCh_params.NtnCommonCh_params;
+	} else {
+		cmd_data = (struct IpaHwOffloadCommonChCmdData_t *)cmd.base;
+		cmd_data->protocol = IPA_HW_FEATURE_NTN;
+		tear = &cmd_data->CommonCh_params.NtnCommonCh_params;
+	}
 
 	/* teardown the DL pipe */
 	ipa3_disable_data_path(ipa_ep_idx_dl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
index 2e5a832..44afb28 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_offload_i.h
@@ -536,6 +536,16 @@
 } __packed;
 
 /**
+ * struct IpaHwOffloadSetUpCmdData_t_v4_0  -
+ *
+ *
+ */
+struct IpaHwOffloadSetUpCmdData_t_v4_0 {
+	u32 protocol;
+	union IpaHwSetUpCmd SetupCh_params;
+} __packed;
+
+/**
  * struct IpaHwCommonChCmd  - Structure holding the parameters
  * for IPA_CPU_2_HW_CMD_OFFLOAD_TEAR_DOWN
  *
@@ -550,4 +560,10 @@
 	union IpaHwCommonChCmd CommonCh_params;
 } __packed;
 
+struct IpaHwOffloadCommonChCmdData_t_v4_0 {
+	u32 protocol;
+	union IpaHwCommonChCmd CommonCh_params;
+} __packed;
+
+
 #endif /* _IPA_UC_OFFLOAD_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 8fe15bc..8c55a01 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -408,7 +408,7 @@
 enum ipa_ees {
 	IPA_EE_AP = 0,
 	IPA_EE_Q6 = 1,
-	IPA_EE_UC = 3,
+	IPA_EE_UC = 2,
 };
 
 struct ipa_ep_configuration {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
index 2253b4b..acc72f0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c
@@ -829,6 +829,21 @@
 		ihl_ofst_meq32 += 2;
 	}
 
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+			ihl_ofst_meq32)) {
+			IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+			goto err;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+		/* 12  => offset of SYN after v4 header */
+		extra = ipa_write_8(12, extra);
+		rest = ipa_write_32(0x20000, rest);
+		rest = ipa_write_32(0x20000, rest);
+		ihl_ofst_meq32++;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_META_DATA) {
 		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE);
 		rest = ipa_write_32(attrib->meta_data_mask, rest);
@@ -1167,6 +1182,57 @@
 		ihl_ofst_meq32 += 2;
 	}
 
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+			ihl_ofst_meq32)) {
+			IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+			goto err;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+		/* 12  => offset of SYN after v4 header */
+		extra = ipa_write_8(12, extra);
+		rest = ipa_write_32(0x20000, rest);
+		rest = ipa_write_32(0x20000, rest);
+		ihl_ofst_meq32++;
+	}
+
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+			ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+			ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+			IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+			goto err;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+
+		/* populate TCP protocol eq */
+		if (attrib->ether_type == 0x0800) {
+			extra = ipa_write_8(30, extra);
+			rest = ipa_write_32(0xFF0000, rest);
+			rest = ipa_write_32(0x60000, rest);
+		} else {
+			extra = ipa_write_8(26, extra);
+			rest = ipa_write_32(0xFF00, rest);
+			rest = ipa_write_32(0x600, rest);
+		}
+
+		/* populate TCP SYN eq */
+		if (attrib->ether_type == 0x0800) {
+			extra = ipa_write_8(54, extra);
+			rest = ipa_write_32(0x20000, rest);
+			rest = ipa_write_32(0x20000, rest);
+		} else {
+			extra = ipa_write_8(74, extra);
+			rest = ipa_write_32(0x20000, rest);
+			rest = ipa_write_32(0x20000, rest);
+		}
+		ihl_ofst_meq32 += 2;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_META_DATA) {
 		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE);
 		rest = ipa_write_32(attrib->meta_data_mask, rest);
@@ -1241,6 +1307,27 @@
 		ihl_ofst_rng16++;
 	}
 
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
+				ihl_ofst_rng16)) {
+			IPAHAL_ERR("ran out of ihl_rng16 eq\n");
+			goto err;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
+		/* 20  => offset of Ethertype after v4 header */
+		if (attrib->ether_type == 0x0800) {
+			extra = ipa_write_8(21, extra);
+			rest = ipa_write_16(0x0045, rest);
+			rest = ipa_write_16(0x0045, rest);
+		} else {
+			extra = ipa_write_8(20, extra);
+			rest = ipa_write_16(attrib->ether_type, rest);
+			rest = ipa_write_16(attrib->ether_type, rest);
+		}
+		ihl_ofst_rng16++;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
 		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ);
 		rest = ipa_write_32(attrib->u.v6.flow_label & 0xFFFFF,
@@ -1711,6 +1798,21 @@
 		ihl_ofst_meq32 += 2;
 	}
 
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+			ihl_ofst_meq32)) {
+			IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+			return -EPERM;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+		/* 12  => offset of SYN after v4 header */
+		eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 12;
+		eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0x20000;
+		eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = 0x20000;
+		ihl_ofst_meq32++;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
 		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
 			IPAHAL_ERR("ran out of meq32 eq\n");
@@ -2108,6 +2210,65 @@
 		ihl_ofst_meq32 += 2;
 	}
 
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+			ihl_ofst_meq32)) {
+			IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+			return -EPERM;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+		/* 12  => offset of SYN after v4 header */
+		eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 12;
+		eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0x20000;
+		eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = 0x20000;
+		ihl_ofst_meq32++;
+	}
+
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
+			ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
+			ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
+			IPAHAL_ERR("ran out of ihl_meq32 eq\n");
+			return -EPERM;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
+
+		/* populate TCP protocol eq */
+		if (attrib->ether_type == 0x0800) {
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 30;
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+				0xFF0000;
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+				0x60000;
+		} else {
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 26;
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+				0xFF00;
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+				0x600;
+		}
+
+		/* populate TCP SYN eq */
+		if (attrib->ether_type == 0x0800) {
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 54;
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+				0x20000;
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+				0x20000;
+		} else {
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 74;
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
+				0x20000;
+			eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
+				0x20000;
+		}
+		ihl_ofst_meq32 += 2;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
 		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
 			IPAHAL_ERR("ran out of meq32 eq\n");
@@ -2250,6 +2411,32 @@
 		ihl_ofst_rng16++;
 	}
 
+	if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
+		if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
+				ihl_ofst_rng16)) {
+			IPAHAL_ERR("ran out of ihl_rng16 eq\n");
+			return -EPERM;
+		}
+		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
+			ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
+		if (attrib->ether_type == 0x0800) {
+			eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset
+				= 21;
+			eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
+				= 0x0045;
+			eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
+				= 0x0045;
+		} else {
+			eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset =
+				20;
+			eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
+				= attrib->ether_type;
+			eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
+				= attrib->ether_type;
+		}
+		ihl_ofst_rng16++;
+	}
+
 	if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
 		*en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ);
 		eq_atrb->fl_eq_present = 1;
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
index 3be414b..d5fc867 100644
--- a/drivers/platform/msm/msm_ext_display.c
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -218,6 +218,12 @@
 		goto end;
 	}
 
+	if (!ext_disp->ops) {
+		pr_err("codec ops not registered\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
 	if (state == EXT_DISPLAY_CABLE_CONNECT) {
 		/* connect codec with interface */
 		*ext_disp->ops = data->codec_ops;
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 2818d56..aafb8fc 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -66,7 +66,7 @@
 	struct msm_bus_client_handle *bus_bw;
 	u32 bus_mas_id;
 	u32 bus_slv_id;
-	spinlock_t ab_ib_lock;
+	struct mutex ab_ib_lock;
 	struct list_head ab_list_head;
 	struct list_head ib_list_head;
 	unsigned long cur_ab;
@@ -608,7 +608,6 @@
 static int geni_se_rmv_ab_ib(struct geni_se_device *geni_se_dev,
 			     struct se_geni_rsc *rsc)
 {
-	unsigned long flags;
 	struct se_geni_rsc *tmp;
 	bool bus_bw_update = false;
 	int ret = 0;
@@ -616,7 +615,7 @@
 	if (unlikely(list_empty(&rsc->ab_list) || list_empty(&rsc->ib_list)))
 		return -EINVAL;
 
-	spin_lock_irqsave(&geni_se_dev->ab_ib_lock, flags);
+	mutex_lock(&geni_se_dev->ab_ib_lock);
 	list_del_init(&rsc->ab_list);
 	geni_se_dev->cur_ab -= rsc->ab;
 
@@ -629,8 +628,6 @@
 		geni_se_dev->cur_ib = 0;
 
 	bus_bw_update = geni_se_check_bus_bw(geni_se_dev);
-	spin_unlock_irqrestore(&geni_se_dev->ab_ib_lock, flags);
-
 	if (bus_bw_update)
 		ret = msm_bus_scale_update_bw(geni_se_dev->bus_bw,
 						geni_se_dev->cur_ab,
@@ -639,6 +636,7 @@
 		    "%s: %lu:%lu (%lu:%lu) %d\n", __func__,
 		    geni_se_dev->cur_ab, geni_se_dev->cur_ib,
 		    rsc->ab, rsc->ib, bus_bw_update);
+	mutex_unlock(&geni_se_dev->ab_ib_lock);
 	return ret;
 }
 
@@ -701,13 +699,12 @@
 static int geni_se_add_ab_ib(struct geni_se_device *geni_se_dev,
 			     struct se_geni_rsc *rsc)
 {
-	unsigned long flags;
 	struct se_geni_rsc *tmp = NULL;
 	struct list_head *ins_list_head;
 	bool bus_bw_update = false;
 	int ret = 0;
 
-	spin_lock_irqsave(&geni_se_dev->ab_ib_lock, flags);
+	mutex_lock(&geni_se_dev->ab_ib_lock);
 	list_add(&rsc->ab_list, &geni_se_dev->ab_list_head);
 	geni_se_dev->cur_ab += rsc->ab;
 
@@ -723,8 +720,6 @@
 		geni_se_dev->cur_ib = rsc->ib;
 
 	bus_bw_update = geni_se_check_bus_bw(geni_se_dev);
-	spin_unlock_irqrestore(&geni_se_dev->ab_ib_lock, flags);
-
 	if (bus_bw_update)
 		ret = msm_bus_scale_update_bw(geni_se_dev->bus_bw,
 						geni_se_dev->cur_ab,
@@ -733,6 +728,7 @@
 		    "%s: %lu:%lu (%lu:%lu) %d\n", __func__,
 		    geni_se_dev->cur_ab, geni_se_dev->cur_ib,
 		    rsc->ab, rsc->ib, bus_bw_update);
+	mutex_unlock(&geni_se_dev->ab_ib_lock);
 	return ret;
 }
 
@@ -1330,7 +1326,7 @@
 	mutex_init(&geni_se_dev->iommu_lock);
 	INIT_LIST_HEAD(&geni_se_dev->ab_list_head);
 	INIT_LIST_HEAD(&geni_se_dev->ib_list_head);
-	spin_lock_init(&geni_se_dev->ab_ib_lock);
+	mutex_init(&geni_se_dev->ab_ib_lock);
 	geni_se_dev->log_ctx = ipc_log_context_create(NUM_LOG_PAGES,
 						dev_name(geni_se_dev->dev), 0);
 	if (!geni_se_dev->log_ctx)
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c
index a23f069..47208f7 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.c
+++ b/drivers/platform/msm/seemp_core/seemp_logk.c
@@ -31,6 +31,7 @@
 
 #define EL2_SCM_ID 0x02001902
 #define KP_EL2_REPORT_REVISION 0x01000101
+#define INVALID_PID -1
 
 static struct seemp_logk_dev *slogk_dev;
 
@@ -65,6 +66,7 @@
 static long seemp_logk_set_mask(unsigned long arg);
 static long seemp_logk_set_mapping(unsigned long arg);
 static long seemp_logk_check_filter(unsigned long arg);
+static pid_t seemp_logk_get_pid(struct task_struct *t);
 static int seemp_logk_rtic_thread(void *data);
 
 void* (*seemp_logk_kernel_begin)(char **buf);
@@ -601,6 +603,26 @@
 	.mmap = seemp_logk_mmap,
 };
 
+static pid_t seemp_logk_get_pid(struct task_struct *t)
+{
+	struct task_struct *task;
+	pid_t pid;
+
+	if (t == NULL)
+		return INVALID_PID;
+
+	rcu_read_lock();
+	for_each_process(task) {
+		if (task == t) {
+			pid = task->pid;
+			rcu_read_unlock();
+			return pid;
+		}
+	}
+	rcu_read_unlock();
+	return INVALID_PID;
+}
+
 static int seemp_logk_rtic_thread(void *data)
 {
 	struct el2_report_header_t *header;
@@ -632,8 +654,9 @@
 					|| report->sequence_number >
 						last_sequence_number)) {
 				seemp_logk_rtic(report->report_type,
-					((struct task_struct *) report->actor)
-						->pid,
+					seemp_logk_get_pid(
+						(struct task_struct *)
+						report->actor),
 					/* leave this empty until
 					 * asset id is provided
 					 */
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 08e1505..431cd24 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -311,6 +311,9 @@
 	POWER_SUPPLY_ATTR(hw_current_max),
 	POWER_SUPPLY_ATTR(real_type),
 	POWER_SUPPLY_ATTR(pr_swap),
+	POWER_SUPPLY_ATTR(cc_step),
+	POWER_SUPPLY_ATTR(cc_step_sel),
+	POWER_SUPPLY_ATTR(sw_jeita_enabled),
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_ATTR(charge_counter_ext),
 	/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index dd5f78f..c793ee5 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -49,7 +49,7 @@
 #define SRAM_READ		"fg_sram_read"
 #define SRAM_WRITE		"fg_sram_write"
 #define PROFILE_LOAD		"fg_profile_load"
-#define DELTA_SOC		"fg_delta_soc"
+#define TTF_PRIMING		"fg_ttf_priming"
 
 /* Delta BSOC irq votable reasons */
 #define DELTA_BSOC_IRQ_VOTER	"fg_delta_bsoc_irq"
@@ -82,6 +82,8 @@
 
 #define BATT_THERM_NUM_COEFFS		3
 
+#define MAX_CC_STEPS			20
+
 /* Debug flag definitions */
 enum fg_debug_flag {
 	FG_IRQ			= BIT(0), /* Show interrupts */
@@ -241,6 +243,11 @@
 	NUM_ESR_TIMERS,
 };
 
+enum ttf_mode {
+	TTF_MODE_NORMAL = 0,
+	TTF_MODE_QNOVO,
+};
+
 /* DT parameters for FG device */
 struct fg_dt_props {
 	bool	force_load_profile;
@@ -323,16 +330,31 @@
 };
 
 struct fg_circ_buf {
-	int	arr[20];
+	int	arr[10];
 	int	size;
 	int	head;
 };
 
+struct fg_cc_step_data {
+	int arr[MAX_CC_STEPS];
+	int sel;
+};
+
 struct fg_pt {
 	s32 x;
 	s32 y;
 };
 
+struct ttf {
+	struct fg_circ_buf	ibatt;
+	struct fg_circ_buf	vbatt;
+	struct fg_cc_step_data	cc_step;
+	struct mutex		lock;
+	int			mode;
+	int			last_ttf;
+	s64			last_ms;
+};
+
 static const struct fg_pt fg_ln_table[] = {
 	{ 1000,		0 },
 	{ 2000,		693 },
@@ -372,6 +394,7 @@
 	struct power_supply	*usb_psy;
 	struct power_supply	*dc_psy;
 	struct power_supply	*parallel_psy;
+	struct power_supply	*pc_port_psy;
 	struct iio_channel	*batt_id_chan;
 	struct iio_channel	*die_temp_chan;
 	struct fg_irq_info	*irqs;
@@ -388,9 +411,9 @@
 	struct fg_cyc_ctr_data	cyc_ctr;
 	struct notifier_block	nb;
 	struct fg_cap_learning  cl;
+	struct ttf		ttf;
 	struct mutex		bus_lock;
 	struct mutex		sram_rw_lock;
-	struct mutex		batt_avg_lock;
 	struct mutex		charge_full_lock;
 	u32			batt_soc_base;
 	u32			batt_info_base;
@@ -403,12 +426,14 @@
 	int			prev_charge_status;
 	int			charge_done;
 	int			charge_type;
+	int			online_status;
 	int			last_soc;
 	int			last_batt_temp;
 	int			health;
 	int			maint_soc;
 	int			delta_soc;
 	int			last_msoc;
+	int			last_recharge_volt_mv;
 	int			esr_timer_charging_default[NUM_ESR_TIMERS];
 	enum slope_limit_status	slope_limit_sts;
 	bool			profile_available;
@@ -429,11 +454,8 @@
 	struct completion	mem_grant;
 	struct delayed_work	profile_load_work;
 	struct work_struct	status_change_work;
-	struct work_struct	cycle_count_work;
-	struct delayed_work	batt_avg_work;
+	struct delayed_work	ttf_work;
 	struct delayed_work	sram_dump_work;
-	struct fg_circ_buf	ibatt_circ_buf;
-	struct fg_circ_buf	vbatt_circ_buf;
 };
 
 /* Debugfs data structures are below */
@@ -496,6 +518,7 @@
 extern void fg_circ_buf_add(struct fg_circ_buf *buf, int val);
 extern void fg_circ_buf_clr(struct fg_circ_buf *buf);
 extern int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg);
+extern int fg_circ_buf_median(struct fg_circ_buf *buf, int *median);
 extern int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input,
 			s32 *output);
 #endif
diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c
index d9ca47c..aed2062 100644
--- a/drivers/power/supply/qcom/fg-util.c
+++ b/drivers/power/supply/qcom/fg-util.c
@@ -10,6 +10,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/sort.h>
 #include "fg-core.h"
 
 void fg_circ_buf_add(struct fg_circ_buf *buf, int val)
@@ -21,7 +22,9 @@
 
 void fg_circ_buf_clr(struct fg_circ_buf *buf)
 {
-	memset(buf, 0, sizeof(*buf));
+	buf->size = 0;
+	buf->head = 0;
+	memset(buf->arr, 0, sizeof(buf->arr));
 }
 
 int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg)
@@ -39,6 +42,39 @@
 	return 0;
 }
 
+static int cmp_int(const void *a, const void *b)
+{
+	return *(int *)a - *(int *)b;
+}
+
+int fg_circ_buf_median(struct fg_circ_buf *buf, int *median)
+{
+	int *temp;
+
+	if (buf->size == 0)
+		return -ENODATA;
+
+	if (buf->size == 1) {
+		*median = buf->arr[0];
+		return 0;
+	}
+
+	temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL);
+	if (!temp)
+		return -ENOMEM;
+
+	memcpy(temp, buf->arr, buf->size * sizeof(*temp));
+	sort(temp, buf->size, sizeof(*temp), cmp_int, NULL);
+
+	if (buf->size % 2)
+		*median = temp[buf->size / 2];
+	else
+		*median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2;
+
+	kfree(temp);
+	return 0;
+}
+
 int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input, s32 *output)
 {
 	int i;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 7c94744..6f615e4 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -1173,6 +1173,42 @@
 	return true;
 }
 
+static bool usb_psy_initialized(struct fg_chip *chip)
+{
+	if (chip->usb_psy)
+		return true;
+
+	chip->usb_psy = power_supply_get_by_name("usb");
+	if (!chip->usb_psy)
+		return false;
+
+	return true;
+}
+
+static bool pc_port_psy_initialized(struct fg_chip *chip)
+{
+	if (chip->pc_port_psy)
+		return true;
+
+	chip->pc_port_psy = power_supply_get_by_name("pc_port");
+	if (!chip->pc_port_psy)
+		return false;
+
+	return true;
+}
+
+static bool dc_psy_initialized(struct fg_chip *chip)
+{
+	if (chip->dc_psy)
+		return true;
+
+	chip->dc_psy = power_supply_get_by_name("dc");
+	if (!chip->dc_psy)
+		return false;
+
+	return true;
+}
+
 static bool is_parallel_charger_available(struct fg_chip *chip)
 {
 	if (!chip->parallel_psy)
@@ -1279,11 +1315,20 @@
 	return true;
 }
 
+#define QNOVO_CL_SKEW_DECIPCT	-30
 static void fg_cap_learning_post_process(struct fg_chip *chip)
 {
 	int64_t max_inc_val, min_dec_val, old_cap;
 	int rc;
 
+	if (is_qnovo_en(chip)) {
+		fg_dbg(chip, FG_CAP_LEARN, "applying skew %d on current learnt capacity %lld\n",
+			QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah);
+		chip->cl.final_cc_uah = chip->cl.final_cc_uah *
+						(1000 + QNOVO_CL_SKEW_DECIPCT);
+		do_div(chip->cl.final_cc_uah, 1000);
+	}
+
 	max_inc_val = chip->cl.learned_cc_uah
 			* (1000 + chip->dt.cl_max_cap_inc);
 	do_div(max_inc_val, 1000);
@@ -1592,6 +1637,9 @@
 	if (chip->wa_flags & PMI8998_V1_REV_WA)
 		return 0;
 
+	if (voltage_mv == chip->last_recharge_volt_mv)
+		return 0;
+
 	fg_dbg(chip, FG_STATUS, "Setting recharge voltage to %dmV\n",
 		voltage_mv);
 	fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR, voltage_mv, &buf);
@@ -1606,6 +1654,7 @@
 		return rc;
 	}
 
+	chip->last_recharge_volt_mv = voltage_mv;
 	return 0;
 }
 
@@ -1916,6 +1965,33 @@
 	return 0;
 }
 
+static int fg_adjust_recharge_voltage(struct fg_chip *chip)
+{
+	int rc, recharge_volt_mv;
+
+	if (chip->dt.auto_recharge_soc)
+		return 0;
+
+	fg_dbg(chip, FG_STATUS, "health: %d chg_status: %d chg_done: %d\n",
+		chip->health, chip->charge_status, chip->charge_done);
+
+	recharge_volt_mv = chip->dt.recharge_volt_thr_mv;
+
+	/* Lower the recharge voltage in soft JEITA */
+	if (chip->health == POWER_SUPPLY_HEALTH_WARM ||
+			chip->health == POWER_SUPPLY_HEALTH_COOL)
+		recharge_volt_mv -= 200;
+
+	rc = fg_set_recharge_voltage(chip, recharge_volt_mv);
+	if (rc < 0) {
+		pr_err("Error in setting recharge_voltage, rc=%d\n",
+			rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static int fg_slope_limit_config(struct fg_chip *chip, int batt_temp)
 {
 	enum slope_limit_status status;
@@ -2133,102 +2209,67 @@
 	return 0;
 }
 
-static void fg_batt_avg_update(struct fg_chip *chip)
+static void fg_ttf_update(struct fg_chip *chip)
 {
-	if (chip->charge_status == chip->prev_charge_status)
+	int rc;
+	int delay_ms;
+	union power_supply_propval prop = {0, };
+	int online = 0;
+
+	if (usb_psy_initialized(chip)) {
+		rc = power_supply_get_property(chip->usb_psy,
+			POWER_SUPPLY_PROP_ONLINE, &prop);
+		if (rc < 0) {
+			pr_err("Couldn't read usb ONLINE prop rc=%d\n", rc);
+			return;
+		}
+
+		online = online || prop.intval;
+	}
+
+	if (pc_port_psy_initialized(chip)) {
+		rc = power_supply_get_property(chip->pc_port_psy,
+			POWER_SUPPLY_PROP_ONLINE, &prop);
+		if (rc < 0) {
+			pr_err("Couldn't read pc_port ONLINE prop rc=%d\n", rc);
+			return;
+		}
+
+		online = online || prop.intval;
+	}
+
+	if (dc_psy_initialized(chip)) {
+		rc = power_supply_get_property(chip->dc_psy,
+			POWER_SUPPLY_PROP_ONLINE, &prop);
+		if (rc < 0) {
+			pr_err("Couldn't read dc ONLINE prop rc=%d\n", rc);
+			return;
+		}
+
+		online = online || prop.intval;
+	}
+
+
+	if (chip->online_status == online)
 		return;
 
-	cancel_delayed_work_sync(&chip->batt_avg_work);
-	fg_circ_buf_clr(&chip->ibatt_circ_buf);
-	fg_circ_buf_clr(&chip->vbatt_circ_buf);
+	chip->online_status = online;
+	if (online)
+		/* wait 35 seconds for the input to settle */
+		delay_ms = 35000;
+	else
+		/* wait 5 seconds for current to settle during discharge */
+		delay_ms = 5000;
 
-	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING ||
-			chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
-		schedule_delayed_work(&chip->batt_avg_work,
-							msecs_to_jiffies(2000));
-}
-
-static void status_change_work(struct work_struct *work)
-{
-	struct fg_chip *chip = container_of(work,
-			struct fg_chip, status_change_work);
-	union power_supply_propval prop = {0, };
-	int rc, batt_temp;
-
-	if (!batt_psy_initialized(chip)) {
-		fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
-		goto out;
-	}
-
-	rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
-			&prop);
-	if (rc < 0) {
-		pr_err("Error in getting charging status, rc=%d\n", rc);
-		goto out;
-	}
-
-	chip->prev_charge_status = chip->charge_status;
-	chip->charge_status = prop.intval;
-	rc = power_supply_get_property(chip->batt_psy,
-			POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
-	if (rc < 0) {
-		pr_err("Error in getting charge type, rc=%d\n", rc);
-		goto out;
-	}
-
-	chip->charge_type = prop.intval;
-	rc = power_supply_get_property(chip->batt_psy,
-			POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
-	if (rc < 0) {
-		pr_err("Error in getting charge_done, rc=%d\n", rc);
-		goto out;
-	}
-
-	chip->charge_done = prop.intval;
-	if (chip->cyc_ctr.en)
-		schedule_work(&chip->cycle_count_work);
-
-	fg_cap_learning_update(chip);
-
-	rc = fg_charge_full_update(chip);
-	if (rc < 0)
-		pr_err("Error in charge_full_update, rc=%d\n", rc);
-
-	rc = fg_adjust_recharge_soc(chip);
-	if (rc < 0)
-		pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
-
-	rc = fg_adjust_ki_coeff_dischg(chip);
-	if (rc < 0)
-		pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
-
-	rc = fg_esr_fcc_config(chip);
-	if (rc < 0)
-		pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
-
-	rc = fg_esr_timer_config(chip, false);
-	if (rc < 0)
-		pr_err("Error in configuring ESR timer, rc=%d\n", rc);
-
-	rc = fg_get_battery_temp(chip, &batt_temp);
-	if (!rc) {
-		rc = fg_slope_limit_config(chip, batt_temp);
-		if (rc < 0)
-			pr_err("Error in configuring slope limiter rc:%d\n",
-				rc);
-
-		rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
-		if (rc < 0)
-			pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
-				rc);
-	}
-
-	fg_batt_avg_update(chip);
-
-out:
-	fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
-		chip->charge_status, chip->charge_type, chip->charge_done);
-	pm_relax(chip->dev);
+	vote(chip->awake_votable, TTF_PRIMING, true, 0);
+	cancel_delayed_work_sync(&chip->ttf_work);
+	mutex_lock(&chip->ttf.lock);
+	fg_circ_buf_clr(&chip->ttf.ibatt);
+	fg_circ_buf_clr(&chip->ttf.vbatt);
+	chip->ttf.last_ttf = 0;
+	chip->ttf.last_ms = 0;
+	mutex_unlock(&chip->ttf.lock);
+	schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
 }
 
 static void restore_cycle_counter(struct fg_chip *chip)
@@ -2236,6 +2277,9 @@
 	int rc = 0, i;
 	u8 data[2];
 
+	if (!chip->cyc_ctr.en)
+		return;
+
 	mutex_lock(&chip->cyc_ctr.lock);
 	for (i = 0; i < BUCKET_COUNT; i++) {
 		rc = fg_sram_read(chip, CYCLE_COUNT_WORD + (i / 2),
@@ -2289,20 +2333,25 @@
 	rc = fg_sram_write(chip, CYCLE_COUNT_WORD + (bucket / 2),
 			CYCLE_COUNT_OFFSET + (bucket % 2) * 2, data, 2,
 			FG_IMA_DEFAULT);
-	if (rc < 0)
+	if (rc < 0) {
 		pr_err("failed to write BATT_CYCLE[%d] rc=%d\n",
 			bucket, rc);
-	else
-		chip->cyc_ctr.count[bucket] = cyc_count;
+		return rc;
+	}
+
+	chip->cyc_ctr.count[bucket] = cyc_count;
+	fg_dbg(chip, FG_STATUS, "Stored count %d in bucket %d\n", cyc_count,
+		bucket);
+
 	return rc;
 }
 
-static void cycle_count_work(struct work_struct *work)
+static void fg_cycle_counter_update(struct fg_chip *chip)
 {
 	int rc = 0, bucket, i, batt_soc;
-	struct fg_chip *chip = container_of(work,
-				struct fg_chip,
-				cycle_count_work);
+
+	if (!chip->cyc_ctr.en)
+		return;
 
 	mutex_lock(&chip->cyc_ctr.lock);
 	rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
@@ -2314,45 +2363,30 @@
 	/* We need only the most significant byte here */
 	batt_soc = (u32)batt_soc >> 24;
 
-	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
-		/* Find out which bucket the SOC falls in */
-		bucket = batt_soc / BUCKET_SOC_PCT;
-		pr_debug("batt_soc: %d bucket: %d\n", batt_soc, bucket);
+	/* Find out which bucket the SOC falls in */
+	bucket = batt_soc / BUCKET_SOC_PCT;
 
-		/*
-		 * If we've started counting for the previous bucket,
-		 * then store the counter for that bucket if the
-		 * counter for current bucket is getting started.
-		 */
-		if (bucket > 0 && chip->cyc_ctr.started[bucket - 1] &&
-			!chip->cyc_ctr.started[bucket]) {
-			rc = fg_inc_store_cycle_ctr(chip, bucket - 1);
-			if (rc < 0) {
-				pr_err("Error in storing cycle_ctr rc: %d\n",
-					rc);
-				goto out;
-			} else {
-				chip->cyc_ctr.started[bucket - 1] = false;
-				chip->cyc_ctr.last_soc[bucket - 1] = 0;
-			}
-		}
+	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
 		if (!chip->cyc_ctr.started[bucket]) {
 			chip->cyc_ctr.started[bucket] = true;
 			chip->cyc_ctr.last_soc[bucket] = batt_soc;
 		}
-	} else {
+	} else if (chip->charge_done || !is_input_present(chip)) {
 		for (i = 0; i < BUCKET_COUNT; i++) {
 			if (chip->cyc_ctr.started[i] &&
-				batt_soc > chip->cyc_ctr.last_soc[i]) {
+				batt_soc > chip->cyc_ctr.last_soc[i] + 2) {
 				rc = fg_inc_store_cycle_ctr(chip, i);
 				if (rc < 0)
 					pr_err("Error in storing cycle_ctr rc: %d\n",
 						rc);
 				chip->cyc_ctr.last_soc[i] = 0;
+				chip->cyc_ctr.started[i] = false;
 			}
-			chip->cyc_ctr.started[i] = false;
 		}
 	}
+
+	fg_dbg(chip, FG_STATUS, "batt_soc: %d bucket: %d chg_status: %d\n",
+		batt_soc, bucket, chip->charge_status);
 out:
 	mutex_unlock(&chip->cyc_ctr.lock);
 }
@@ -2373,6 +2407,87 @@
 	return count;
 }
 
+static void status_change_work(struct work_struct *work)
+{
+	struct fg_chip *chip = container_of(work,
+			struct fg_chip, status_change_work);
+	union power_supply_propval prop = {0, };
+	int rc, batt_temp;
+
+	if (!batt_psy_initialized(chip)) {
+		fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
+		goto out;
+	}
+
+	rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS,
+			&prop);
+	if (rc < 0) {
+		pr_err("Error in getting charging status, rc=%d\n", rc);
+		goto out;
+	}
+
+	chip->prev_charge_status = chip->charge_status;
+	chip->charge_status = prop.intval;
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
+	if (rc < 0) {
+		pr_err("Error in getting charge type, rc=%d\n", rc);
+		goto out;
+	}
+
+	chip->charge_type = prop.intval;
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CHARGE_DONE, &prop);
+	if (rc < 0) {
+		pr_err("Error in getting charge_done, rc=%d\n", rc);
+		goto out;
+	}
+
+	chip->charge_done = prop.intval;
+	fg_cycle_counter_update(chip);
+	fg_cap_learning_update(chip);
+
+	rc = fg_charge_full_update(chip);
+	if (rc < 0)
+		pr_err("Error in charge_full_update, rc=%d\n", rc);
+
+	rc = fg_adjust_recharge_soc(chip);
+	if (rc < 0)
+		pr_err("Error in adjusting recharge_soc, rc=%d\n", rc);
+
+	rc = fg_adjust_recharge_voltage(chip);
+	if (rc < 0)
+		pr_err("Error in adjusting recharge_voltage, rc=%d\n", rc);
+
+	rc = fg_adjust_ki_coeff_dischg(chip);
+	if (rc < 0)
+		pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
+
+	rc = fg_esr_fcc_config(chip);
+	if (rc < 0)
+		pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
+
+	rc = fg_get_battery_temp(chip, &batt_temp);
+	if (!rc) {
+		rc = fg_slope_limit_config(chip, batt_temp);
+		if (rc < 0)
+			pr_err("Error in configuring slope limiter rc:%d\n",
+				rc);
+
+		rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
+		if (rc < 0)
+			pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
+				rc);
+	}
+
+	fg_ttf_update(chip);
+
+out:
+	fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n",
+		chip->charge_status, chip->charge_type, chip->charge_done);
+	pm_relax(chip->dev);
+}
+
 static int fg_bp_params_config(struct fg_chip *chip)
 {
 	int rc = 0;
@@ -2733,45 +2848,19 @@
 
 module_param_cb(restart, &fg_restart_ops, &fg_restart, 0644);
 
-#define BATT_AVG_POLL_PERIOD_MS	10000
-static void batt_avg_work(struct work_struct *work)
-{
-	struct fg_chip *chip = container_of(work, struct fg_chip,
-					    batt_avg_work.work);
-	int rc, ibatt_now, vbatt_now;
-
-	mutex_lock(&chip->batt_avg_lock);
-	rc = fg_get_battery_current(chip, &ibatt_now);
-	if (rc < 0) {
-		pr_err("failed to get battery current, rc=%d\n", rc);
-		goto reschedule;
-	}
-
-	rc = fg_get_battery_voltage(chip, &vbatt_now);
-	if (rc < 0) {
-		pr_err("failed to get battery voltage, rc=%d\n", rc);
-		goto reschedule;
-	}
-
-	fg_circ_buf_add(&chip->ibatt_circ_buf, ibatt_now);
-	fg_circ_buf_add(&chip->vbatt_circ_buf, vbatt_now);
-
-reschedule:
-	mutex_unlock(&chip->batt_avg_lock);
-	schedule_delayed_work(&chip->batt_avg_work,
-			      msecs_to_jiffies(BATT_AVG_POLL_PERIOD_MS));
-}
-
 #define HOURS_TO_SECONDS	3600
 #define OCV_SLOPE_UV		10869
 #define MILLI_UNIT		1000
 #define MICRO_UNIT		1000000
-static int fg_get_time_to_full(struct fg_chip *chip, int *val)
+#define NANO_UNIT		1000000000
+static int fg_get_time_to_full_locked(struct fg_chip *chip, int *val)
 {
-	int rc, ibatt_avg, vbatt_avg, rbatt, msoc, ocv_cc2cv, full_soc,
-		act_cap_uah;
-	s32 i_cc2cv, soc_cc2cv, ln_val, centi_tau_scale;
-	s64 t_predicted_cc = 0, t_predicted_cv = 0;
+	int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
+		i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm, ttf_mode,
+		i, soc_per_step, msoc_this_step, msoc_next_step,
+		ibatt_this_step, t_predicted_this_step, ttf_slope,
+		t_predicted_cv, t_predicted = 0;
+	s64 delta_ms;
 
 	if (chip->bp.float_volt_uv <= 0) {
 		pr_err("battery profile is not loaded\n");
@@ -2790,48 +2879,53 @@
 	}
 	fg_dbg(chip, FG_TTF, "msoc=%d\n", msoc);
 
+	/* the battery is considered full if the SOC is 100% */
 	if (msoc >= 100) {
 		*val = 0;
 		return 0;
 	}
 
-	mutex_lock(&chip->batt_avg_lock);
-	rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
-	if (rc < 0) {
-		/* try to get instantaneous current */
-		rc = fg_get_battery_current(chip, &ibatt_avg);
-		if (rc < 0) {
-			mutex_unlock(&chip->batt_avg_lock);
-			pr_err("failed to get battery current, rc=%d\n", rc);
-			return rc;
-		}
+	if (is_qnovo_en(chip))
+		ttf_mode = TTF_MODE_QNOVO;
+	else
+		ttf_mode = TTF_MODE_NORMAL;
+
+	/* when switching TTF algorithms the TTF needs to be reset */
+	if (chip->ttf.mode != ttf_mode) {
+		fg_circ_buf_clr(&chip->ttf.ibatt);
+		fg_circ_buf_clr(&chip->ttf.vbatt);
+		chip->ttf.last_ttf = 0;
+		chip->ttf.last_ms = 0;
+		chip->ttf.mode = ttf_mode;
 	}
 
-	rc = fg_circ_buf_avg(&chip->vbatt_circ_buf, &vbatt_avg);
-	if (rc < 0) {
-		/* try to get instantaneous voltage */
-		rc = fg_get_battery_voltage(chip, &vbatt_avg);
-		if (rc < 0) {
-			mutex_unlock(&chip->batt_avg_lock);
-			pr_err("failed to get battery voltage, rc=%d\n", rc);
-			return rc;
-		}
+	/* at least 10 samples are required to produce a stable IBATT */
+	if (chip->ttf.ibatt.size < 10) {
+		*val = -1;
+		return 0;
 	}
 
-	mutex_unlock(&chip->batt_avg_lock);
-	fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
+	rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
+	if (rc < 0) {
+		pr_err("failed to get IBATT AVG rc=%d\n", rc);
+		return rc;
+	}
 
-	/* clamp ibatt_avg to -150mA */
-	if (ibatt_avg > -150000)
-		ibatt_avg = -150000;
+	rc = fg_circ_buf_median(&chip->ttf.vbatt, &vbatt_avg);
+	if (rc < 0) {
+		pr_err("failed to get VBATT AVG rc=%d\n", rc);
+		return rc;
+	}
+
+	ibatt_avg = -ibatt_avg / MILLI_UNIT;
+	vbatt_avg /= MILLI_UNIT;
+
+	/* clamp ibatt_avg to iterm */
+	if (ibatt_avg < abs(chip->dt.sys_term_curr_ma))
+		ibatt_avg = abs(chip->dt.sys_term_curr_ma);
+
 	fg_dbg(chip, FG_TTF, "ibatt_avg=%d\n", ibatt_avg);
-
-	/* reverse polarity to be consistent with unsigned current settings */
-	ibatt_avg = abs(ibatt_avg);
-
-	/* estimated battery current at the CC to CV transition */
-	i_cc2cv = div_s64((s64)ibatt_avg * vbatt_avg, chip->bp.float_volt_uv);
-	fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
+	fg_dbg(chip, FG_TTF, "vbatt_avg=%d\n", vbatt_avg);
 
 	rc = fg_get_battery_resistance(chip, &rbatt);
 	if (rc < 0) {
@@ -2839,19 +2933,14 @@
 		return rc;
 	}
 
-	/* clamp rbatt to 50mOhms */
-	if (rbatt < 50000)
-		rbatt = 50000;
-
+	rbatt /= MILLI_UNIT;
 	fg_dbg(chip, FG_TTF, "rbatt=%d\n", rbatt);
 
-	rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
+	rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
 	if (rc < 0) {
 		pr_err("failed to get ACT_BATT_CAP rc=%d\n", rc);
 		return rc;
 	}
-	act_cap_uah *= MILLI_UNIT;
-	fg_dbg(chip, FG_TTF, "actual_capacity_uah=%d\n", act_cap_uah);
 
 	rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
 	if (rc < 0) {
@@ -2860,69 +2949,148 @@
 	}
 	full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
 								FULL_SOC_RAW);
-	fg_dbg(chip, FG_TTF, "full_soc=%d\n", full_soc);
+	act_cap_mah = full_soc * act_cap_mah / 100;
+	fg_dbg(chip, FG_TTF, "act_cap_mah=%d\n", act_cap_mah);
+
+	/* estimated battery current at the CC to CV transition */
+	switch (chip->ttf.mode) {
+	case TTF_MODE_NORMAL:
+		i_cc2cv = ibatt_avg * vbatt_avg /
+			max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT);
+		break;
+	case TTF_MODE_QNOVO:
+		i_cc2cv = min(
+			chip->ttf.cc_step.arr[MAX_CC_STEPS - 1] / MILLI_UNIT,
+			ibatt_avg * vbatt_avg /
+			max(MILLI_UNIT, chip->bp.float_volt_uv / MILLI_UNIT));
+		break;
+	default:
+		pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
+		break;
+	}
+	fg_dbg(chip, FG_TTF, "i_cc2cv=%d\n", i_cc2cv);
 
 	/* if we are already in CV state then we can skip estimating CC */
 	if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
-		goto skip_cc_estimate;
+		goto cv_estimate;
 
-	/* if the charger is current limited then use power approximation */
-	if (ibatt_avg > chip->bp.fastchg_curr_ma * MILLI_UNIT - 50000)
-		ocv_cc2cv = div_s64((s64)rbatt * ibatt_avg, MICRO_UNIT);
-	else
-		ocv_cc2cv = div_s64((s64)rbatt * i_cc2cv, MICRO_UNIT);
-	ocv_cc2cv = chip->bp.float_volt_uv - ocv_cc2cv;
-	fg_dbg(chip, FG_TTF, "ocv_cc2cv=%d\n", ocv_cc2cv);
-
-	soc_cc2cv = div_s64(chip->bp.float_volt_uv - ocv_cc2cv, OCV_SLOPE_UV);
 	/* estimated SOC at the CC to CV transition */
+	soc_cc2cv = DIV_ROUND_CLOSEST(rbatt * i_cc2cv, OCV_SLOPE_UV);
 	soc_cc2cv = 100 - soc_cc2cv;
 	fg_dbg(chip, FG_TTF, "soc_cc2cv=%d\n", soc_cc2cv);
 
-	/* the esimated SOC may be lower than the current SOC */
-	if (soc_cc2cv - msoc <= 0)
-		goto skip_cc_estimate;
+	switch (chip->ttf.mode) {
+	case TTF_MODE_NORMAL:
+		if (soc_cc2cv - msoc <= 0)
+			goto cv_estimate;
 
-	t_predicted_cc = div_s64((s64)full_soc * act_cap_uah, 100);
-	t_predicted_cc = div_s64(t_predicted_cc * (soc_cc2cv - msoc), 100);
-	t_predicted_cc *= HOURS_TO_SECONDS;
-	t_predicted_cc = div_s64(t_predicted_cc, (ibatt_avg + i_cc2cv) / 2);
+		divisor = max(100, (ibatt_avg + i_cc2cv) / 2 * 100);
+		t_predicted = div_s64((s64)act_cap_mah * (soc_cc2cv - msoc) *
+						HOURS_TO_SECONDS, divisor);
+		break;
+	case TTF_MODE_QNOVO:
+		soc_per_step = 100 / MAX_CC_STEPS;
+		for (i = msoc / soc_per_step; i < MAX_CC_STEPS - 1; ++i) {
+			msoc_next_step = (i + 1) * soc_per_step;
+			if (i == msoc / soc_per_step)
+				msoc_this_step = msoc;
+			else
+				msoc_this_step = i * soc_per_step;
 
-skip_cc_estimate:
-	fg_dbg(chip, FG_TTF, "t_predicted_cc=%lld\n", t_predicted_cc);
+			/* scale ibatt by 85% to account for discharge pulses */
+			ibatt_this_step = min(
+					chip->ttf.cc_step.arr[i] / MILLI_UNIT,
+					ibatt_avg) * 85 / 100;
+			divisor = max(100, ibatt_this_step * 100);
+			t_predicted_this_step = div_s64((s64)act_cap_mah *
+					(msoc_next_step - msoc_this_step) *
+					HOURS_TO_SECONDS, divisor);
+			t_predicted += t_predicted_this_step;
+			fg_dbg(chip, FG_TTF, "[%d, %d] ma=%d t=%d\n",
+				msoc_this_step, msoc_next_step,
+				ibatt_this_step, t_predicted_this_step);
+		}
+		break;
+	default:
+		pr_err("TTF mode %d is not supported\n", chip->ttf.mode);
+		break;
+	}
 
-	/* CV estimate starts here */
-	if (chip->charge_type >= POWER_SUPPLY_CHARGE_TYPE_TAPER)
-		ln_val = ibatt_avg / (abs(chip->dt.sys_term_curr_ma) + 200);
+cv_estimate:
+	fg_dbg(chip, FG_TTF, "t_predicted_cc=%d\n", t_predicted);
+
+	iterm = max(100, abs(chip->dt.sys_term_curr_ma) + 200);
+	fg_dbg(chip, FG_TTF, "iterm=%d\n", iterm);
+
+	if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_TAPER)
+		tau = max(MILLI_UNIT, ibatt_avg * MILLI_UNIT / iterm);
 	else
-		ln_val = i_cc2cv / (abs(chip->dt.sys_term_curr_ma) + 200);
+		tau = max(MILLI_UNIT, i_cc2cv * MILLI_UNIT / iterm);
 
-	if (msoc < 95)
-		centi_tau_scale = 100;
-	else
-		centi_tau_scale = 20 * (100 - msoc);
+	rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), tau, &tau);
+	if (rc < 0) {
+		pr_err("failed to interpolate tau rc=%d\n", rc);
+		return rc;
+	}
 
-	fg_dbg(chip, FG_TTF, "ln_in=%d\n", ln_val);
-	rc = fg_lerp(fg_ln_table, ARRAY_SIZE(fg_ln_table), ln_val, &ln_val);
-	fg_dbg(chip, FG_TTF, "ln_out=%d\n", ln_val);
-	t_predicted_cv = div_s64((s64)act_cap_uah * rbatt, MICRO_UNIT);
-	t_predicted_cv = div_s64(t_predicted_cv * centi_tau_scale, 100);
-	t_predicted_cv = div_s64(t_predicted_cv * ln_val, MILLI_UNIT);
-	t_predicted_cv = div_s64(t_predicted_cv * HOURS_TO_SECONDS, MICRO_UNIT);
-	fg_dbg(chip, FG_TTF, "t_predicted_cv=%lld\n", t_predicted_cv);
-	*val = t_predicted_cc + t_predicted_cv;
+	/* tau is scaled linearly from 95% to 100% SOC */
+	if (msoc >= 95)
+		tau = tau * 2 * (100 - msoc) / 10;
+
+	fg_dbg(chip, FG_TTF, "tau=%d\n", tau);
+	t_predicted_cv = div_s64((s64)act_cap_mah * rbatt * tau *
+						HOURS_TO_SECONDS, NANO_UNIT);
+	fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
+	t_predicted += t_predicted_cv;
+
+	fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted);
+	if (chip->ttf.last_ms != 0) {
+		delta_ms = ktime_ms_delta(ktime_get_boottime(),
+					  ms_to_ktime(chip->ttf.last_ms));
+		if (delta_ms > 10000) {
+			ttf_slope = div64_s64(
+				(s64)(t_predicted - chip->ttf.last_ttf) *
+				MICRO_UNIT, delta_ms);
+			if (ttf_slope > -100)
+				ttf_slope = -100;
+			else if (ttf_slope < -2000)
+				ttf_slope = -2000;
+
+			t_predicted = div_s64(
+				(s64)ttf_slope * delta_ms, MICRO_UNIT) +
+				chip->ttf.last_ttf;
+			fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope);
+		} else {
+			t_predicted = chip->ttf.last_ttf;
+		}
+	}
+
+	/* clamp the ttf to 0 */
+	if (t_predicted < 0)
+		t_predicted = 0;
+
+	fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted);
+	*val = t_predicted;
 	return 0;
 }
 
+static int fg_get_time_to_full(struct fg_chip *chip, int *val)
+{
+	int rc;
+
+	mutex_lock(&chip->ttf.lock);
+	rc = fg_get_time_to_full_locked(chip, val);
+	mutex_unlock(&chip->ttf.lock);
+	return rc;
+}
+
 #define CENTI_ICORRECT_C0	105
 #define CENTI_ICORRECT_C1	20
 static int fg_get_time_to_empty(struct fg_chip *chip, int *val)
 {
-	int rc, ibatt_avg, msoc, act_cap_uah;
-	s32 divisor;
-	s64 t_predicted;
+	int rc, ibatt_avg, msoc, full_soc, act_cap_mah, divisor;
 
-	rc = fg_circ_buf_avg(&chip->ibatt_circ_buf, &ibatt_avg);
+	rc = fg_circ_buf_median(&chip->ttf.ibatt, &ibatt_avg);
 	if (rc < 0) {
 		/* try to get instantaneous current */
 		rc = fg_get_battery_current(chip, &ibatt_avg);
@@ -2932,16 +3100,10 @@
 		}
 	}
 
-	/* clamp ibatt_avg to 150mA */
-	if (ibatt_avg < 150000)
-		ibatt_avg = 150000;
-
-	rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_uah);
-	if (rc < 0) {
-		pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
-		return rc;
-	}
-	act_cap_uah *= MILLI_UNIT;
+	ibatt_avg /= MILLI_UNIT;
+	/* clamp ibatt_avg to 100mA */
+	if (ibatt_avg < 100)
+		ibatt_avg = 100;
 
 	rc = fg_get_prop_capacity(chip, &msoc);
 	if (rc < 0) {
@@ -2949,14 +3111,25 @@
 		return rc;
 	}
 
-	t_predicted = div_s64((s64)msoc * act_cap_uah, 100);
-	t_predicted *= HOURS_TO_SECONDS;
-	divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
-	divisor = div_s64((s64)divisor * ibatt_avg, 10000);
-	if (divisor > 0)
-		t_predicted = div_s64(t_predicted, divisor);
+	rc = fg_get_sram_prop(chip, FG_SRAM_ACT_BATT_CAP, &act_cap_mah);
+	if (rc < 0) {
+		pr_err("Error in getting ACT_BATT_CAP, rc=%d\n", rc);
+		return rc;
+	}
 
-	*val = t_predicted;
+	rc = fg_get_sram_prop(chip, FG_SRAM_FULL_SOC, &full_soc);
+	if (rc < 0) {
+		pr_err("failed to get full soc rc=%d\n", rc);
+		return rc;
+	}
+	full_soc = DIV_ROUND_CLOSEST(((u16)full_soc >> 8) * FULL_CAPACITY,
+								FULL_SOC_RAW);
+	act_cap_mah = full_soc * act_cap_mah / 100;
+
+	divisor = CENTI_ICORRECT_C0 * 100 + CENTI_ICORRECT_C1 * msoc;
+	divisor = ibatt_avg * divisor / 100;
+	divisor = max(100, divisor);
+	*val = act_cap_mah * msoc * HOURS_TO_SECONDS / divisor;
 	return 0;
 }
 
@@ -3118,6 +3291,67 @@
 	fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n");
 	return 0;
 }
+
+static void ttf_work(struct work_struct *work)
+{
+	struct fg_chip *chip = container_of(work, struct fg_chip,
+					    ttf_work.work);
+	int rc, ibatt_now, vbatt_now, ttf;
+	ktime_t ktime_now;
+
+	mutex_lock(&chip->ttf.lock);
+	if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
+			chip->charge_status != POWER_SUPPLY_STATUS_DISCHARGING)
+		goto end_work;
+
+	rc = fg_get_battery_current(chip, &ibatt_now);
+	if (rc < 0) {
+		pr_err("failed to get battery current, rc=%d\n", rc);
+		goto end_work;
+	}
+
+	rc = fg_get_battery_voltage(chip, &vbatt_now);
+	if (rc < 0) {
+		pr_err("failed to get battery voltage, rc=%d\n", rc);
+		goto end_work;
+	}
+
+	fg_circ_buf_add(&chip->ttf.ibatt, ibatt_now);
+	fg_circ_buf_add(&chip->ttf.vbatt, vbatt_now);
+
+	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING) {
+		rc = fg_get_time_to_full_locked(chip, &ttf);
+		if (rc < 0) {
+			pr_err("failed to get ttf, rc=%d\n", rc);
+			goto end_work;
+		}
+
+		/* keep the wake lock and prime the IBATT and VBATT buffers */
+		if (ttf < 0) {
+			/* delay for one FG cycle */
+			schedule_delayed_work(&chip->ttf_work,
+							msecs_to_jiffies(1500));
+			mutex_unlock(&chip->ttf.lock);
+			return;
+		}
+
+		/* update the TTF reference point every minute */
+		ktime_now = ktime_get_boottime();
+		if (ktime_ms_delta(ktime_now,
+				   ms_to_ktime(chip->ttf.last_ms)) > 60000 ||
+				   chip->ttf.last_ms == 0) {
+			chip->ttf.last_ttf = ttf;
+			chip->ttf.last_ms = ktime_to_ms(ktime_now);
+		}
+	}
+
+	/* recurse every 10 seconds */
+	schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(10000));
+end_work:
+	vote(chip->awake_votable, TTF_PRIMING, false, 0);
+	mutex_unlock(&chip->ttf.lock);
+}
+
 /* PSY CALLBACKS STAY HERE */
 
 static int fg_psy_get_property(struct power_supply *psy,
@@ -3194,6 +3428,20 @@
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 		rc = fg_get_sram_prop(chip, FG_SRAM_VBATT_FULL, &pval->intval);
 		break;
+	case POWER_SUPPLY_PROP_CC_STEP:
+		if ((chip->ttf.cc_step.sel >= 0) &&
+				(chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
+			pval->intval =
+				chip->ttf.cc_step.arr[chip->ttf.cc_step.sel];
+		} else {
+			pr_err("cc_step_sel is out of bounds [0, %d]\n",
+				chip->ttf.cc_step.sel);
+			return -EINVAL;
+		}
+		break;
+	case POWER_SUPPLY_PROP_CC_STEP_SEL:
+		pval->intval = chip->ttf.cc_step.sel;
+		break;
 	default:
 		pr_err("unsupported property %d\n", psp);
 		rc = -EINVAL;
@@ -3232,6 +3480,26 @@
 	case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
 		rc = fg_prepare_for_qnovo(chip, pval->intval);
 		break;
+	case POWER_SUPPLY_PROP_CC_STEP:
+		if ((chip->ttf.cc_step.sel >= 0) &&
+				(chip->ttf.cc_step.sel < MAX_CC_STEPS)) {
+			chip->ttf.cc_step.arr[chip->ttf.cc_step.sel] =
+								pval->intval;
+		} else {
+			pr_err("cc_step_sel is out of bounds [0, %d]\n",
+				chip->ttf.cc_step.sel);
+			return -EINVAL;
+		}
+		break;
+	case POWER_SUPPLY_PROP_CC_STEP_SEL:
+		if ((pval->intval >= 0) && (pval->intval < MAX_CC_STEPS)) {
+			chip->ttf.cc_step.sel = pval->intval;
+		} else {
+			pr_err("cc_step_sel is out of bounds [0, %d]\n",
+				pval->intval);
+			return -EINVAL;
+		}
+		break;
 	default:
 		break;
 	}
@@ -3245,6 +3513,8 @@
 	switch (psp) {
 	case POWER_SUPPLY_PROP_CYCLE_COUNT_ID:
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_CC_STEP:
+	case POWER_SUPPLY_PROP_CC_STEP_SEL:
 		return 1;
 	default:
 		break;
@@ -3305,6 +3575,8 @@
 	POWER_SUPPLY_PROP_SOC_REPORTING_READY,
 	POWER_SUPPLY_PROP_DEBUG_BATTERY,
 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CC_STEP,
+	POWER_SUPPLY_PROP_CC_STEP_SEL,
 };
 
 static const struct power_supply_desc fg_psy_desc = {
@@ -3515,8 +3787,7 @@
 		return rc;
 	}
 
-	if (chip->cyc_ctr.en)
-		restore_cycle_counter(chip);
+	restore_cycle_counter(chip);
 
 	if (chip->dt.jeita_hyst_temp >= 0) {
 		val = chip->dt.jeita_hyst_temp << JEITA_TEMP_HYST_SHIFT;
@@ -3766,6 +4037,11 @@
 		if (rc < 0)
 			pr_err("Error in adjusting timebase, rc=%d\n", rc);
 
+		rc = fg_adjust_recharge_voltage(chip);
+		if (rc < 0)
+			pr_err("Error in adjusting recharge_voltage, rc=%d\n",
+				rc);
+
 		chip->last_batt_temp = batt_temp;
 		power_supply_changed(chip->batt_psy);
 	}
@@ -3813,8 +4089,7 @@
 	int rc;
 
 	fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
-	if (chip->cyc_ctr.en)
-		schedule_work(&chip->cycle_count_work);
+	fg_cycle_counter_update(chip);
 
 	if (chip->cl.active)
 		fg_cap_learning_update(chip);
@@ -4519,6 +4794,7 @@
 	chip->charge_status = -EINVAL;
 	chip->prev_charge_status = -EINVAL;
 	chip->ki_coeff_full_soc = -EINVAL;
+	chip->online_status = -EINVAL;
 	chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
 	if (!chip->regmap) {
 		dev_err(chip->dev, "Parent regmap is unavailable\n");
@@ -4587,15 +4863,14 @@
 	mutex_init(&chip->sram_rw_lock);
 	mutex_init(&chip->cyc_ctr.lock);
 	mutex_init(&chip->cl.lock);
-	mutex_init(&chip->batt_avg_lock);
+	mutex_init(&chip->ttf.lock);
 	mutex_init(&chip->charge_full_lock);
 	init_completion(&chip->soc_update);
 	init_completion(&chip->soc_ready);
 	init_completion(&chip->mem_grant);
 	INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
 	INIT_WORK(&chip->status_change_work, status_change_work);
-	INIT_WORK(&chip->cycle_count_work, cycle_count_work);
-	INIT_DELAYED_WORK(&chip->batt_avg_work, batt_avg_work);
+	INIT_DELAYED_WORK(&chip->ttf_work, ttf_work);
 	INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work);
 
 	rc = fg_memif_init(chip);
@@ -4692,7 +4967,7 @@
 	if (rc < 0)
 		pr_err("Error in configuring ESR timer, rc=%d\n", rc);
 
-	cancel_delayed_work_sync(&chip->batt_avg_work);
+	cancel_delayed_work_sync(&chip->ttf_work);
 	if (fg_sram_dump)
 		cancel_delayed_work_sync(&chip->sram_dump_work);
 	return 0;
@@ -4707,9 +4982,7 @@
 	if (rc < 0)
 		pr_err("Error in configuring ESR timer, rc=%d\n", rc);
 
-	fg_circ_buf_clr(&chip->ibatt_circ_buf);
-	fg_circ_buf_clr(&chip->vbatt_circ_buf);
-	schedule_delayed_work(&chip->batt_avg_work, 0);
+	schedule_delayed_work(&chip->ttf_work, 0);
 	if (fg_sram_dump)
 		schedule_delayed_work(&chip->sram_dump_work,
 				msecs_to_jiffies(fg_sram_dump_period_ms));
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index cf90f90..b208079 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -1396,6 +1396,17 @@
 	union power_supply_propval pval = {0};
 
 	/*
+	 * In some cases (esp shutting down) the userspace would  disable by
+	 * setting qnovo_enable=0. Also charger could be removed or there is
+	 * an error (i.e. its not okay to run qnovo)-
+	 * skip taking ESR measurement in such situations
+	 */
+
+	if (get_client_vote(chip->disable_votable, USER_VOTER)
+		|| get_effective_result(chip->not_ok_to_qnovo_votable) > 0)
+		return IRQ_HANDLED;
+
+	/*
 	 * hw resets pt_en bit once ptrain_done triggers.
 	 * vote on behalf of QNI to disable it such that
 	 * once QNI enables it, the votable state changes
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index faca084..60f5d23 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -900,6 +900,7 @@
 	POWER_SUPPLY_PROP_TEMP,
 	POWER_SUPPLY_PROP_TECHNOLOGY,
 	POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
+	POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
 	POWER_SUPPLY_PROP_CHARGE_DONE,
 	POWER_SUPPLY_PROP_PARALLEL_DISABLE,
 	POWER_SUPPLY_PROP_SET_SHIP_MODE,
@@ -962,6 +963,9 @@
 	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
 		val->intval = chg->step_chg_enabled;
 		break;
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+		val->intval = chg->sw_jeita_enabled;
+		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 		rc = smblib_get_prop_batt_voltage_now(chg, val);
 		break;
@@ -1081,6 +1085,13 @@
 	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
 		chg->step_chg_enabled = !!val->intval;
 		break;
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+		if (chg->sw_jeita_enabled != (!!val->intval)) {
+			rc = smblib_disable_hw_jeita(chg, !!val->intval);
+			if (rc == 0)
+				chg->sw_jeita_enabled = !!val->intval;
+		}
+		break;
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
 		chg->batt_profile_fcc_ua = val->intval;
 		vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
@@ -1123,6 +1134,7 @@
 	case POWER_SUPPLY_PROP_RERUN_AICL:
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
 	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
+	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
 		return 1;
 	default:
 		break;
@@ -1715,6 +1727,14 @@
 		}
 	}
 
+	if (chg->sw_jeita_enabled) {
+		rc = smblib_disable_hw_jeita(chg, true);
+		if (rc < 0) {
+			dev_err(chg->dev, "Couldn't set hw jeita rc=%d\n", rc);
+			return rc;
+		}
+	}
+
 	return rc;
 }
 
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 601f3e1..cc3bd93 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -2079,6 +2079,29 @@
 	return rc;
 }
 
+int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable)
+{
+	int rc;
+	u8 mask;
+
+	/*
+	 * Disable h/w base JEITA compensation if s/w JEITA is enabled
+	 */
+	mask = JEITA_EN_COLD_SL_FCV_BIT
+		| JEITA_EN_HOT_SL_FCV_BIT
+		| JEITA_EN_HOT_SL_CCC_BIT
+		| JEITA_EN_COLD_SL_CCC_BIT,
+	rc = smblib_masked_write(chg, JEITA_EN_CFG_REG, mask,
+			disable ? 0 : mask);
+	if (rc < 0) {
+		dev_err(chg->dev,
+			"Couldn't configure s/w jeita rc=%d\n",
+			rc);
+		return rc;
+	}
+	return 0;
+}
+
 /*******************
  * DC PSY GETTERS *
  *******************/
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 2746555..bfc5cae 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -508,6 +508,7 @@
 				union power_supply_propval *val);
 int smblib_icl_override(struct smb_charger *chg, bool override);
 int smblib_dp_dm(struct smb_charger *chg, int val);
+int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable);
 int smblib_rerun_aicl(struct smb_charger *chg);
 int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
 int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c
index 053aac3..06ecc7e 100644
--- a/drivers/power/supply/qcom/step-chg-jeita.c
+++ b/drivers/power/supply/qcom/step-chg-jeita.c
@@ -271,6 +271,13 @@
 	int rc = 0, fcc_ua = 0, fv_uv = 0;
 	u64 elapsed_us;
 
+	rc = power_supply_get_property(chip->batt_psy,
+		POWER_SUPPLY_PROP_SW_JEITA_ENABLED, &pval);
+	if (rc < 0)
+		chip->sw_jeita_enable = 0;
+	else
+		chip->sw_jeita_enable = pval.intval;
+
 	if (!chip->sw_jeita_enable) {
 		if (chip->fcc_votable)
 			vote(chip->fcc_votable, JEITA_VOTER, false, 0);
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index aef28db..0be35b3 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -24,6 +24,7 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/machine.h>
+#include <linux/qpnp/qpnp-revid.h>
 
 #define QPNP_LCDB_REGULATOR_DRIVER_NAME		"qcom,qpnp-lcdb-regulator"
 
@@ -146,6 +147,8 @@
 #define MIN_SOFT_START_US		0
 #define MAX_SOFT_START_US		2000
 
+#define BST_HEADROOM_DEFAULT_MV		200
+
 struct ldo_regulator {
 	struct regulator_desc		rdesc;
 	struct regulator_dev		*rdev;
@@ -186,12 +189,14 @@
 	int				soft_start_us;
 	int				vreg_ok_dbc_us;
 	int				voltage_mv;
+	u16				headroom_mv;
 };
 
 struct qpnp_lcdb {
 	struct device			*dev;
 	struct platform_device		*pdev;
 	struct regmap			*regmap;
+	struct pmic_revid_data		*pmic_rev_id;
 	u32				base;
 	int				sc_irq;
 
@@ -199,9 +204,6 @@
 	bool				ttw_enable;
 	bool				ttw_mode_sw;
 
-	/* top level DT params */
-	bool				force_module_reenable;
-
 	/* status parameters */
 	bool				lcdb_enabled;
 	bool				settings_saved;
@@ -579,6 +581,65 @@
 	return 0;
 }
 
+static int qpnp_lcdb_enable_wa(struct qpnp_lcdb *lcdb)
+{
+	int rc;
+	u8 val = 0;
+
+	/* required only for PM660L */
+	if (lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE)
+		return 0;
+
+	val = MODULE_EN_BIT;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+						&val, 1);
+	if (rc < 0) {
+		pr_err("Failed to enable lcdb rc= %d\n", rc);
+		return rc;
+	}
+
+	val = 0;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+							&val, 1);
+	if (rc < 0) {
+		pr_err("Failed to disable lcdb rc= %d\n", rc);
+		return rc;
+	}
+
+	/* execute the below for rev1.1 */
+	if (lcdb->pmic_rev_id->rev3 == PM660L_V1P1_REV3 &&
+		lcdb->pmic_rev_id->rev4 == PM660L_V1P1_REV4) {
+		/*
+		 * delay to make sure that the MID pin – ie the
+		 * output of the LCDB boost – returns to 0V
+		 * after the module is disabled
+		 */
+		usleep_range(10000, 10100);
+
+		rc = qpnp_lcdb_masked_write(lcdb,
+				lcdb->base + LCDB_MISC_CTL_REG,
+				DIS_SCP_BIT, DIS_SCP_BIT);
+		if (rc < 0) {
+			pr_err("Failed to disable SC rc=%d\n", rc);
+			return rc;
+		}
+		/* delay for SC-disable to take effect */
+		usleep_range(1000, 1100);
+
+		rc = qpnp_lcdb_masked_write(lcdb,
+				lcdb->base + LCDB_MISC_CTL_REG,
+				DIS_SCP_BIT, 0);
+		if (rc < 0) {
+			pr_err("Failed to enable SC rc=%d\n", rc);
+			return rc;
+		}
+		/* delay for SC-enable to take effect */
+		usleep_range(1000, 1100);
+	}
+
+	return 0;
+}
+
 static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb)
 {
 	int rc = 0, timeout, delay;
@@ -598,31 +659,20 @@
 		}
 	}
 
+	rc = qpnp_lcdb_enable_wa(lcdb);
+	if (rc < 0) {
+		pr_err("Failed to execute enable_wa rc=%d\n", rc);
+		return rc;
+	}
+
 	val = MODULE_EN_BIT;
 	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
 							&val, 1);
 	if (rc < 0) {
-		pr_err("Failed to enable lcdb rc= %d\n", rc);
+		pr_err("Failed to disable lcdb rc= %d\n", rc);
 		goto fail_enable;
 	}
 
-	if (lcdb->force_module_reenable) {
-		val = 0;
-		rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
-								&val, 1);
-		if (rc < 0) {
-			pr_err("Failed to enable lcdb rc= %d\n", rc);
-			goto fail_enable;
-		}
-		val = MODULE_EN_BIT;
-		rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
-								&val, 1);
-		if (rc < 0) {
-			pr_err("Failed to disable lcdb rc= %d\n", rc);
-			goto fail_enable;
-		}
-	}
-
 	/* poll for vreg_ok */
 	timeout = 10;
 	delay = lcdb->bst.soft_start_us + lcdb->ldo.soft_start_us +
@@ -806,28 +856,40 @@
 #define VOLTAGE_STEP_50_MV			50
 #define VOLTAGE_STEP_50MV_OFFSET		0xA
 static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb,
-					int voltage_mv)
+					int voltage_mv, u8 type)
 {
 	int rc = 0;
 	u8 val = 0;
+	int bst_voltage_mv;
+	struct ldo_regulator *ldo = &lcdb->ldo;
+	struct ncp_regulator *ncp = &lcdb->ncp;
+	struct bst_params *bst = &lcdb->bst;
 
-	if (voltage_mv < MIN_BST_VOLTAGE_MV)
-		voltage_mv = MIN_BST_VOLTAGE_MV;
-	else if (voltage_mv > MAX_BST_VOLTAGE_MV)
-		voltage_mv = MAX_BST_VOLTAGE_MV;
+	/* Vout_Boost = headroom_mv + max( Vout_LDO, abs (Vout_NCP)) */
+	bst_voltage_mv = max(voltage_mv, max(ldo->voltage_mv, ncp->voltage_mv));
+	bst_voltage_mv += bst->headroom_mv;
 
-	val = DIV_ROUND_UP(voltage_mv - MIN_BST_VOLTAGE_MV,
-					VOLTAGE_STEP_50_MV);
+	if (bst_voltage_mv < MIN_BST_VOLTAGE_MV)
+		bst_voltage_mv = MIN_BST_VOLTAGE_MV;
+	else if (bst_voltage_mv > MAX_BST_VOLTAGE_MV)
+		bst_voltage_mv = MAX_BST_VOLTAGE_MV;
 
-	rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
-				LCDB_BST_OUTPUT_VOLTAGE_REG,
-				SET_OUTPUT_VOLTAGE_MASK, val);
-	if (rc < 0)
-		pr_err("Failed to set boost voltage %d mv rc=%d\n",
-			voltage_mv, rc);
-	else
-		pr_debug("Boost voltage set = %d mv (0x%02x = 0x%02x)\n",
-			voltage_mv, LCDB_BST_OUTPUT_VOLTAGE_REG, val);
+	if (bst_voltage_mv != bst->voltage_mv) {
+		val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV,
+						VOLTAGE_STEP_50_MV);
+
+		rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
+					LCDB_BST_OUTPUT_VOLTAGE_REG,
+					SET_OUTPUT_VOLTAGE_MASK, val);
+		if (rc < 0) {
+			pr_err("Failed to set boost voltage %d mv rc=%d\n",
+				bst_voltage_mv, rc);
+		} else {
+			pr_debug("Boost voltage set = %d mv (0x%02x = 0x%02x)\n",
+			      bst_voltage_mv, LCDB_BST_OUTPUT_VOLTAGE_REG, val);
+			bst->voltage_mv = bst_voltage_mv;
+		}
+	}
 
 	return rc;
 }
@@ -858,25 +920,16 @@
 	u16 offset = LCDB_LDO_OUTPUT_VOLTAGE_REG;
 	u8 val = 0;
 
-	if (type == BST)
-		return qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv);
-
-	if (type == NCP)
-		offset = LCDB_NCP_OUTPUT_VOLTAGE_REG;
-
 	if (!is_between(voltage_mv, MIN_VOLTAGE_MV, MAX_VOLTAGE_MV)) {
 		pr_err("Invalid voltage %dmv (min=%d max=%d)\n",
 			voltage_mv, MIN_VOLTAGE_MV, MAX_VOLTAGE_MV);
 		return -EINVAL;
 	}
 
-	/* Change the BST voltage to LDO + 100mV */
-	if (type == LDO) {
-		rc = qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv + 100);
-		if (rc < 0) {
-			pr_err("Failed to set boost voltage rc=%d\n", rc);
-			return rc;
-		}
+	rc = qpnp_lcdb_set_bst_voltage(lcdb, voltage_mv, type);
+	if (rc < 0) {
+		pr_err("Failed to set boost voltage rc=%d\n", rc);
+		return rc;
 	}
 
 	/* Below logic is only valid for LDO and NCP type */
@@ -889,6 +942,9 @@
 		val += VOLTAGE_STEP_50MV_OFFSET;
 	}
 
+	if (type == NCP)
+		offset = LCDB_NCP_OUTPUT_VOLTAGE_REG;
+
 	rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + offset,
 				SET_OUTPUT_VOLTAGE_MASK, val);
 	if (rc < 0)
@@ -1011,6 +1067,8 @@
 	rc = qpnp_lcdb_set_voltage(lcdb, min_uV / 1000, LDO);
 	if (rc < 0)
 		pr_err("Failed to set LDO voltage rc=%c\n", rc);
+	else
+		lcdb->ldo.voltage_mv = min_uV / 1000;
 
 	return rc;
 }
@@ -1082,6 +1140,8 @@
 	rc = qpnp_lcdb_set_voltage(lcdb, min_uV / 1000, NCP);
 	if (rc < 0)
 		pr_err("Failed to set LDO voltage rc=%c\n", rc);
+	else
+		lcdb->ncp.voltage_mv = min_uV / 1000;
 
 	return rc;
 }
@@ -1342,6 +1402,12 @@
 		return -EINVAL;
 	}
 
+	/* Boost head room configuration */
+	of_property_read_u16(node, "qcom,bst-headroom-mv",
+					&lcdb->bst.headroom_mv);
+	if (lcdb->bst.headroom_mv < BST_HEADROOM_DEFAULT_MV)
+		lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
+
 	return 0;
 }
 
@@ -1648,6 +1714,9 @@
 	}
 	lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200	+ 200;
 
+	if (!lcdb->bst.headroom_mv)
+		lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
+
 	return 0;
 }
 
@@ -1674,7 +1743,8 @@
 		return rc;
 	}
 
-	if (lcdb->sc_irq >= 0) {
+	if (lcdb->sc_irq >= 0 &&
+		lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) {
 		lcdb->sc_count = 0;
 		rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq,
 				NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT,
@@ -1714,8 +1784,26 @@
 {
 	int rc = 0;
 	const char *label;
-	struct device_node *temp, *node = lcdb->dev->of_node;
+	struct device_node *revid_dev_node, *temp, *node = lcdb->dev->of_node;
 
+	revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
+	if (!revid_dev_node) {
+		pr_err("Missing qcom,pmic-revid property - fail driver\n");
+		return -EINVAL;
+	}
+
+	lcdb->pmic_rev_id = get_revid_data(revid_dev_node);
+	if (IS_ERR(lcdb->pmic_rev_id)) {
+		pr_debug("Unable to get revid data\n");
+		/*
+		 * revid should to be defined, return -EPROBE_DEFER
+		 * until the revid module registers.
+		 */
+		of_node_put(revid_dev_node);
+		return -EPROBE_DEFER;
+	}
+
+	of_node_put(revid_dev_node);
 	for_each_available_child_of_node(node, temp) {
 		rc = of_property_read_string(temp, "label", &label);
 		if (rc < 0) {
@@ -1742,9 +1830,6 @@
 		}
 	}
 
-	lcdb->force_module_reenable = of_property_read_bool(node,
-					"qcom,force-module-reenable");
-
 	if (of_property_read_bool(node, "qcom,ttw-enable")) {
 		rc = qpnp_lcdb_parse_ttw(lcdb);
 		if (rc < 0) {
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 38eff96..d1f717b 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -753,6 +753,15 @@
 
 source "drivers/soc/qcom/memshare/Kconfig"
 
+config MSM_REMOTEQDSS
+	bool "Allow debug tools to enable events on other processors"
+	depends on QCOM_SCM && DEBUG_FS
+	help
+	  Other onchip processors/execution environments may support debug
+	  events. Provide a sysfs interface for debug tools to dynamically
+	  enable/disable these events. Interface located in
+	  /sys/class/remoteqdss.
+
 config QSEE_IPC_IRQ_BRIDGE
 	tristate "QSEE IPC Interrupt Bridge"
 	help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 2d7d62a..567493d 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -79,4 +79,5 @@
 obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o
 obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
 obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o
+obj-$(CONFIG_MSM_REMOTEQDSS) += remoteqdss.o
 obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index a2ab266..dc891eb 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -292,6 +292,7 @@
 	ICNSS_WLFW_EXISTS,
 	ICNSS_SHUTDOWN_DONE,
 	ICNSS_HOST_TRIGGERED_PDR,
+	ICNSS_FW_DOWN,
 };
 
 struct ce_irq_list {
@@ -1946,6 +1947,12 @@
 
 	icnss_pr_dbg("Received Ind 0x%x, msg_len: %d\n", msg_id, msg_len);
 
+	if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
+		icnss_pr_dbg("FW down, ignoring 0x%x, state: 0x%lx\n",
+				msg_id, penv->state);
+		return;
+	}
+
 	switch (msg_id) {
 	case QMI_WLFW_FW_READY_IND_V01:
 		icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_READY_IND,
@@ -1992,6 +1999,7 @@
 		return -ENODEV;
 
 	set_bit(ICNSS_WLFW_EXISTS, &penv->state);
+	clear_bit(ICNSS_FW_DOWN, &penv->state);
 
 	penv->wlfw_clnt = qmi_handle_create(icnss_qmi_wlfw_clnt_notify, penv);
 	if (!penv->wlfw_clnt) {
@@ -2492,6 +2500,8 @@
 	icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n",
 		      priv->state, notif->crashed);
 
+	set_bit(ICNSS_FW_DOWN, &priv->state);
+
 	if (notif->crashed)
 		priv->stats.recovery.root_pd_crash++;
 	else
@@ -2619,6 +2629,7 @@
 	icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n",
 		      *state, priv->state, icnss_pdr_cause[cause]);
 event_post:
+	set_bit(ICNSS_FW_DOWN, &priv->state);
 	icnss_ignore_qmi_timeout(true);
 	clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
 
@@ -2627,6 +2638,8 @@
 	icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
 				ICNSS_EVENT_SYNC, event_data);
 done:
+	if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01)
+		clear_bit(ICNSS_FW_DOWN, &priv->state);
 	return NOTIFY_OK;
 }
 
@@ -3834,6 +3847,9 @@
 		case ICNSS_HOST_TRIGGERED_PDR:
 			seq_puts(s, "HOST TRIGGERED PDR");
 			continue;
+		case ICNSS_FW_DOWN:
+			seq_puts(s, "FW DOWN");
+			continue;
 		}
 
 		seq_printf(s, "UNKNOWN-%d", i);
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
index aa6c5d7..bcaeca5 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_rpmh.c
@@ -1794,7 +1794,7 @@
 	int ret = 0;
 	char *test_cl = "test-client";
 	bool log_transaction = false;
-	u64 slp_ib, slp_ab;
+	u64 dual_ib, dual_ab, act_ib, act_ab;
 
 	rt_mutex_lock(&msm_bus_adhoc_lock);
 
@@ -1815,15 +1815,20 @@
 	}
 
 	if (cl->active_only) {
-		slp_ib = 0;
-		slp_ab = 0;
+		act_ib = ib;
+		act_ab = ab;
+		dual_ib = 0;
+		dual_ab = 0;
 	} else {
-		slp_ib = ib;
-		slp_ab = ab;
+		dual_ib = ib;
+		dual_ab = ab;
+		act_ib = 0;
+		act_ab = 0;
 	}
 
-	ret = update_path(cl->mas_dev, cl->slv, ib, ab, slp_ib, slp_ab,
-		cl->cur_act_ib, cl->cur_act_ab, cl->first_hop, cl->active_only);
+	ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, dual_ib,
+		dual_ab, cl->cur_act_ib, cl->cur_act_ab, cl->first_hop,
+							cl->active_only);
 
 	if (ret) {
 		MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
@@ -1832,10 +1837,10 @@
 	}
 
 	commit_data();
-	cl->cur_act_ib = ib;
-	cl->cur_act_ab = ab;
-	cl->cur_slp_ib = slp_ib;
-	cl->cur_slp_ab = slp_ab;
+	cl->cur_act_ib = act_ib;
+	cl->cur_act_ab = act_ab;
+	cl->cur_dual_ib = dual_ib;
+	cl->cur_dual_ab = dual_ab;
 
 	if (log_transaction)
 		getpath_debug(cl->mas, cl->first_hop, cl->active_only);
@@ -1847,7 +1852,7 @@
 }
 
 static int update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
-				u64 act_ib, u64 slp_ib, u64 slp_ab)
+				u64 act_ib, u64 dual_ib, u64 dual_ab)
 {
 	int ret = 0;
 
@@ -1860,18 +1865,18 @@
 
 	if ((cl->cur_act_ib == act_ib) &&
 		(cl->cur_act_ab == act_ab) &&
-		(cl->cur_slp_ib == slp_ib) &&
-		(cl->cur_slp_ab == slp_ab)) {
+		(cl->cur_dual_ib == dual_ib) &&
+		(cl->cur_dual_ab == dual_ab)) {
 		MSM_BUS_ERR("No change in vote");
 		goto exit_change_context;
 	}
 
-	if (!slp_ab && !slp_ib)
+	if (!dual_ab && !dual_ib)
 		cl->active_only = true;
-	msm_bus_dbg_rec_transaction(cl, cl->cur_act_ab, cl->cur_slp_ib);
-	ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, slp_ib, slp_ab,
-				cl->cur_act_ab, cl->cur_act_ab,  cl->first_hop,
-				cl->active_only);
+	msm_bus_dbg_rec_transaction(cl, cl->cur_act_ab, cl->cur_dual_ib);
+	ret = update_path(cl->mas_dev, cl->slv, act_ib, act_ab, dual_ib,
+				dual_ab, cl->cur_act_ab, cl->cur_act_ab,
+				cl->first_hop, cl->active_only);
 	if (ret) {
 		MSM_BUS_ERR("%s: Update path failed! %d active_only %d\n",
 				__func__, ret, cl->active_only);
@@ -1880,8 +1885,8 @@
 	commit_data();
 	cl->cur_act_ib = act_ib;
 	cl->cur_act_ab = act_ab;
-	cl->cur_slp_ib = slp_ib;
-	cl->cur_slp_ab = slp_ab;
+	cl->cur_dual_ib = dual_ib;
+	cl->cur_dual_ab = dual_ab;
 //	trace_bus_update_request_end(cl->name);
 exit_change_context:
 	rt_mutex_unlock(&msm_bus_adhoc_lock);
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_client_api.c b/drivers/soc/qcom/msm_bus/msm_bus_client_api.c
index b6595a2..14583cb 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_client_api.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_client_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -142,17 +142,17 @@
  * act_ab: The average bandwidth(AB) in Bytes/s to be used in active context.
  * act_ib: The instantaneous bandwidth(IB) in Bytes/s to be used in active
  *         context.
- * slp_ib: The average bandwidth(AB) in Bytes/s to be used in dual context.
- * slp_ab: The instantaneous bandwidth(IB) in Bytes/s to be used in dual
+ * dual_ib: The average bandwidth(AB) in Bytes/s to be used in dual context.
+ * dual_ab: The instantaneous bandwidth(IB) in Bytes/s to be used in dual
  *         context.
  */
 int
 msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
-				u64 act_ib, u64 slp_ib, u64 slp_ab)
+				u64 act_ib, u64 dual_ib, u64 dual_ab)
 {
 	if (arb_ops.update_context)
 		return arb_ops.update_bw_context(cl, act_ab, act_ib,
-							slp_ab, slp_ib);
+							dual_ab, dual_ib);
 
 	return -EPROBE_DEFER;
 }
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_core.h b/drivers/soc/qcom/msm_bus/msm_bus_core.h
index 4911cf2..ee67ac0 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_core.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_core.h
@@ -68,7 +68,7 @@
 	int (*update_bw)(struct msm_bus_client_handle *cl, u64 ab, u64 ib);
 	void (*unregister)(struct msm_bus_client_handle *cl);
 	int (*update_bw_context)(struct msm_bus_client_handle *cl, u64 act_ab,
-				u64 act_ib, u64 slp_ib, u64 slp_ab);
+				u64 act_ib, u64 dual_ib, u64 dual_ab);
 	int (*query_usecase)(struct msm_bus_tcs_usecase *tcs_usecase,
 				uint32_t cl, unsigned int index);
 	int (*query_usecase_all)(struct msm_bus_tcs_handle *tcs_handle,
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index e45f61e..de89b8f 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -821,6 +821,7 @@
 	uint16_t clnt;
 	int i, j;
 
+	memset(&data, 0, sizeof(data));
 	data.opcode = RESET_EVENTS;
 	data.reset_event = code;
 
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 92a97fae..9f12564a 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -239,7 +239,7 @@
 			      int num_of_intents, uint32_t size)
 {
 	int i;
-	int rc;
+	int rc = 0;
 
 	if (!apr_ch || !num_of_intents || !size) {
 		pr_err("%s: Invalid parameter\n", __func__);
diff --git a/drivers/soc/qcom/remoteqdss.c b/drivers/soc/qcom/remoteqdss.c
new file mode 100644
index 0000000..9a668c0
--- /dev/null
+++ b/drivers/soc/qcom/remoteqdss.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <soc/qcom/scm.h>
+#include <linux/debugfs.h>
+#include <linux/ratelimit.h>
+#include <linux/dma-mapping.h>
+
+#define REMOTEQDSS_FLAG_QUIET (BIT(0))
+
+static unsigned long remoteqdss_dbg_flags;
+module_param_named(dbg_flags, remoteqdss_dbg_flags, ulong, 0644);
+
+static struct dentry *remoteqdss_dir;
+
+#define REMOTEQDSS_ERR(fmt, ...) \
+	pr_debug("%s: " fmt, __func__, ## __VA_ARGS__)
+
+#define REMOTEQDSS_ERR_CALLER(fmt, caller, ...) \
+	pr_debug("%pf: " fmt, caller, ## __VA_ARGS__)
+
+struct qdss_msg_translation {
+	u64 val;
+	char *msg;
+};
+
+/*
+ * id			Unique identifier
+ * sw_entity_group	Array index
+ * sw_event_group	Array index
+ * dir			Parent debugfs directory
+ */
+struct remoteqdss_data {
+	uint32_t id;
+	uint32_t sw_entity_group;
+	uint32_t sw_event_group;
+	struct dentry *dir;
+};
+
+static struct device dma_dev;
+
+/* Allowed message formats */
+
+enum remoteqdss_cmd_id {
+	CMD_ID_QUERY_SWEVENT_TAG,
+	CMD_ID_FILTER_SWTRACE_STATE,
+	CMD_ID_QUERY_SWTRACE_STATE,
+	CMD_ID_FILTER_SWEVENT,
+	CMD_ID_QUERY_SWEVENT,
+	CMD_ID_FILTER_SWENTITY,
+	CMD_ID_QUERY_SWENTITY,
+};
+
+struct remoteqdss_header_fmt {
+	uint32_t subsys_id;
+	uint32_t cmd_id;
+};
+
+struct remoteqdss_filter_swtrace_state_fmt {
+	struct remoteqdss_header_fmt h;
+	uint32_t state;
+};
+
+struct remoteqdss_filter_swevent_fmt {
+	struct remoteqdss_header_fmt h;
+	uint32_t event_group;
+	uint32_t event_mask;
+};
+
+struct remoteqdss_query_swevent_fmt {
+	struct remoteqdss_header_fmt h;
+	uint32_t event_group;
+};
+
+struct remoteqdss_filter_swentity_fmt {
+	struct remoteqdss_header_fmt h;
+	uint32_t entity_group;
+	uint32_t entity_mask;
+};
+
+struct remoteqdss_query_swentity_fmt {
+	struct remoteqdss_header_fmt h;
+	uint32_t entity_group;
+};
+
+/* msgs is a null terminated array */
+static void remoteqdss_err_translation(struct qdss_msg_translation *msgs,
+					u64 err, const void *caller)
+{
+	static DEFINE_RATELIMIT_STATE(rl, 5 * HZ, 2);
+	struct qdss_msg_translation *msg;
+
+	if (!err)
+		return;
+
+	if (remoteqdss_dbg_flags & REMOTEQDSS_FLAG_QUIET)
+		return;
+
+	for (msg = msgs; msg->msg; msg++) {
+		if (err == msg->val && __ratelimit(&rl)) {
+			REMOTEQDSS_ERR_CALLER("0x%llx: %s\n", caller, err,
+						msg->msg);
+			return;
+		}
+	}
+
+	REMOTEQDSS_ERR_CALLER("Error 0x%llx\n", caller, err);
+}
+
+/* Shared across all remoteqdss scm functions */
+#define SCM_CMD_ID (0x1)
+
+/* Response Values */
+#define SCM_CMD_FAIL		(0x80)
+#define SCM_QDSS_UNAVAILABLE	(0x81)
+#define SCM_UNINITIALIZED	(0x82)
+#define SCM_BAD_ARG		(0x83)
+#define SCM_BAD_SUBSYS		(0x85)
+
+static struct qdss_msg_translation remoteqdss_scm_msgs[] = {
+	{SCM_CMD_FAIL,
+		"Command failed"},
+	{SCM_QDSS_UNAVAILABLE,
+		"QDSS not available or cannot turn QDSS (clock) on"},
+	{SCM_UNINITIALIZED,
+		"Tracer not initialized or unable to initialize"},
+	{SCM_BAD_ARG,
+		"Invalid parameter value"},
+	{SCM_BAD_SUBSYS,
+		"Incorrect subsys ID"},
+	{}
+};
+
+static struct remoteqdss_data *create_remoteqdss_data(u32 id)
+{
+	struct remoteqdss_data *data;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	data->id = id;
+	return data;
+}
+
+static void free_remoteqdss_data(struct remoteqdss_data *data)
+{
+	kfree(data);
+}
+
+static int remoteqdss_do_scm_call(struct scm_desc *desc,
+		dma_addr_t addr, size_t size, const void *caller)
+{
+	int ret;
+
+	memset(desc, 0, sizeof(*desc));
+	desc->args[0] = dma_to_phys(&dma_dev, addr);
+	desc->args[1] = size;
+	desc->arginfo = SCM_ARGS(2, SCM_RO, SCM_VAL);
+
+	ret = scm_call2(
+		SCM_SIP_FNID(SCM_SVC_QDSS, SCM_CMD_ID),
+		desc);
+	if (ret)
+		return ret;
+
+	remoteqdss_err_translation(remoteqdss_scm_msgs, desc->ret[0], caller);
+	ret = desc->ret[0] ? -EINVAL : 0;
+	return ret;
+}
+
+static int remoteqdss_scm_query_swtrace(void *priv, u64 *val)
+{
+	struct remoteqdss_data *data = priv;
+	int ret;
+	struct scm_desc desc;
+	struct remoteqdss_header_fmt *fmt;
+	dma_addr_t addr;
+
+	fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+	if (!fmt)
+		return -ENOMEM;
+	fmt->subsys_id = data->id;
+	fmt->cmd_id = CMD_ID_QUERY_SWTRACE_STATE;
+
+	ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+					__builtin_return_address(0));
+	*val = desc.ret[1];
+
+	dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+	return ret;
+}
+
+static int remoteqdss_scm_filter_swtrace(void *priv, u64 val)
+{
+	struct remoteqdss_data *data = priv;
+	int ret;
+	struct scm_desc desc;
+	struct remoteqdss_filter_swtrace_state_fmt *fmt;
+	dma_addr_t addr;
+
+	fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+	if (!fmt)
+		return -ENOMEM;
+	fmt->h.subsys_id = data->id;
+	fmt->h.cmd_id = CMD_ID_FILTER_SWTRACE_STATE;
+	fmt->state = (uint32_t)val;
+
+	ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+					__builtin_return_address(0));
+
+	dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+	return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_sw_trace_output,
+			remoteqdss_scm_query_swtrace,
+			remoteqdss_scm_filter_swtrace,
+			"0x%llx\n");
+
+static int remoteqdss_scm_query_tag(void *priv, u64 *val)
+{
+	struct remoteqdss_data *data = priv;
+	int ret;
+	struct scm_desc desc;
+	struct remoteqdss_header_fmt *fmt;
+	dma_addr_t addr;
+
+	fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+	if (!fmt)
+		return -ENOMEM;
+	fmt->subsys_id = data->id;
+	fmt->cmd_id = CMD_ID_QUERY_SWEVENT_TAG;
+
+	ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+					__builtin_return_address(0));
+	*val = desc.ret[1];
+
+	dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+	return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_tag,
+			remoteqdss_scm_query_tag,
+			NULL,
+			"0x%llx\n");
+
+static int remoteqdss_scm_query_swevent(void *priv, u64 *val)
+{
+	struct remoteqdss_data *data = priv;
+	int ret;
+	struct scm_desc desc;
+	struct remoteqdss_query_swevent_fmt *fmt;
+	dma_addr_t addr;
+
+	fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+	if (!fmt)
+		return -ENOMEM;
+	fmt->h.subsys_id = data->id;
+	fmt->h.cmd_id = CMD_ID_QUERY_SWEVENT;
+	fmt->event_group = data->sw_event_group;
+
+	ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+					__builtin_return_address(0));
+	*val = desc.ret[1];
+
+	dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+	return ret;
+}
+
+static int remoteqdss_scm_filter_swevent(void *priv, u64 val)
+{
+	struct remoteqdss_data *data = priv;
+	int ret;
+	struct scm_desc desc;
+	struct remoteqdss_filter_swevent_fmt *fmt;
+	dma_addr_t addr;
+
+	fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+	if (!fmt)
+		return -ENOMEM;
+	fmt->h.subsys_id = data->id;
+	fmt->h.cmd_id = CMD_ID_FILTER_SWEVENT;
+	fmt->event_group = data->sw_event_group;
+	fmt->event_mask = (uint32_t)val;
+
+	ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+					__builtin_return_address(0));
+
+	dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+	return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_swevent,
+			remoteqdss_scm_query_swevent,
+			remoteqdss_scm_filter_swevent,
+			"0x%llx\n");
+
+static int remoteqdss_scm_query_swentity(void *priv, u64 *val)
+{
+	struct remoteqdss_data *data = priv;
+	int ret;
+	struct scm_desc desc;
+	struct remoteqdss_query_swentity_fmt *fmt;
+	dma_addr_t addr;
+
+	fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+	if (!fmt)
+		return -ENOMEM;
+	fmt->h.subsys_id = data->id;
+	fmt->h.cmd_id = CMD_ID_QUERY_SWENTITY;
+	fmt->entity_group = data->sw_entity_group;
+
+	ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+					__builtin_return_address(0));
+	*val = desc.ret[1];
+
+	dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+	return ret;
+}
+
+static int remoteqdss_scm_filter_swentity(void *priv, u64 val)
+{
+	struct remoteqdss_data *data = priv;
+	int ret;
+	struct scm_desc desc;
+	struct remoteqdss_filter_swentity_fmt *fmt;
+	dma_addr_t addr;
+
+	fmt = dma_alloc_coherent(&dma_dev, sizeof(*fmt), &addr, GFP_KERNEL);
+	if (!fmt)
+		return -ENOMEM;
+	fmt->h.subsys_id = data->id;
+	fmt->h.cmd_id = CMD_ID_FILTER_SWENTITY;
+	fmt->entity_group = data->sw_entity_group;
+	fmt->entity_mask = (uint32_t)val;
+
+	ret = remoteqdss_do_scm_call(&desc, addr, sizeof(*fmt),
+					__builtin_return_address(0));
+
+	dma_free_coherent(&dma_dev, sizeof(*fmt), fmt, addr);
+	return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_swentity,
+			remoteqdss_scm_query_swentity,
+			remoteqdss_scm_filter_swentity,
+			"0x%llx\n");
+
+static void __init enumerate_scm_devices(struct dentry *parent)
+{
+	u64 unused;
+	int ret;
+	struct remoteqdss_data *data;
+	struct dentry *dentry;
+
+	if (!is_scm_armv8())
+		return;
+
+	data = create_remoteqdss_data(0);
+	if (!data)
+		return;
+
+	/* Assume failure means device not present */
+	ret = remoteqdss_scm_query_swtrace(data, &unused);
+	if (ret)
+		goto out;
+
+	data->dir = debugfs_create_dir("tz", parent);
+	if (IS_ERR_OR_NULL(data->dir))
+		goto out;
+
+	dentry = debugfs_create_file("sw_trace_output", 0644,
+			data->dir, data, &fops_sw_trace_output);
+	if (IS_ERR_OR_NULL(dentry))
+		goto out;
+
+	dentry = debugfs_create_u32("sw_entity_group", 0644,
+			data->dir, &data->sw_entity_group);
+	if (IS_ERR_OR_NULL(dentry))
+		goto out;
+
+	dentry = debugfs_create_u32("sw_event_group", 0644,
+			data->dir, &data->sw_event_group);
+	if (IS_ERR_OR_NULL(dentry))
+		goto out;
+
+	dentry = debugfs_create_file("tag", 0444,
+			data->dir, data, &fops_tag);
+	if (IS_ERR_OR_NULL(dentry))
+		goto out;
+
+	dentry = debugfs_create_file("swevent", 0644,
+			data->dir, data, &fops_swevent);
+	if (IS_ERR_OR_NULL(dentry))
+		goto out;
+
+	dentry = debugfs_create_file("swentity", 0644,
+			data->dir, data, &fops_swentity);
+	if (IS_ERR_OR_NULL(dentry))
+		goto out;
+
+	return;
+
+out:
+	debugfs_remove_recursive(data->dir);
+	free_remoteqdss_data(data);
+}
+
+static int __init remoteqdss_init(void)
+{
+	unsigned long old_flags = remoteqdss_dbg_flags;
+	int ret;
+
+	/* Set up DMA */
+	arch_setup_dma_ops(&dma_dev, 0, U64_MAX, NULL, false);
+	ret = dma_coerce_mask_and_coherent(&dma_dev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	/*
+	 * disable normal error messages while checking
+	 * if support is present.
+	 */
+	remoteqdss_dbg_flags |= REMOTEQDSS_FLAG_QUIET;
+
+	remoteqdss_dir = debugfs_create_dir("remoteqdss", NULL);
+	if (!remoteqdss_dir)
+		return 0;
+
+	enumerate_scm_devices(remoteqdss_dir);
+
+	remoteqdss_dbg_flags = old_flags;
+	return 0;
+}
+late_initcall(remoteqdss_init);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 8580484..8a7043a6 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -845,6 +845,28 @@
 }
 EXPORT_SYMBOL(rpmh_read);
 
+/**
+ * rpmh_ctrlr_idle: Check if the controller is idle
+ *
+ * @rc: The RPMH handle got from rpmh_get_dev_channel
+ *
+ * Returns if the controller is idle or not.
+ */
+int rpmh_ctrlr_idle(struct rpmh_client *rc)
+{
+	if (IS_ERR_OR_NULL(rc))
+		return -EINVAL;
+
+	if (rpmh_standalone)
+		return 0;
+
+	if (!mbox_controller_is_idle(rc->chan))
+		return -EBUSY;
+
+	return 0;
+}
+EXPORT_SYMBOL(rpmh_ctrlr_idle);
+
 static inline int is_req_valid(struct rpmh_req *req)
 {
 	return (req->sleep_val != UINT_MAX && req->wake_val != UINT_MAX
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index f4f4c36..2ecbf15 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 
 #include <soc/qcom/rpmh.h>
+#include <soc/qcom/system_pm.h>
 
 #define ARCH_TIMER_HZ		(19200000UL)
 #define PDC_TIME_VALID_SHIFT	31
@@ -34,6 +35,15 @@
 }
 
 /**
+ * system_sleep_allowed() - Returns if its okay to enter system low power modes
+ */
+bool system_sleep_allowed(void)
+{
+	return (rpmh_ctrlr_idle(rpmh_client) == 0);
+}
+EXPORT_SYMBOL(system_sleep_allowed);
+
+/**
  * system_sleep_enter() - Activties done when entering system low power modes
  *
  * @sleep_val: The sleep duration in us.
diff --git a/drivers/soundwire/soundwire.c b/drivers/soundwire/soundwire.c
index f0c7aa9..16b16e5e 100644
--- a/drivers/soundwire/soundwire.c
+++ b/drivers/soundwire/soundwire.c
@@ -79,11 +79,16 @@
 {
 	struct swr_device *swr_dev_loop, *safe;
 
+	/*
+	 * master still has reference to all nodes and deletes
+	 * at platform_unregister, so need to init the deleted
+	 * entry
+	 */
 	list_for_each_entry_safe(swr_dev_loop, safe,
 				 &swr_dev->master->devices,
 				 dev_list) {
 		if (swr_dev == swr_dev_loop)
-			list_del(&swr_dev_loop->dev_list);
+			list_del_init(&swr_dev_loop->dev_list);
 	}
 }
 EXPORT_SYMBOL(swr_remove_device);
@@ -789,9 +794,7 @@
 
 static void swr_master_release(struct device *dev)
 {
-	struct swr_master *master = to_swr_master(dev);
-
-	kfree(master);
+	/* kfree of master done at swrm_remove of device */
 }
 
 #define swr_master_attr_gr NULL
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 55b1a0e..453a63f 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -409,6 +409,8 @@
 # define DP_TEST_LINK_EDID_READ		    (1 << 2)
 # define DP_TEST_LINK_PHY_TEST_PATTERN	    (1 << 3) /* DPCD >= 1.1 */
 # define DP_TEST_LINK_FAUX_PATTERN	    (1 << 4) /* DPCD >= 1.2 */
+# define DP_TEST_LINK_AUDIO_PATTERN     (1 << 5)
+# define DP_TEST_LINK_AUDIO_DISABLED_VIDEO (1 << 6)
 
 #define DP_TEST_LINK_RATE		    0x219
 # define DP_LINK_RATE_162		    (0x6)
@@ -417,6 +419,63 @@
 #define DP_TEST_LANE_COUNT		    0x220
 
 #define DP_TEST_PATTERN			    0x221
+# define DP_NO_TEST_PATTERN                 0x0
+# define DP_COLOR_RAMP                      0x1
+# define DP_BLACK_AND_WHITE_VERTICAL_LINES  0x2
+# define DP_COLOR_SQUARE                    0x3
+
+#define DP_TEST_H_TOTAL_HI                  0x222
+#define DP_TEST_H_TOTAL_LO                  0x223
+
+#define DP_TEST_V_TOTAL_HI                  0x224
+#define DP_TEST_V_TOTAL_LO                  0x225
+
+#define DP_TEST_H_START_HI                  0x226
+#define DP_TEST_H_START_LO                  0x227
+
+#define DP_TEST_V_START_HI                  0x228
+#define DP_TEST_V_START_LO                  0x229
+
+#define DP_TEST_HSYNC_HI                    0x22A
+# define DP_TEST_HSYNC_POLARITY             (1 << 7)
+# define DP_TEST_HSYNC_WIDTH_HI_MASK        (127 << 0)
+#define DP_TEST_HSYNC_WIDTH_LO              0x22B
+
+#define DP_TEST_VSYNC_HI                    0x22C
+# define DP_TEST_VSYNC_POLARITY             (1 << 7)
+# define DP_TEST_VSYNC_WIDTH_HI_MASK        (127 << 0)
+#define DP_TEST_VSYNC_WIDTH_LO              0x22D
+
+#define DP_TEST_H_WIDTH_HI                  0x22E
+#define DP_TEST_H_WIDTH_LO                  0x22F
+
+#define DP_TEST_V_HEIGHT_HI                 0x230
+#define DP_TEST_V_HEIGHT_LO                 0x231
+
+#define DP_TEST_MISC0                       0x232
+# define DP_TEST_SYNC_CLOCK                 (1 << 0)
+# define DP_TEST_COLOR_FORMAT_MASK          (3 << 1)
+# define DP_TEST_COLOR_FORMAT_SHIFT         1
+# define DP_COLOR_FORMAT_RGB                (0 << 1)
+# define DP_COLOR_FORMAT_YCbCr422           (1 << 1)
+# define DP_COLOR_FORMAT_YCbCr444           (2 << 1)
+# define DP_TEST_DYNAMIC_RANGE_CEA          (1 << 3)
+# define DP_TEST_YCBCR_COEFFICIENTS         (1 << 4)
+# define DP_YCBCR_COEFFICIENTS_ITU601       (0 << 4)
+# define DP_YCBCR_COEFFICIENTS_ITU709       (1 << 4)
+# define DP_TEST_BIT_DEPTH_MASK             (7 << 5)
+# define DP_TEST_BIT_DEPTH_SHIFT            5
+# define DP_TEST_BIT_DEPTH_6                (0 << 5)
+# define DP_TEST_BIT_DEPTH_8                (1 << 5)
+# define DP_TEST_BIT_DEPTH_10               (2 << 5)
+# define DP_TEST_BIT_DEPTH_12               (3 << 5)
+# define DP_TEST_BIT_DEPTH_16               (4 << 5)
+
+#define DP_TEST_MISC1                       0x233
+# define DP_TEST_REFRESH_DENOMINATOR        (1 << 0)
+# define DP_TEST_INTERLACED                 (1 << 1)
+
+#define DP_TEST_REFRESH_RATE_NUMERATOR      0x234
 
 #define DP_TEST_CRC_R_CR		    0x240
 #define DP_TEST_CRC_G_Y			    0x242
@@ -426,6 +485,14 @@
 # define DP_TEST_CRC_SUPPORTED		    (1 << 5)
 # define DP_TEST_COUNT_MASK		    0xf
 
+#define DP_TEST_PHY_PATTERN		    0x248
+# define DP_TEST_PHY_PATTERN_NONE			0x0
+# define DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING	0x1
+# define DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT 0x2
+# define DP_TEST_PHY_PATTERN_PRBS7			0x3
+# define DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN	0x4
+# define DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN	0x5
+
 #define DP_TEST_RESPONSE		    0x260
 # define DP_TEST_ACK			    (1 << 0)
 # define DP_TEST_NAK			    (1 << 1)
@@ -436,6 +503,19 @@
 #define DP_TEST_SINK			    0x270
 # define DP_TEST_SINK_START		    (1 << 0)
 
+#define DP_TEST_AUDIO_MODE		    0x271
+
+#define DP_TEST_AUDIO_PATTERN_TYPE	    0x272
+
+#define DP_TEST_AUDIO_PERIOD_CH1	    0x273
+#define DP_TEST_AUDIO_PERIOD_CH2	    0x274
+#define DP_TEST_AUDIO_PERIOD_CH3	    0x275
+#define DP_TEST_AUDIO_PERIOD_CH4	    0x276
+#define DP_TEST_AUDIO_PERIOD_CH5	    0x277
+#define DP_TEST_AUDIO_PERIOD_CH6	    0x278
+#define DP_TEST_AUDIO_PERIOD_CH7	    0x279
+#define DP_TEST_AUDIO_PERIOD_CH8	    0x27A
+
 #define DP_PAYLOAD_TABLE_UPDATE_STATUS      0x2c0   /* 1.2 MST */
 # define DP_PAYLOAD_TABLE_UPDATED           (1 << 0)
 # define DP_PAYLOAD_ACT_HANDLED             (1 << 1)
diff --git a/include/linux/msm-bus.h b/include/linux/msm-bus.h
index 26e948f..c298666 100644
--- a/include/linux/msm-bus.h
+++ b/include/linux/msm-bus.h
@@ -87,8 +87,8 @@
 	struct device *mas_dev;
 	u64 cur_act_ib;
 	u64 cur_act_ab;
-	u64 cur_slp_ib;
-	u64 cur_slp_ab;
+	u64 cur_dual_ib;
+	u64 cur_dual_ab;
 	bool active_only;
 };
 
@@ -125,7 +125,7 @@
 void msm_bus_scale_unregister(struct msm_bus_client_handle *cl);
 int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib);
 int msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl,
-		u64 act_ab, u64 act_ib, u64 slp_ib, u64 slp_ab);
+		u64 act_ab, u64 act_ib, u64 dual_ib, u64 dual_ab);
 int msm_bus_scale_query_tcs_cmd(struct msm_bus_tcs_usecase *tcs_usecase,
 					uint32_t cl, unsigned int index);
 int msm_bus_scale_query_tcs_cmd_all(struct msm_bus_tcs_handle *tcs_handle,
@@ -192,7 +192,7 @@
 
 static inline int
 msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
-				u64 act_ib, u64 slp_ib, u64 slp_ab)
+				u64 act_ib, u64 dual_ib, u64 dual_ab)
 
 {
 	return 0;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 8e7a431..ec3be7b 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -249,6 +249,9 @@
 	POWER_SUPPLY_PROP_HW_CURRENT_MAX,
 	POWER_SUPPLY_PROP_REAL_TYPE,
 	POWER_SUPPLY_PROP_PR_SWAP,
+	POWER_SUPPLY_PROP_CC_STEP,
+	POWER_SUPPLY_PROP_CC_STEP_SEL,
+	POWER_SUPPLY_PROP_SW_JEITA_ENABLED,
 	/* Local extensions of type int64_t */
 	POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
 	/* Properties of type `const char *' */
diff --git a/include/net/cnss_nl.h b/include/net/cnss_nl.h
new file mode 100644
index 0000000..86c2fcc
--- /dev/null
+++ b/include/net/cnss_nl.h
@@ -0,0 +1,100 @@
+/* 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 _NET_CNSS_GENETLINK_H_
+#define _NET_CNSS_GENETLINK_H_
+
+#define CLD80211_MAX_COMMANDS 40
+#define CLD80211_MAX_NL_DATA  4096
+
+/**
+ * enum cld80211_attr - Driver/Application embeds the data in nlmsg with the
+ *			help of below attributes
+ *
+ * @CLD80211_ATTR_VENDOR_DATA: Embed all other attributes in this nested
+ *	attribute.
+ * @CLD80211_ATTR_DATA: Embed complete data in this attribute
+ *
+ * Any new message in future can be added as another attribute
+ */
+enum cld80211_attr {
+	CLD80211_ATTR_VENDOR_DATA = 1,
+	CLD80211_ATTR_DATA,
+	/* add new attributes above here */
+
+	__CLD80211_ATTR_AFTER_LAST,
+	CLD80211_ATTR_MAX = __CLD80211_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum cld80211_multicast_groups - List of multicast groups supported
+ *
+ * @CLD80211_MCGRP_SVC_MSGS: WLAN service message will be sent to this group.
+ *	Ex: Status ind messages
+ * @CLD80211_MCGRP_HOST_LOGS: All logging related messages from driver will be
+ *	sent to this multicast group
+ * @CLD80211_MCGRP_FW_LOGS: Firmware logging messages will be sent to this group
+ * @CLD80211_MCGRP_PER_PKT_STATS: Messages related packet stats debugging infra
+ *	will be sent to this group
+ * @CLD80211_MCGRP_DIAG_EVENTS: Driver/Firmware status logging diag events will
+ *	be sent to this group
+ * @CLD80211_MCGRP_FATAL_EVENTS: Any fatal message generated in driver/firmware
+ *	will be sent to this group
+ * @CLD80211_MCGRP_OEM_MSGS: All OEM message will be sent to this group
+ *	Ex: LOWI messages
+ */
+enum cld80211_multicast_groups {
+	CLD80211_MCGRP_SVC_MSGS,
+	CLD80211_MCGRP_HOST_LOGS,
+	CLD80211_MCGRP_FW_LOGS,
+	CLD80211_MCGRP_PER_PKT_STATS,
+	CLD80211_MCGRP_DIAG_EVENTS,
+	CLD80211_MCGRP_FATAL_EVENTS,
+	CLD80211_MCGRP_OEM_MSGS,
+};
+
+/**
+ * typedef cld80211_cb - Callback to be called when an nlmsg is received with
+ *			 the registered cmd_id command from userspace
+ * @data: Payload of the message to be sent to driver
+ * @data_len: Length of the payload
+ * @cb_ctx: callback context to be returned to driver when the callback
+ *	 is called
+ * @pid: process id of the sender
+ */
+typedef void (*cld80211_cb)(const void *data, int data_len,
+			    void *cb_ctx, int pid);
+
+/**
+ * register_cld_cmd_cb() - Allows cld driver to register for commands with
+ *	callback
+ * @cmd_id: Command to be registered. Valid range [1, CLD80211_MAX_COMMANDS]
+ * @cb: Callback to be called when an nlmsg is received with cmd_id command
+ *       from userspace
+ * @cb_ctx: context provided by driver; Send this as cb_ctx of func()
+ *         to driver
+ */
+int register_cld_cmd_cb(u8 cmd_id, cld80211_cb cb, void *cb_ctx);
+
+/**
+ * deregister_cld_cmd_cb() - Allows cld driver to de-register the command it
+ *	has already registered
+ * @cmd_id: Command to be deregistered.
+ */
+int deregister_cld_cmd_cb(u8 cmd_id);
+
+/**
+ * cld80211_get_genl_family() - Returns current netlink family context
+ */
+struct genl_family *cld80211_get_genl_family(void);
+
+#endif /* _NET_CNSS_GENETLINK_H_ */
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
index 75e6ccd..f0b3d02 100644
--- a/include/soc/qcom/rpmh.h
+++ b/include/soc/qcom/rpmh.h
@@ -40,6 +40,8 @@
 
 int rpmh_invalidate(struct rpmh_client *rc);
 
+int rpmh_ctrlr_idle(struct rpmh_client *rc);
+
 int rpmh_flush(struct rpmh_client *rc);
 
 int rpmh_read(struct rpmh_client *rc, u32 addr, u32 *resp);
@@ -82,6 +84,9 @@
 static inline int rpmh_invalidate(struct rpmh_client *rc)
 { return -ENODEV; }
 
+static inline int rpmh_ctrlr_idle(struct rpmh_client *rc)
+{ return -ENODEV; }
+
 static inline int rpmh_flush(struct rpmh_client *rc)
 { return -ENODEV; }
 
diff --git a/include/soc/qcom/system_pm.h b/include/soc/qcom/system_pm.h
index 0be089b..6d0993a 100644
--- a/include/soc/qcom/system_pm.h
+++ b/include/soc/qcom/system_pm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,12 +17,18 @@
 int system_sleep_enter(uint64_t sleep_val);
 
 void system_sleep_exit(void);
+
+bool system_sleep_allowed(void);
 #else
 static inline int system_sleep_enter(uint64_t sleep_val)
 { return -ENODEV; }
 
 static inline void system_sleep_exit(void)
 { }
+
+static inline bool system_sleep_allowed(void)
+{ return false; }
+
 #endif /* CONFIG_QTI_SYSTEM_PM */
 
 #endif /* __SOC_QCOM_SYS_PM_H__ */
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 5fdbdd8..51c0165 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -132,6 +132,8 @@
 #define IPA_FLT_MAC_DST_ADDR_802_3	(1ul << 20)
 #define IPA_FLT_MAC_ETHER_TYPE		(1ul << 21)
 #define IPA_FLT_MAC_DST_ADDR_L2TP	(1ul << 22)
+#define IPA_FLT_TCP_SYN			(1ul << 23)
+#define IPA_FLT_TCP_SYN_L2TP		(1ul << 24)
 
 /**
  * maximal number of NAT PDNs in the PDN config table
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 24e93a6..26506d5 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1123,6 +1123,9 @@
 #define V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION  \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 113)
 
+#define V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 114)
+
 /*  Camera class control IDs */
 
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 957d642..67cb46c 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -1374,6 +1374,10 @@
 {
 	struct spi_device *spi = to_spi_device(dev);
 	struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
+	struct wcd_spi_debug_data *dbg_data = &wcd_spi->debug_data;
+
+	debugfs_remove_recursive(dbg_data->dir);
+	dbg_data->dir = NULL;
 
 	wcd_spi->m_dev = NULL;
 	wcd_spi->m_ops = NULL;
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index fe1ce45..2fc26dc 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -128,6 +128,8 @@
 #define WCD934X_DIG_CORE_REG_MIN  WCD934X_CDC_ANC0_CLK_RESET_CTL
 #define WCD934X_DIG_CORE_REG_MAX  0xFFF
 
+#define WCD934X_CHILD_DEVICES_MAX	6
+
 #define WCD934X_MAX_MICBIAS 4
 #define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone"
 #define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone"
@@ -626,6 +628,11 @@
 	int power_active_ref;
 	int sidetone_coeff_array[IIR_MAX][BAND_MAX]
 		[WCD934X_CDC_SIDETONE_IIR_COEFF_MAX];
+
+	struct spi_device *spi;
+	struct platform_device *pdev_child_devices
+		[WCD934X_CHILD_DEVICES_MAX];
+	int child_count;
 };
 
 static const struct tavil_reg_mask_val tavil_spkr_default[] = {
@@ -5105,6 +5112,13 @@
 	int band_idx = 0, coeff_idx = 0;
 	struct snd_soc_codec *codec = tavil->codec;
 
+	/*
+	 * snd_soc_write call crashes at rmmod if there is no machine
+	 * driver and hence no codec pointer available
+	 */
+	if (!codec)
+		return;
+
 	for (band_idx = 0; band_idx < BAND_MAX; band_idx++) {
 		snd_soc_write(codec,
 		(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
@@ -9397,6 +9411,9 @@
 
 	control = dev_get_drvdata(codec->dev->parent);
 	devm_kfree(codec->dev, control->rx_chs);
+	/* slimslave deinit in wcd core looks for this value */
+	control->num_rx_port = 0;
+	control->num_tx_port = 0;
 	control->rx_chs = NULL;
 	control->tx_chs = NULL;
 	tavil_cleanup_irqs(tavil);
@@ -9736,6 +9753,7 @@
 		goto err_dt_parse;
 	}
 
+	tavil->spi = spi;
 	/* Put the reference to SPI master */
 	put_device(&master->dev);
 
@@ -9782,6 +9800,7 @@
 	}
 
 	platdata = &tavil->swr.plat_data;
+	tavil->child_count = 0;
 
 	for_each_child_of_node(wcd9xxx->dev->of_node, node) {
 
@@ -9849,6 +9868,10 @@
 				__func__);
 			tavil->swr.ctrl_data = swr_ctrl_data;
 		}
+		if (tavil->child_count < WCD934X_CHILD_DEVICES_MAX)
+			tavil->pdev_child_devices[tavil->child_count++] = pdev;
+		else
+			goto err_mem;
 	}
 
 	return;
@@ -10076,11 +10099,24 @@
 static int tavil_remove(struct platform_device *pdev)
 {
 	struct tavil_priv *tavil;
+	int count = 0;
 
 	tavil = platform_get_drvdata(pdev);
 	if (!tavil)
 		return -EINVAL;
 
+	/* do dsd deinit before codec->component->regmap becomes freed */
+	if (tavil->dsd_config) {
+		tavil_dsd_deinit(tavil->dsd_config);
+		tavil->dsd_config = NULL;
+	}
+
+	if (tavil->spi)
+		spi_unregister_device(tavil->spi);
+	for (count = 0; count < tavil->child_count &&
+				count < WCD934X_CHILD_DEVICES_MAX; count++)
+		platform_device_unregister(tavil->pdev_child_devices[count]);
+
 	mutex_destroy(&tavil->micb_lock);
 	mutex_destroy(&tavil->svs_mutex);
 	mutex_destroy(&tavil->codec_mutex);
@@ -10091,10 +10127,6 @@
 	snd_soc_unregister_codec(&pdev->dev);
 	clk_put(tavil->wcd_ext_clk);
 	wcd_resmgr_remove(tavil->resmgr);
-	if (tavil->dsd_config) {
-		tavil_dsd_deinit(tavil->dsd_config);
-		tavil->dsd_config = NULL;
-	}
 	devm_kfree(&pdev->dev, tavil);
 	return 0;
 }
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index c8b01c6..543bc31 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -3632,7 +3632,6 @@
 		clear_bit(STATUS_PORT_STARTED,
 			  mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask);
 	}
-	kfree(mi2s_dai_data);
 	return 0;
 }
 
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 7a5ccd8..2792616 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -7149,6 +7149,7 @@
 
 	msm_release_pinctrl(pdev);
 	snd_soc_unregister_card(card);
+	audio_notifier_deregister("sdm845");
 	return 0;
 }