Merge "msm: ADSPRPC: Avoid race condition during map creation and free"
diff --git a/Documentation/devicetree/bindings/leds/leds-qti-tri-led.txt b/Documentation/devicetree/bindings/leds/leds-qti-tri-led.txt
new file mode 100644
index 0000000..c088d42
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-qti-tri-led.txt
@@ -0,0 +1,60 @@
+Qualcomm Technologies, Inc. TRI_LED driver specific bindings
+
+This binding document describes the properties of TRI_LED module in
+Qualcomm Technologies, Inc. PMIC chips.
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Must be "qcom,tri-led".
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Register base of the TRI_LED module and length.
+
+Properties for child nodes:
+- pwms:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: The PWM device (phandle) used for controlling LED.
+
+- led-sources:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: see Documentation/devicetree/bindings/leds/common.txt;
+		Device current output identifiers are: 0 - LED1_EN,
+		1 - LED2_EN, 2 - LED3_EN.
+
+- label:
+	Usage: optional
+	Value type: <string>
+	Definition: see Documentation/devicetree/bindings/leds/common.txt;
+
+- linux,default-trigger:
+	Usage: optional
+	Value_type: <string>
+	Definition: see Documentation/devicetree/bindings/leds/common.txt;
+
+Example:
+
+	pmi8998_rgb: tri-led@d000{
+		compatible = "qcom,tri-led";
+		reg = <0xd000 0x100>;
+
+		red {
+			label = "red";
+			pwms = <&pmi8998_lpg 4 1000000>;
+			led-sources = <0>;
+		};
+		green {
+			label = "green";
+			pwms = <&pmi8998_lpg 3 1000000>;
+			led-sources = <1>;
+		};
+		blue {
+			label = "blue";
+			pwms = <&pmi8998_lpg 2 1000000>;
+			led-sources = <2>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt
index 6af2bac..dfe5852 100644
--- a/Documentation/devicetree/bindings/pci/msm_pcie.txt
+++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt
@@ -37,6 +37,7 @@
 		     MSIs, virtual IRQ's (INT#), link state notifications.
   - perst-gpio: PERST GPIO specified by PCIe spec.
   - wake-gpio: WAKE GPIO specified by PCIe spec.
+  - phy-status-offset: Offset from PCIe PHY base to check if PCIe PHY is up.
   - <supply-name>-supply: phandle to the regulator device tree node.
     Refer to the schematics for the corresponding voltage regulators.
     vreg-1.8-supply: phandle to the analog supply for the PCIe controller.
@@ -274,6 +275,7 @@
 		qcom,switch-latency = <100>;
 		qcom,wr-halt-size = <0xa>; /* 1KB */
 		qcom,slv-addr-space-size = <0x1000000>; /* 16MB */
+		qcom,phy-status-offset = <0x800>;
 		qcom,cpl-timeout = <0x2>;
 
 		iommus = <&anoc0_smmu>;
diff --git a/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt
new file mode 100644
index 0000000..3174ccb
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-qti-lpg.txt
@@ -0,0 +1,36 @@
+Qualcomm Technologies, Inc. LPG driver specific bindings
+
+This binding document describes the properties of LPG (Light Pulse Generator)
+device module in Qualcomm Technologies, Inc. PMIC chips.
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: Must be "qcom,pwm-lpg".
+
+- reg:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: Register base and length for LPG modules. The length
+		      varies based on the number of channels available in
+		      the PMIC chips.
+
+- reg-names:
+	Usage: required
+	Value type: <string>
+	Definition: The name of the register defined in the reg property.
+		      It must be "lpg-base".
+
+- #pwm-cells:
+	Usage: required
+	Value type: <u32>
+	Definition: See Documentation/devicetree/bindings/pwm/pwm.txt;
+
+Example:
+
+	pmi8998_lpg: lpg@b100 {
+		compatible = "qcom,pwm-lpg";
+		reg = <0xb100 0x600>;
+		reg-names = "lpg-base";
+		#pwm-cells = <2>;
+	};
diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
index fba7204..be8c2f0 100644
--- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
+++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
@@ -14,6 +14,7 @@
 - qcom,fastrpc-glink:	Flag to use glink instead of smd for IPC
 - qcom,rpc-latency-us:	FastRPC QoS latency vote
 - qcom,adsp-remoteheap-vmid:  FastRPC remote heap VMID list
+- qcom,fastrpc-adsp-audio-pdr:  Flag to enable ADSP Audio PDR
 
 Optional subnodes:
 - qcom,msm_fastrpc_compute_cb :	Child nodes representing the compute context
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index a37e441..e996ba5 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -272,6 +272,7 @@
 SUNW	Sun Microsystems, Inc
 swir	Sierra Wireless
 syna	Synaptics Inc.
+synaptics	Synaptics Inc.
 synology	Synology, Inc.
 tbs	TBS Technologies
 tcg	Trusted Computing Group
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi
index 0b94534..e939bd2 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi
@@ -139,6 +139,8 @@
 
 		qcom,slv-addr-space-size = <0x40000000>;
 
+		qcom,phy-status-offset = <0x814>;
+
 		qcom,cpl-timeout = <0x2>;
 
 		qcom,boot-option = <0x1>;
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 7d5ee77..5829942 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -17,6 +17,7 @@
 #include <dt-bindings/clock/qcom,gcc-sdxpoorwills.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+#include <dt-bindings/clock/qcom,aop-qmp.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. SDX POORWILLS";
@@ -223,6 +224,13 @@
 		mbox-names = "apps";
 	};
 
+	clock_aop: qcom,aopclk {
+		compatible = "qcom,aop-qmp-clk-v1";
+		#clock-cells = <1>;
+		mboxes = <&qmp_aop 0>;
+		mbox-names = "qdss_clk";
+	};
+
 	snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive {
 		compatible = "qcom,devbw";
 		governor = "powersave";
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index b9628eb..1fb8f20 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -25,6 +25,7 @@
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_SDXPOORWILLS=y
+CONFIG_PCI_MSM=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_CMA=y
@@ -316,6 +317,7 @@
 CONFIG_GPIO_USB_DETECT=y
 CONFIG_USB_BAM=y
 CONFIG_MSM_CLK_RPMH=y
+CONFIG_MSM_CLK_AOP_QMP=y
 CONFIG_MDM_GCC_SDXPOORWILLS=y
 CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index b5268d6..61c362e 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -27,6 +27,7 @@
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_SDXPOORWILLS=y
 # CONFIG_VDSO is not set
+CONFIG_PCI_MSM=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_CMA=y
@@ -315,6 +316,7 @@
 CONFIG_GPIO_USB_DETECT=y
 CONFIG_USB_BAM=y
 CONFIG_MSM_CLK_RPMH=y
+CONFIG_MSM_CLK_AOP_QMP=y
 CONFIG_MDM_GCC_SDXPOORWILLS=y
 CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index f9dfe80..4952b98 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -44,6 +44,7 @@
 	select HAVE_ARM_ARCH_TIMER
 	select MSM_CORTEX_A7
 	select PINCTRL
+	select PCI
 	select QCOM_SCM if SMP
 	select MSM_JTAG_MM if CORESIGHT_ETM
 	select PM_DEVFREQ
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
index c059443..1b38d06 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -38,17 +38,13 @@
 		qcom,mdss-dsi-te-dcs-command = <1>;
 		qcom,mdss-dsi-te-check-enable;
 		qcom,mdss-dsi-te-using-te-pin;
-		qcom,mdss-dsi-panel-timings =
-			[da 34 24 00 64 68 28 38 2a 03 04 00];
-		qcom,mdss-dsi-t-clk-pre = <0x29>;
-		qcom,mdss-dsi-t-clk-post = <0x03>;
 		qcom,mdss-dsi-dma-trigger = "trigger_sw";
 		qcom,mdss-dsi-mdp-trigger = "none";
 		qcom,mdss-dsi-lp11-init;
 		qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
 		qcom,mdss-dsi-bl-min-level = <1>;
 		qcom,mdss-dsi-bl-max-level = <4095>;
-		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+		qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 50>;
 		qcom,mdss-dsi-display-timings {
 			timing@0 {
 				qcom,mdss-dsi-panel-framerate = <60>;
@@ -77,11 +73,11 @@
 					05 01 00 00 0a 00 02 20 00
 					15 01 00 00 00 00 02 bb 10
 					05 01 00 00 78 00 02 11 00
-					05 01 00 00 14 00 02 29 00
+					05 01 00 00 78 00 02 29 00
 				];
 				qcom,mdss-dsi-off-command = [
-					05 01 00 00 14 00 02
-					28 00 05 01 00 00 78 00 02 10 00
+					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";
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index a142840..04202e5 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -675,6 +675,8 @@
 		reg = <0x1800000 0x80000>;
 		reg-names = "cc_base";
 		vdd_gfx-supply = <&gfx_vreg_corner>;
+		clocks = <&clock_gcc clk_xo_clk_src>;
+		clock-names = "xo";
 		qcom,gfxfreq-corner =
 			 <         0   0 >,
 			 < 133330000   1 >,  /* Min SVS   */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
index f287b21..a280fd3 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -16,6 +16,7 @@
 		compatible = "qcom,pil-tz-generic";
 		qcom,pas-id = <13>;
 		qcom,firmware-name = "a615_zap";
+		memory-region = <&pil_gpu_mem>;
 	};
 
 	msm_bus: qcom,kgsl-busmon{
diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
index d2a6640..9a7e742 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
@@ -307,6 +307,12 @@
 	 qcom,dsi-display-active;
 };
 
+&dsi_panel_pwr_supply {
+	qcom,panel-supply-entry@2 {
+		qcom,supply-post-off-sleep = <5>;
+	};
+};
+
 &pm660l_wled {
 	status = "okay";
 	qcom,led-strings-list = [00 01];
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index ce88d14..007f937 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -826,8 +826,15 @@
 };
 
 &dsi_dual_nt36850_truly_cmd {
-	qcom,mdss-dsi-t-clk-post = <0x0E>;
+	qcom,mdss-dsi-t-clk-post = <0x28>;
 	qcom,mdss-dsi-t-clk-pre = <0x30>;
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9c>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+	qcom,mdss-dsi-panel-status-read-length = <1>;
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 2b391a5..88117cf 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -529,6 +529,30 @@
 			reg = <0 0x93e00000 0 0x1e00000>;
 		};
 
+		pil_ipa_fw_mem: ips_fw_region@0x95c00000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x95c00000 0 0x10000>;
+		};
+
+		pil_ipa_gsi_mem: ipa_gsi_region@0x95c10000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x95c10000 0 0x5000>;
+		};
+
+		pil_gpu_mem: gpu_region@0x95c15000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x95c15000 0 0x2000>;
+		};
+
+		qseecom_mem: qseecom_region@0x9e400000 {
+			compatible = "shared-dma-pool";
+			no-map;
+			reg = <0 0x9e400000 0 0x1400000>;
+		};
+
 		adsp_mem: adsp_region {
 			compatible = "shared-dma-pool";
 			alloc-ranges = <0 0x00000000 0 0xffffffff>;
@@ -537,14 +561,6 @@
 			size = <0 0xc00000>;
 		};
 
-		qseecom_mem: qseecom_region {
-			compatible = "shared-dma-pool";
-			alloc-ranges = <0 0x00000000 0 0xffffffff>;
-			no-map;
-			alignment = <0 0x400000>;
-			size = <0 0x1400000>;
-		};
-
 		qseecom_ta_mem: qseecom_ta_region {
 			compatible = "shared-dma-pool";
 			alloc-ranges = <0 0x00000000 0 0xffffffff>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index 33bcaa6..000f5d3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -16,6 +16,7 @@
 		compatible = "qcom,pil-tz-generic";
 		qcom,pas-id = <13>;
 		qcom,firmware-name = "a630_zap";
+		memory-region = <&pil_gpu_mem>;
 	};
 
 	msm_bus: qcom,kgsl-busmon{
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi
index daf5687..af7feb5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -202,6 +202,8 @@
 
 		qcom,ep-latency = <10>;
 
+		qcom,phy-status-offset = <0x974>;
+
 		qcom,boot-option = <0x1>;
 
 		linux,pci-domain = <0>;
@@ -535,6 +537,8 @@
 
 		qcom,slv-addr-space-size = <0x20000000>;
 
+		qcom,phy-status-offset = <0x1aac>;
+
 		qcom,boot-option = <0x1>;
 
 		linux,pci-domain = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 11c48bd..78be790 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -749,6 +749,123 @@
 			};
 		};
 
+		/* add pingrp for touchscreen */
+		pmx_ts_int_active {
+			ts_int_active: ts_int_active {
+				mux {
+					pins = "gpio122";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio122";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_int_suspend {
+			ts_int_suspend1: ts_int_suspend1 {
+				mux {
+					pins = "gpio122";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio122";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_reset_active {
+			ts_reset_active: ts_reset_active {
+				mux {
+					pins = "gpio99";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio99";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+		};
+
+		pmx_ts_reset_suspend {
+			ts_reset_suspend1: ts_reset_suspend1 {
+				mux {
+					pins = "gpio99";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio99";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		pmx_ts_release {
+			ts_release: ts_release {
+				mux {
+					pins = "gpio122", "gpio99";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio122", "gpio99";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+
+		ts_mux {
+			ts_active: ts_active {
+				mux {
+					pins = "gpio99", "gpio122";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio99", "gpio122";
+					drive-strength = <16>;
+					bias-pull-up;
+				};
+			};
+
+			ts_reset_suspend: ts_reset_suspend {
+				mux {
+					pins = "gpio99";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio99";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			ts_int_suspend: ts_int_suspend {
+				mux {
+					pins = "gpio122";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio122";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
 		sec_aux_pcm {
 			sec_aux_pcm_sleep: sec_aux_pcm_sleep {
 				mux {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
index d95dda0..a5c6ab5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
@@ -206,8 +206,8 @@
 	qcom,vdd-io-current-level = <200 22000>;
 
 	pinctrl-names = "active", "sleep";
-	pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on &storage_cd>;
-	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &storage_cd>;
+	pinctrl-0 = <&sdc2_clk_on  &sdc2_cmd_on &sdc2_data_on &storage_cd>;
+	pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>;
 
 	cd-gpios = <&tlmm 126 GPIO_ACTIVE_HIGH>;
 
@@ -217,3 +217,30 @@
 &wil6210 {
 	status = "ok";
 };
+
+&qupv3_se5_i2c {
+	status = "ok";
+	synaptics_dsx@20 {
+		compatible = "synaptics,dsx-i2c";
+		reg = <0x20>;
+		interrupt-parent = <&tlmm>;
+		interrupts = <122 0x2008>;
+		vdd-supply = <&pm8998_l14>;
+		avdd-supply = <&pm8998_l28>;
+		pinctrl-names = "pmx_ts_active", "pmx_ts_suspend",
+				"pmx_ts_release";
+		pinctrl-0 = <&ts_int_active &ts_reset_active>;
+		pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+		pinctrl-2 = <&ts_release>;
+		synaptics,pwr-reg-name = "avdd";
+		synaptics,bus-reg-name = "vdd";
+		synaptics,ub-i2c-addr = <0x2c>;
+		synaptics,irq-gpio = <&tlmm 122 0x2008>;
+		synaptics,reset-gpio = <&tlmm 99 0x0>;
+		synaptics,irq-on-state = <0>;
+		synaptics,power-delay-ms = <200>;
+		synaptics,reset-delay-ms = <200>;
+		synaptics,reset-on-state = <0>;
+		synaptics,reset-active-ms = <20>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 9d7c519..ec8665b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -559,7 +559,7 @@
 			regulator-min-microvolt = <2704000>;
 			regulator-max-microvolt = <2960000>;
 			qcom,init-voltage = <2704000>;
-			qcom,init-mode = <RPMH_REGULATOR_MODE_LPM>;
+			qcom,init-mode = <RPMH_REGULATOR_MODE_HPM>;
 		};
 	};
 
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index b08ccbb..8ba0af7 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -185,7 +185,8 @@
 	}
 
 	wb_congested = wb_congested_get_create(&q->backing_dev_info,
-					       blkcg->css.id, GFP_NOWAIT);
+					       blkcg->css.id,
+					       GFP_NOWAIT | __GFP_NOWARN);
 	if (!wb_congested) {
 		ret = -ENOMEM;
 		goto err_put_css;
@@ -193,7 +194,7 @@
 
 	/* allocate */
 	if (!new_blkg) {
-		new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT);
+		new_blkg = blkg_alloc(blkcg, q, GFP_NOWAIT | __GFP_NOWARN);
 		if (unlikely(!new_blkg)) {
 			ret = -ENOMEM;
 			goto err_put_congested;
@@ -1022,7 +1023,7 @@
 	}
 
 	spin_lock_init(&blkcg->lock);
-	INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT);
+	INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_NOWAIT | __GFP_NOWARN);
 	INIT_HLIST_HEAD(&blkcg->blkg_list);
 #ifdef CONFIG_CGROUP_WRITEBACK
 	INIT_LIST_HEAD(&blkcg->cgwb_list);
@@ -1240,7 +1241,7 @@
 		if (blkg->pd[pol->plid])
 			continue;
 
-		pd = pol->pd_alloc_fn(GFP_NOWAIT, q->node);
+		pd = pol->pd_alloc_fn(GFP_NOWAIT | __GFP_NOWARN, q->node);
 		if (!pd)
 			swap(pd, pd_prealloc);
 		if (!pd) {
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 4ac4910..6a90155 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -3868,7 +3868,8 @@
 			goto out;
 	}
 
-	cfqq = kmem_cache_alloc_node(cfq_pool, GFP_NOWAIT | __GFP_ZERO,
+	cfqq = kmem_cache_alloc_node(cfq_pool,
+				     GFP_NOWAIT | __GFP_ZERO | __GFP_NOWARN,
 				     cfqd->queue->node);
 	if (!cfqq) {
 		cfqq = &cfqd->oom_cfqq;
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 5cf41d5..3f35d54 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -28,6 +28,8 @@
 #include <soc/qcom/glink.h>
 #include <soc/qcom/subsystem_notif.h>
 #include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/service-notifier.h>
+#include <soc/qcom/service-locator.h>
 #include <linux/scatterlist.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
@@ -58,6 +60,9 @@
 #define VMID_ADSP_Q6    6
 #define DEBUGFS_SIZE 1024
 
+#define AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME   "audio_pdr_adsprpc"
+#define AUDIO_PDR_ADSP_SERVICE_NAME              "avs/audio"
+
 #define RPC_TIMEOUT	(5 * HZ)
 #define BALIGN		128
 #define NUM_CHANNELS	4	/* adsp, mdsp, slpi, cdsp*/
@@ -110,6 +115,9 @@
 
 static int fastrpc_glink_open(int cid);
 static void fastrpc_glink_close(void *chan, int cid);
+static int fastrpc_audio_pdr_notifier_cb(struct notifier_block *nb,
+					unsigned long code,
+					void *data);
 static struct dentry *debugfs_root;
 static struct dentry *debugfs_global_file;
 
@@ -224,6 +232,16 @@
 	int used;
 };
 
+struct fastrpc_static_pd {
+	char *spdname;
+	struct notifier_block pdrnb;
+	struct notifier_block get_service_nb;
+	void *pdrhandle;
+	int pdrcount;
+	int prevpdrcount;
+	int ispdup;
+};
+
 struct fastrpc_glink_info {
 	int link_state;
 	int port_state;
@@ -238,6 +256,7 @@
 	void *chan;
 	struct device *dev;
 	struct fastrpc_session_ctx session[NUM_SESSIONS];
+	struct fastrpc_static_pd spd[NUM_SESSIONS];
 	struct completion work;
 	struct completion workport;
 	struct notifier_block nb;
@@ -334,6 +353,7 @@
 	int cid;
 	int ssrcount;
 	int pd;
+	char *spdname;
 	int file_close;
 	struct fastrpc_apps *apps;
 	struct hlist_head perf;
@@ -353,6 +373,14 @@
 		.subsys = "adsp",
 		.link.link_info.edge = "lpass",
 		.link.link_info.transport = "smem",
+		.spd = {
+			{
+				.spdname =
+					AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME,
+				.pdrnb.notifier_call =
+						fastrpc_audio_pdr_notifier_cb,
+			}
+		},
 	},
 	{
 		.name = "mdsprpc-smd",
@@ -1123,6 +1151,21 @@
 	spin_unlock(&me->hlock);
 
 }
+
+static void fastrpc_notify_pdr_drivers(struct fastrpc_apps *me, char *spdname)
+{
+	struct fastrpc_file *fl;
+	struct hlist_node *n;
+
+	spin_lock(&me->hlock);
+	hlist_for_each_entry_safe(fl, n, &me->drivers, hn) {
+		if (fl->spdname && !strcmp(spdname, fl->spdname))
+			fastrpc_notify_users(fl);
+	}
+	spin_unlock(&me->hlock);
+
+}
+
 static void context_list_ctor(struct fastrpc_ctx_lst *me)
 {
 	INIT_HLIST_HEAD(&me->interrupted);
@@ -1706,7 +1749,28 @@
 	return err;
 }
 
+static int fastrpc_get_adsp_session(char *name, int *session)
+{
+	struct fastrpc_apps *me = &gfa;
+	int err = 0, i;
+
+	for (i = 0; i < NUM_SESSIONS; i++) {
+		if (!me->channel[0].spd[i].spdname)
+			continue;
+		if (!strcmp(name, me->channel[0].spd[i].spdname))
+			break;
+	}
+	VERIFY(err, i < NUM_SESSIONS);
+	if (err)
+		goto bail;
+	*session = i;
+bail:
+	return err;
+}
+
+static int fastrpc_mmap_remove_pdr(struct fastrpc_file *fl);
 static int fastrpc_channel_open(struct fastrpc_file *fl);
+static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl);
 static int fastrpc_init_process(struct fastrpc_file *fl,
 				struct fastrpc_ioctl_init_attrs *uproc)
 {
@@ -1846,6 +1910,12 @@
 		inbuf.pgid = current->tgid;
 		inbuf.namelen = init->filelen;
 		inbuf.pageslen = 0;
+
+		if (!strcmp(proc_name, "audiopd")) {
+			fl->spdname = AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME;
+			VERIFY(err, !fastrpc_mmap_remove_pdr(fl));
+		}
+
 		if (!me->staticpd_flags) {
 			inbuf.pageslen = 1;
 			mutex_lock(&fl->fl_map_mutex);
@@ -2157,6 +2227,33 @@
 	return err;
 }
 
+static int fastrpc_mmap_remove_pdr(struct fastrpc_file *fl)
+{
+	struct fastrpc_apps *me = &gfa;
+	int session = 0, err = 0;
+
+	VERIFY(err, !fastrpc_get_adsp_session(
+			AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME, &session));
+	if (err)
+		goto bail;
+	if (me->channel[fl->cid].spd[session].pdrcount !=
+		me->channel[fl->cid].spd[session].prevpdrcount) {
+		if (fastrpc_mmap_remove_ssr(fl))
+			pr_err("ADSPRPC: SSR: Failed to unmap remote heap\n");
+		me->channel[fl->cid].spd[session].prevpdrcount =
+				me->channel[fl->cid].spd[session].pdrcount;
+	}
+	if (!me->channel[fl->cid].spd[session].ispdup) {
+		VERIFY(err, 0);
+		if (err) {
+			err = -ENOTCONN;
+			goto bail;
+		}
+	}
+bail:
+	return err;
+}
+
 static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
 			     size_t len, struct fastrpc_mmap **ppmap);
 
@@ -3077,6 +3174,64 @@
 	return NOTIFY_DONE;
 }
 
+static int fastrpc_audio_pdr_notifier_cb(struct notifier_block *pdrnb,
+					unsigned long code,
+					void *data)
+{
+	struct fastrpc_apps *me = &gfa;
+	struct fastrpc_static_pd *spd;
+	struct notif_data *notifdata = data;
+
+	spd = container_of(pdrnb, struct fastrpc_static_pd, pdrnb);
+	if (code == SERVREG_NOTIF_SERVICE_STATE_DOWN_V01) {
+		mutex_lock(&me->smd_mutex);
+		spd->pdrcount++;
+		spd->ispdup = 0;
+		pr_info("ADSPRPC: Audio PDR notifier %d %s\n",
+					MAJOR(me->dev_no), spd->spdname);
+		mutex_unlock(&me->smd_mutex);
+		if (!strcmp(spd->spdname,
+				AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME))
+			me->staticpd_flags = 0;
+		fastrpc_notify_pdr_drivers(me, spd->spdname);
+	} else if (code == SUBSYS_RAMDUMP_NOTIFICATION) {
+		if (me->channel[0].remoteheap_ramdump_dev &&
+				notifdata->enable_ramdump) {
+			me->channel[0].ramdumpenabled = 1;
+		}
+	} else if (code == SERVREG_NOTIF_SERVICE_STATE_UP_V01) {
+		spd->ispdup = 1;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int fastrpc_get_service_location_notify(struct notifier_block *nb,
+					     unsigned long opcode, void *data)
+{
+	struct fastrpc_static_pd *spd;
+	struct pd_qmi_client_data *pdr = data;
+	int curr_state = 0;
+
+	spd = container_of(nb, struct fastrpc_static_pd, get_service_nb);
+	if (opcode == LOCATOR_DOWN) {
+		pr_err("ADSPRPC: Audio PD restart notifier locator down\n");
+		return NOTIFY_DONE;
+	}
+
+	if (pdr->total_domains == 1) {
+		spd->pdrhandle = service_notif_register_notifier(
+				pdr->domain_list[0].name,
+				pdr->domain_list[0].instance_id,
+				&spd->pdrnb, &curr_state);
+		if (IS_ERR(spd->pdrhandle))
+			pr_err("ADSPRPC: Unable to register notifier\n");
+	} else
+		pr_err("ADSPRPC: Service returned invalid domains\n");
+
+	return NOTIFY_DONE;
+}
+
 static const struct file_operations fops = {
 	.open = fastrpc_device_open,
 	.release = fastrpc_device_release,
@@ -3206,6 +3361,7 @@
 	struct platform_device *ion_pdev;
 	struct cma *cma;
 	uint32_t val;
+	int ret = 0;
 
 
 	if (of_device_is_compatible(dev->of_node,
@@ -3260,7 +3416,26 @@
 		}
 		return 0;
 	}
+	if (of_property_read_bool(dev->of_node,
+					"qcom,fastrpc-adsp-audio-pdr")) {
+		int session;
 
+		VERIFY(err, !fastrpc_get_adsp_session(
+			AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME, &session));
+		if (err)
+			goto spdbail;
+		me->channel[0].spd[session].get_service_nb.notifier_call =
+					fastrpc_get_service_location_notify;
+		ret = get_service_location(
+				AUDIO_PDR_SERVICE_LOCATION_CLIENT_NAME,
+				AUDIO_PDR_ADSP_SERVICE_NAME,
+				&me->channel[0].spd[session].get_service_nb);
+		if (ret)
+			pr_err("ADSPRPC: Get service location failed: %d\n",
+								ret);
+	}
+spdbail:
+	err = 0;
 	VERIFY(err, !of_platform_populate(pdev->dev.of_node,
 					  fastrpc_match_table,
 					  NULL, &pdev->dev));
diff --git a/drivers/clk/msm/clock-gcc-8953.c b/drivers/clk/msm/clock-gcc-8953.c
index e25da83..b2dc3d26 100644
--- a/drivers/clk/msm/clock-gcc-8953.c
+++ b/drivers/clk/msm/clock-gcc-8953.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -4072,8 +4072,17 @@
 	struct resource *res;
 	int ret;
 	u32 regval;
+	struct clk *xo_clk;
 	bool compat_bin = false;
 
+	/* Require the GCC-RPM-XO clock to be registered first */
+	xo_clk = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(xo_clk)) {
+		if (PTR_ERR(xo_clk) != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Unable to get xo clock\n");
+		return PTR_ERR(xo_clk);
+	}
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cc_base");
 	if (!res) {
 		dev_err(&pdev->dev, "Register base not defined\n");
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 4a4ee0f..5aa9914 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -443,13 +443,12 @@
 {
 	u32 cntkctl = arch_timer_get_cntkctl();
 
-	/* Disable user access to the timers */
+	/* Disable user access to the timers and the physical counter */
 	/* Also disable virtual event stream */
 	cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
 			| ARCH_TIMER_USR_VT_ACCESS_EN
-			| ARCH_TIMER_VIRT_EVT_EN);
-
-	cntkctl |= ARCH_TIMER_USR_PCT_ACCESS_EN;
+			| ARCH_TIMER_VIRT_EVT_EN
+			| ARCH_TIMER_USR_PCT_ACCESS_EN);
 
 	/* Enable user access to the virtual counter */
 	if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_VCT_ACCESS))
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 006f723..cb54b5f 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -71,6 +71,8 @@
 	struct completion video_comp;
 
 	bool orientation;
+	bool power_on;
+
 	atomic_t aborted;
 
 	u32 pixel_rate;
@@ -128,6 +130,11 @@
 
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
+	if (!ctrl->power_on || atomic_read(&ctrl->aborted)) {
+		pr_err("CTRL off, return\n");
+		return;
+	}
+
 	reinit_completion(&ctrl->idle_comp);
 	dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE);
 
@@ -833,7 +840,7 @@
 
 	tries = 0;
 	old_v_level = ctrl->link->phy_params.v_level;
-	while (1) {
+	while (!atomic_read(&ctrl->aborted)) {
 		drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
 
 		ret = dp_ctrl_read_link_status(ctrl, link_status);
@@ -960,7 +967,7 @@
 			ret = -EINVAL;
 			break;
 		}
-	} while (1);
+	} while (!atomic_read(&ctrl->aborted));
 
 	return ret;
 }
@@ -1180,6 +1187,11 @@
 
 	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
+	if (!ctrl->power_on || atomic_read(&ctrl->aborted)) {
+		pr_err("CTRL off, return\n");
+		return -EINVAL;
+	}
+
 	ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
 	ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
 
@@ -1341,7 +1353,6 @@
 	atomic_set(&ctrl->aborted, 0);
 	rate = ctrl->panel->link_info.rate;
 
-	ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true);
 	ctrl->catalog->hpd_config(ctrl->catalog, true);
 
 	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
@@ -1396,6 +1407,7 @@
 	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
 		dp_ctrl_send_phy_test_pattern(ctrl);
 
+	ctrl->power_on = true;
 	pr_debug("End-\n");
 
 end:
@@ -1419,6 +1431,7 @@
 
 	dp_ctrl_disable_mainlink_clocks(ctrl);
 
+	ctrl->power_on = false;
 	pr_debug("DP off done\n");
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 0b3d903..054b3c8 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -665,6 +665,8 @@
 		pr_err("invalid input\n");
 		len = -EINVAL;
 	}
+
+	debug->panel->setup_hdr(debug->panel, &c_state->hdr_meta);
 end:
 	return len;
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index f2c0a0e..d19058f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -22,6 +22,8 @@
 #include <linux/of_irq.h>
 #include <linux/hdcp_qseecom.h>
 
+#include "sde_connector.h"
+
 #include "msm_drv.h"
 #include "dp_usbpd.h"
 #include "dp_parser.h"
@@ -87,11 +89,12 @@
 
 	struct workqueue_struct *wq;
 	struct delayed_work hdcp_cb_work;
-	struct work_struct connect_work;
+	struct delayed_work connect_work;
 	struct work_struct attention_work;
 	struct mutex hdcp_mutex;
 	struct mutex session_lock;
 	int hdcp_status;
+	unsigned long audio_status;
 };
 
 static const struct of_device_id dp_dt_match[] = {
@@ -99,6 +102,11 @@
 	{}
 };
 
+static bool dp_display_framework_ready(struct dp_display_private *dp)
+{
+	return dp->dp_display.post_open ? false : true;
+}
+
 static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
 {
 	return dp->hdcp.feature_enabled &&
@@ -448,31 +456,30 @@
 	}
 
 	/* if cable is already connected, send notification */
-	if (dp_display->is_connected)
-		dp_display_send_hpd_event(dp);
+	if (dp->usbpd->hpd_high)
+		queue_delayed_work(dp->wq, &dp->connect_work, HZ * 10);
 	else
 		dp_display->post_open = NULL;
-
 }
 
 static int dp_display_send_hpd_notification(struct dp_display_private *dp,
 		bool hpd)
 {
+	u32 timeout_sec;
+
 	dp->dp_display.is_connected = hpd;
 
-	/* in case, framework is not yet up, don't notify hpd */
-	if (dp->dp_display.post_open)
-		return 0;
+	if  (dp_display_framework_ready(dp))
+		timeout_sec = 5;
+	else
+		timeout_sec = 10;
 
 	reinit_completion(&dp->notification_comp);
 	dp_display_send_hpd_event(dp);
 
-	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 5)) {
+	if (!wait_for_completion_timeout(&dp->notification_comp,
+						HZ * timeout_sec)) {
 		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
-		/* cancel any pending request */
-		dp->ctrl->abort(dp->ctrl);
-		dp->aux->abort(dp->aux);
-
 		return -EINVAL;
 	}
 
@@ -497,26 +504,21 @@
 	rc = dp->panel->read_sink_caps(dp->panel,
 		dp->dp_display.connector, dp->usbpd->multi_func);
 	if (rc) {
-		if (rc == -ETIMEDOUT) {
-			pr_err("Sink cap read failed, skip notification\n");
+		/*
+		 * ETIMEDOUT --> cable may have been removed
+		 * ENOTCONN --> no downstream device connected
+		 */
+		if (rc == -ETIMEDOUT || rc == -ENOTCONN)
 			goto end;
-		} else {
+		else
 			goto notify;
-		}
-	}
-
-	dp->link->process_request(dp->link);
-
-	if (dp_display_is_sink_count_zero(dp)) {
-		pr_debug("no downstream devices connected\n");
-		rc = -EINVAL;
-		goto end;
 	}
 
 	edid = dp->panel->edid_ctrl->edid;
 
 	dp->audio_supported = drm_detect_monitor_audio(edid);
 
+	dp->link->process_request(dp->link);
 	dp->panel->handle_sink_request(dp->panel);
 
 	dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz;
@@ -573,9 +575,9 @@
 	if (dp->audio_supported)
 		dp->audio->off(dp->audio);
 
-	rc = dp_display_send_hpd_notification(dp, false);
+	dp->audio_status = -ENODEV;
 
-	dp->aux->deinit(dp->aux);
+	rc = dp_display_send_hpd_notification(dp, false);
 
 	dp->panel->video_test = false;
 
@@ -602,8 +604,9 @@
 
 	dp_display_host_init(dp);
 
-	if (dp->usbpd->hpd_high)
-		queue_work(dp->wq, &dp->connect_work);
+	/* check for hpd high and framework ready */
+	if  (dp->usbpd->hpd_high && dp_display_framework_ready(dp))
+		queue_delayed_work(dp->wq, &dp->connect_work, 0);
 end:
 	return rc;
 }
@@ -620,6 +623,8 @@
 
 	dp->ctrl->push_idle(dp->ctrl);
 	dp->ctrl->off(dp->ctrl);
+	dp->panel->deinit(dp->panel);
+	dp->aux->deinit(dp->aux);
 	dp->power_on = false;
 }
 
@@ -667,6 +672,7 @@
 	dp->aux->abort(dp->aux);
 
 	/* wait for idle state */
+	cancel_delayed_work(&dp->connect_work);
 	flush_workqueue(dp->wq);
 
 	dp_display_handle_disconnect(dp);
@@ -678,13 +684,13 @@
 {
 	mutex_lock(&dp->audio->ops_lock);
 
-	if (dp->audio_supported)
+	if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status))
 		dp->audio->off(dp->audio);
 
 	dp->ctrl->link_maintenance(dp->ctrl);
 
-	if (dp->audio_supported)
-		dp->audio->on(dp->audio);
+	if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status))
+		dp->audio_status = dp->audio->on(dp->audio);
 
 	mutex_unlock(&dp->audio->ops_lock);
 }
@@ -707,7 +713,7 @@
 			return;
 		}
 
-		queue_work(dp->wq, &dp->connect_work);
+		queue_delayed_work(dp->wq, &dp->connect_work, 0);
 		return;
 	}
 
@@ -753,17 +759,19 @@
 		return -ENODEV;
 	}
 
-	if (dp->usbpd->hpd_irq && dp->usbpd->hpd_high) {
+	if (dp->usbpd->hpd_irq && dp->usbpd->hpd_high &&
+	    dp->power_on) {
 		dp->link->process_request(dp->link);
 		queue_work(dp->wq, &dp->attention_work);
 	} else if (dp->usbpd->hpd_high) {
-		queue_work(dp->wq, &dp->connect_work);
+		queue_delayed_work(dp->wq, &dp->connect_work, 0);
 	} else {
 		/* cancel any pending request */
 		dp->ctrl->abort(dp->ctrl);
 		dp->aux->abort(dp->aux);
 
 		/* wait for idle state */
+		cancel_delayed_work(&dp->connect_work);
 		flush_workqueue(dp->wq);
 
 		dp_display_handle_disconnect(dp);
@@ -774,7 +782,8 @@
 
 static void dp_display_connect_work(struct work_struct *work)
 {
-	struct dp_display_private *dp = container_of(work,
+	struct delayed_work *dw = to_delayed_work(work);
+	struct dp_display_private *dp = container_of(dw,
 			struct dp_display_private, connect_work);
 
 	if (dp->dp_display.is_connected) {
@@ -1070,7 +1079,7 @@
 	if (dp->audio_supported) {
 		dp->audio->bw_code = dp->link->link_params.bw_code;
 		dp->audio->lane_count = dp->link->link_params.lane_count;
-		dp->audio->on(dp->audio);
+		dp->audio_status = dp->audio->on(dp->audio);
 	}
 
 	dp_display_update_hdcp_info(dp);
@@ -1081,6 +1090,8 @@
 		dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
 		queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ / 2);
 	}
+
+	dp->panel->setup_hdr(dp->panel, NULL);
 end:
 	/* clear framework event notifier */
 	dp_display->post_open = NULL;
@@ -1125,6 +1136,8 @@
 static int dp_display_disable(struct dp_display *dp_display)
 {
 	struct dp_display_private *dp;
+	struct drm_connector *connector;
+	struct sde_connector_state *c_state;
 
 	if (!dp_display) {
 		pr_err("invalid input\n");
@@ -1132,6 +1145,8 @@
 	}
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
+	connector = dp->dp_display.connector;
+	c_state = to_sde_connector_state(connector->state);
 
 	mutex_lock(&dp->session_lock);
 
@@ -1142,6 +1157,15 @@
 
 	dp->ctrl->off(dp->ctrl);
 	dp->panel->deinit(dp->panel);
+	dp->aux->deinit(dp->aux);
+
+	connector->hdr_eotf = 0;
+	connector->hdr_metadata_type_one = 0;
+	connector->hdr_max_luminance = 0;
+	connector->hdr_avg_luminance = 0;
+	connector->hdr_min_luminance = 0;
+
+	memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
 
 	dp->power_on = false;
 
@@ -1252,8 +1276,7 @@
 	return ret;
 }
 
-
-static int dp_display_pre_kickoff(struct dp_display *dp_display,
+static int dp_display_config_hdr(struct dp_display *dp_display,
 			struct drm_msm_ext_hdr_metadata *hdr)
 {
 	int rc = 0;
@@ -1266,8 +1289,7 @@
 
 	dp = container_of(dp_display, struct dp_display_private, dp_display);
 
-	if (hdr->hdr_supported && dp->panel->hdr_supported(dp->panel))
-		rc = dp->panel->setup_hdr(dp->panel, hdr);
+	rc = dp->panel->setup_hdr(dp->panel, hdr);
 
 	return rc;
 }
@@ -1281,7 +1303,7 @@
 	}
 
 	INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work);
-	INIT_WORK(&dp->connect_work, dp_display_connect_work);
+	INIT_DELAYED_WORK(&dp->connect_work, dp_display_connect_work);
 	INIT_WORK(&dp->attention_work, dp_display_attention_work);
 
 	return 0;
@@ -1308,6 +1330,7 @@
 
 	dp->pdev = pdev;
 	dp->name = "drm_dp";
+	dp->audio_status = -ENODEV;
 
 	rc = dp_display_create_workqueue(dp);
 	if (rc) {
@@ -1332,7 +1355,7 @@
 	g_dp_display->get_debug     = dp_get_debug;
 	g_dp_display->post_open     = dp_display_post_open;
 	g_dp_display->post_init     = dp_display_post_init;
-	g_dp_display->pre_kickoff   = dp_display_pre_kickoff;
+	g_dp_display->config_hdr    = dp_display_config_hdr;
 
 	rc = component_add(&pdev->dev, &dp_display_comp_ops);
 	if (rc) {
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index c55e6c8..266de5f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -43,7 +43,7 @@
 	int (*request_irq)(struct dp_display *dp_display);
 	struct dp_debug *(*get_debug)(struct dp_display *dp_display);
 	void (*post_open)(struct dp_display *dp_display);
-	int (*pre_kickoff)(struct dp_display *dp_display,
+	int (*config_hdr)(struct dp_display *dp_display,
 				struct drm_msm_ext_hdr_metadata *hdr_meta);
 	void (*post_init)(struct dp_display *dp_display);
 };
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 7746b8e..b834230 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -276,18 +276,17 @@
 	.mode_set     = dp_bridge_mode_set,
 };
 
-int dp_connector_pre_kickoff(struct drm_connector *connector,
-		void *display,
-		struct msm_display_kickoff_params *params)
+int dp_connector_config_hdr(void *display,
+	struct sde_connector_state *c_state)
 {
 	struct dp_display *dp = display;
 
-	if (!connector || !display || !params) {
+	if (!display || !c_state) {
 		pr_err("invalid params\n");
 		return -EINVAL;
 	}
 
-	return dp->pre_kickoff(dp, params->hdr_meta);
+	return dp->config_hdr(dp, &c_state->hdr_meta);
 }
 
 int dp_connector_post_init(struct drm_connector *connector, void *display)
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 89b0a7e..3ca10c2 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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
@@ -32,15 +32,13 @@
 };
 
 /**
- * dp_connector_pre_kickoff - callback to perform pre kickoff initialization
- * @connector: Pointer to drm connector structure
+ * dp_connector_config_hdr - callback to configure HDR
  * @display: Pointer to private display handle
- * @params: Pointer to kickoff parameters
+ * @c_state: connect state data
  * Returns: Zero on success
  */
-int dp_connector_pre_kickoff(struct drm_connector *connector,
-		void *display,
-		struct msm_display_kickoff_params *params);
+int dp_connector_config_hdr(void *display,
+		struct sde_connector_state *c_state);
 
 /**
  * dp_connector_post_init - callback to perform additional initialization steps
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 0401760..e0aedc0 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 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
@@ -309,12 +309,14 @@
 static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
 	struct drm_connector *connector, bool multi_func)
 {
-	int rc = 0;
+	int rc = 0, rlen, count, downstream_ports;
+	const int count_len = 1;
 	struct dp_panel_private *panel;
 
 	if (!dp_panel || !connector) {
 		pr_err("invalid input\n");
-		return -EINVAL;
+		rc = -EINVAL;
+		goto end;
 	}
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
@@ -327,19 +329,35 @@
 		dp_panel->max_bw_code)) {
 		if ((rc == -ETIMEDOUT) || (rc == -ENODEV)) {
 			pr_err("DPCD read failed, return early\n");
-			return rc;
+			goto end;
 		}
 		pr_err("panel dpcd read failed/incorrect, set default params\n");
 		dp_panel_set_default_link_params(dp_panel);
 	}
 
+	downstream_ports = dp_panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
+				DP_DWN_STRM_PORT_PRESENT;
+
+	if (downstream_ports) {
+		rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_SINK_COUNT,
+				&count, count_len);
+		if (rlen == count_len) {
+			count = DP_GET_SINK_COUNT(count);
+			if (!count) {
+				pr_err("no downstream ports connected\n");
+				rc = -ENOTCONN;
+				goto end;
+			}
+		}
+	}
+
 	rc = dp_panel_read_edid(dp_panel, connector);
 	if (rc) {
 		pr_err("panel edid read failed, set failsafe mode\n");
 		return rc;
 	}
-
-	return 0;
+end:
+	return rc;
 }
 
 static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel,
@@ -648,6 +666,7 @@
 {
 	int rc = 0;
 	struct dp_panel_private *panel;
+	struct dp_catalog_hdr_data *hdr;
 
 	if (!dp_panel) {
 		pr_err("invalid input\n");
@@ -655,11 +674,13 @@
 	}
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+	hdr = &panel->catalog->hdr_data;
 
 	if (!panel->custom_edid)
 		sde_free_edid((void **)&dp_panel->edid_ctrl);
 
 	memset(&dp_panel->pinfo, 0, sizeof(dp_panel->pinfo));
+	memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta));
 	panel->panel_on = false;
 
 	return rc;
@@ -706,30 +727,6 @@
 		(panel->minor >= 4 || panel->vscext_supported);
 }
 
-static bool dp_panel_is_validate_hdr_state(struct dp_panel_private *panel,
-		struct drm_msm_ext_hdr_metadata *hdr_meta)
-{
-	struct drm_msm_ext_hdr_metadata *panel_hdr_meta =
-			&panel->catalog->hdr_data.hdr_meta;
-
-	if (!hdr_meta)
-		goto end;
-
-	/* bail out if HDR not active */
-	if (hdr_meta->hdr_state == HDR_DISABLED &&
-	    panel->hdr_state == HDR_DISABLED)
-		goto end;
-
-	/* bail out if same meta data is received */
-	if (hdr_meta->hdr_state == HDR_ENABLED &&
-		panel_hdr_meta->eotf == hdr_meta->eotf)
-		goto end;
-
-	return true;
-end:
-	return false;
-}
-
 static int dp_panel_setup_hdr(struct dp_panel *dp_panel,
 		struct drm_msm_ext_hdr_metadata *hdr_meta)
 {
@@ -744,14 +741,18 @@
 	}
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+	hdr = &panel->catalog->hdr_data;
 
-	if (!dp_panel_is_validate_hdr_state(panel, hdr_meta))
-		goto end;
+	/* use cached meta data in case meta data not provided */
+	if (!hdr_meta) {
+		if (hdr->hdr_meta.hdr_state)
+			goto cached;
+		else
+			goto end;
+	}
 
 	panel->hdr_state = hdr_meta->hdr_state;
 
-	hdr = &panel->catalog->hdr_data;
-
 	hdr->ext_header_byte0 = 0x00;
 	hdr->ext_header_byte1 = 0x04;
 	hdr->ext_header_byte2 = 0x1F;
@@ -786,8 +787,9 @@
 		memcpy(&hdr->hdr_meta, hdr_meta, sizeof(hdr->hdr_meta));
 	else
 		memset(&hdr->hdr_meta, 0, sizeof(hdr->hdr_meta));
-
-	panel->catalog->config_hdr(panel->catalog, panel->hdr_state);
+cached:
+	if (panel->panel_on)
+		panel->catalog->config_hdr(panel->catalog, panel->hdr_state);
 end:
 	return rc;
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index d5c4386..df0aad5e 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -939,34 +939,38 @@
 	struct sde_connector_state *c_state,
 	void *usr_ptr)
 {
+	int rc = 0;
 	struct drm_connector *connector;
 	struct drm_msm_ext_hdr_metadata *hdr_meta;
 	int i;
 
 	if (!c_conn || !c_state) {
 		SDE_ERROR_CONN(c_conn, "invalid args\n");
-		return -EINVAL;
+		rc = -EINVAL;
+		goto end;
 	}
 
 	connector = &c_conn->base;
 
 	if (!connector->hdr_supported) {
 		SDE_ERROR_CONN(c_conn, "sink doesn't support HDR\n");
-		return -ENOTSUPP;
+		rc = -ENOTSUPP;
+		goto end;
 	}
 
 	memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta));
 
 	if (!usr_ptr) {
 		SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n");
-		return 0;
+		goto end;
 	}
 
 	if (copy_from_user(&c_state->hdr_meta,
 		(void __user *)usr_ptr,
 			sizeof(*hdr_meta))) {
 		SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n");
-		return -EFAULT;
+		rc = -EFAULT;
+		goto end;
 	}
 
 	hdr_meta = &c_state->hdr_meta;
@@ -989,7 +993,10 @@
 				   hdr_meta->display_primaries_y[i]);
 	}
 
-	return 0;
+	if (c_conn->ops.config_hdr)
+		rc = c_conn->ops.config_hdr(c_conn->display, c_state);
+end:
+	return rc;
 }
 
 static int sde_connector_atomic_set_property(struct drm_connector *connector,
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 7cf09b7..9c37869 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -241,6 +241,16 @@
 	 */
 	int (*cmd_transfer)(void *display, const char *cmd_buf,
 			u32 cmd_buf_len);
+
+	/**
+	 * config_hdr - configure HDR
+	 * @display: Pointer to private display handle
+	 * @c_state: Pointer to connector state
+	 * Returns: Zero on success, negative error code for failures
+	 */
+	int (*config_hdr)(void *display,
+		struct sde_connector_state *c_state);
+
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c
index a6f22c9..442104b 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -513,6 +513,7 @@
 	struct msm_drm_private *priv;
 	int i;
 	int rc;
+	unsigned long irq_flags;
 
 	if (!sde_kms) {
 		SDE_ERROR("invalid sde_kms\n");
@@ -543,6 +544,7 @@
 	sde_disable_all_irqs(sde_kms);
 	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
 
+	spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags);
 	kfree(sde_kms->irq_obj.irq_cb_tbl);
 	kfree(sde_kms->irq_obj.enable_counts);
 	kfree(sde_kms->irq_obj.irq_counts);
@@ -550,6 +552,7 @@
 	sde_kms->irq_obj.enable_counts = NULL;
 	sde_kms->irq_obj.irq_counts = NULL;
 	sde_kms->irq_obj.total_irqs = 0;
+	spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags);
 }
 
 static void sde_core_irq_mask(struct irq_data *irqd)
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index b3eb101..73e2af0 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -3276,7 +3276,8 @@
 	 * smmu state is attached,
 	 */
 	if ((smmu_state->state != DETACHED) &&
-			(smmu_state->state != DETACH_ALL_REQ))
+			(smmu_state->state != DETACH_ALL_REQ) &&
+			sde_crtc->enabled)
 		sde_cp_crtc_apply_properties(crtc);
 
 	/*
@@ -4487,28 +4488,41 @@
 }
 
 static int _sde_crtc_excl_rect_overlap_check(struct plane_state pstates[],
-	int cnt, int curr_cnt, struct sde_rect *excl_rect, int z_pos)
+	int cnt, int curr_cnt, struct sde_rect *excl_rect)
 {
 	struct sde_rect dst_rect, intersect;
 	int i, rc = -EINVAL;
 	const struct drm_plane_state *pstate;
 
-	/* start checking from next plane */
-	for (i = curr_cnt; i < cnt; i++) {
+	for (i = 0; i < cnt; i++) {
+		if (i == curr_cnt)
+			continue;
+
 		pstate = pstates[i].drm_pstate;
 		POPULATE_RECT(&dst_rect, pstate->crtc_x, pstate->crtc_y,
 				pstate->crtc_w, pstate->crtc_h, false);
 		sde_kms_rect_intersect(&dst_rect, excl_rect, &intersect);
 
+		/* complete intersection of excl_rect is required */
 		if (intersect.w == excl_rect->w && intersect.h == excl_rect->h
-				/* next plane may be on same z-order */
-				&& z_pos != pstates[i].stage) {
+			    /* intersecting rect should be in another z_order */
+			    && pstates[curr_cnt].stage != pstates[i].stage) {
 			rc = 0;
 			goto end;
 		}
 	}
 
-	SDE_ERROR("excl rect does not find top overlapping rect\n");
+	SDE_ERROR(
+	    "no overlapping rect for [%d] z_pos:%d, excl_rect:{%d,%d,%d,%d}\n",
+			i, pstates[curr_cnt].stage,
+			excl_rect->x, excl_rect->y, excl_rect->w, excl_rect->h);
+	for (i = 0; i < cnt; i++) {
+		pstate = pstates[i].drm_pstate;
+		SDE_ERROR("[%d] p:%d, z_pos:%d, src:{%d,%d,%d,%d}\n",
+				i, pstate->plane->base.id, pstates[i].stage,
+				pstate->crtc_x, pstate->crtc_y,
+				pstate->crtc_w, pstate->crtc_h);
+	}
 end:
 	return rc;
 }
@@ -4550,9 +4564,9 @@
 		pstate = pstates[i].drm_pstate;
 		sde_pstate = to_sde_plane_state(pstate);
 		if (sde_pstate->excl_rect.w && sde_pstate->excl_rect.h) {
-			/* check overlap on all top z-order */
+			/* check overlap on any other z-order */
 			rc = _sde_crtc_excl_rect_overlap_check(pstates, cnt,
-			     i + 1, &sde_pstate->excl_rect, pstates[i].stage);
+			     i, &sde_pstate->excl_rect);
 			if (rc)
 				goto end;
 		}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 3b5e3f5..92ab669 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -3739,6 +3739,7 @@
 	SDE_ATRACE_BEGIN("enc_prepare_for_kickoff");
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		phys = sde_enc->phys_encs[i];
+		params->is_primary = sde_enc->disp_info.is_primary;
 		if (phys) {
 			if (phys->ops.prepare_for_kickoff) {
 				rc = phys->ops.prepare_for_kickoff(
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 8038eb6..2c84e20 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
  * Author: Rob Clark <robdclark@gmail.com>
  *
@@ -54,11 +54,13 @@
 /**
  * sde_encoder_kickoff_params - info encoder requires at kickoff
  * @inline_rotate_prefill: number of lines to prefill for inline rotation
+ * @is_primary: set to true if the display is primary display
  * @affected_displays:  bitmask, bit set means the ROI of the commit lies within
  *                      the bounds of the physical display at the bit index
  */
 struct sde_encoder_kickoff_params {
 	u32 inline_rotate_prefill;
+	u32 is_primary;
 	unsigned long affected_displays;
 };
 
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 4a15e6f..69dc385 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -245,9 +245,10 @@
  *	HW layer requires VSYNC counter of first pixel of tgt VFP line.
  * @phys_enc: Pointer to physical encoder
  * @rot_fetch_lines: number of line to prefill, or 0 to disable
+ * @is_primary: set true if the display is primary display
  */
 static void programmable_rot_fetch_config(struct sde_encoder_phys *phys_enc,
-		u32 rot_fetch_lines)
+		u32 rot_fetch_lines, u32 is_primary)
 {
 	struct sde_encoder_phys_vid *vid_enc =
 		to_sde_encoder_phys_vid(phys_enc);
@@ -264,7 +265,8 @@
 			!phys_enc->hw_ctl->ops.get_bitmask_intf ||
 			!phys_enc->hw_ctl->ops.update_pending_flush ||
 			!vid_enc->hw_intf->ops.setup_rot_start ||
-			!phys_enc->sde_kms)
+			!phys_enc->sde_kms ||
+			!is_primary)
 		return;
 
 	timing = &vid_enc->timing_params;
@@ -873,7 +875,8 @@
 		vid_enc->error_count = 0;
 	}
 
-	programmable_rot_fetch_config(phys_enc, params->inline_rotate_prefill);
+	programmable_rot_fetch_config(phys_enc,
+			params->inline_rotate_prefill, params->is_primary);
 
 	return rc;
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 545ed65..cdc6a9c 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -1681,6 +1681,8 @@
 		if (sde_cfg->has_wb_ubwc)
 			set_bit(SDE_WB_UBWC, &wb->features);
 
+		set_bit(SDE_WB_XY_ROI_OFFSET, &wb->features);
+
 		for (j = 0; j < sde_cfg->mdp_count; j++) {
 			sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].reg_off =
 				PROP_BITVALUE_ACCESS(prop_value,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 2b0aa37..5d3835c 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -949,7 +949,7 @@
 		.get_mode_info  = dp_connector_get_mode_info,
 		.post_open  = dp_connector_post_open,
 		.check_status = NULL,
-		.pre_kickoff  = dp_connector_pre_kickoff,
+		.config_hdr = dp_connector_config_hdr,
 		.cmd_transfer = NULL,
 	};
 	struct msm_display_info info;
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 66fc011..52d45bb 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -1307,10 +1307,13 @@
 	do {
 		if (!regulator_is_enabled(gmu->cx_gdsc))
 			return 0;
-		cond_resched();
+		usleep_range(10, 100);
 
 	} while (!(time_after(jiffies, t)));
 
+	if (!regulator_is_enabled(gmu->cx_gdsc))
+		return 0;
+
 	dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout");
 	return -ETIMEDOUT;
 }
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 22a708e..25b85ab 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 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
@@ -28,7 +28,7 @@
 #include <asm/cacheflush.h>
 #include <asm/dma-iommu.h>
 
-#if defined(CONFIG_IOMMU_DEBUG_TRACKING) || defined(CONFIG_IOMMU_TESTS)
+#if defined(CONFIG_IOMMU_TESTS)
 
 static const char *iommu_debug_attr_to_string(enum iommu_attr attr)
 {
@@ -170,6 +170,8 @@
 	u64 phys;
 	size_t len;
 	struct list_head list;
+	struct mutex clk_lock;
+	unsigned int clk_count;
 };
 
 static int iommu_debug_build_phoney_sg_table(struct device *dev,
@@ -1195,6 +1197,7 @@
 		return -ENOMEM;
 	}
 
+	val = VMID_CP_CAMERA;
 	if (is_secure && iommu_domain_set_attr(ddev->domain,
 					       DOMAIN_ATTR_SECURE_VMID,
 					       &val)) {
@@ -1485,6 +1488,10 @@
 	ssize_t retval;
 	size_t buflen;
 
+	if (kptr_restrict != 0) {
+		pr_err("kptr_restrict needs to be disabled.\n");
+		return -EPERM;
+	}
 	if (!dev->archdata.mapping) {
 		pr_err("No mapping. Did you already attach?\n");
 		return -EINVAL;
@@ -1552,6 +1559,10 @@
 	ssize_t retval;
 	size_t buflen;
 
+	if (kptr_restrict != 0) {
+		pr_err("kptr_restrict needs to be disabled.\n");
+		return -EPERM;
+	}
 	if (!ddev->domain) {
 		pr_err("No domain. Did you already attach?\n");
 		return -EINVAL;
@@ -1600,6 +1611,10 @@
 	ssize_t retval;
 	size_t buflen;
 
+	if (kptr_restrict != 0) {
+		pr_err("kptr_restrict needs to be disabled.\n");
+		return -EPERM;
+	}
 	if (!dev->archdata.mapping) {
 		pr_err("No mapping. Did you already attach?\n");
 		return -EINVAL;
@@ -2046,20 +2061,34 @@
 		return -EFAULT;
 	}
 
+	mutex_lock(&ddev->clk_lock);
 	switch (buf) {
 	case '0':
+		if (ddev->clk_count == 0) {
+			dev_err(dev, "Config clocks already disabled\n");
+			break;
+		}
+
+		if (--ddev->clk_count > 0)
+			break;
+
 		dev_err(dev, "Disabling config clocks\n");
 		iommu_disable_config_clocks(ddev->domain);
 		break;
 	case '1':
+		if (ddev->clk_count++ > 0)
+			break;
+
 		dev_err(dev, "Enabling config clocks\n");
 		if (iommu_enable_config_clocks(ddev->domain))
 			dev_err(dev, "Failed!\n");
 		break;
 	default:
 		dev_err(dev, "Invalid value. Should be 0 or 1.\n");
+		mutex_unlock(&ddev->clk_lock);
 		return -EINVAL;
 	}
+	mutex_unlock(&ddev->clk_lock);
 
 	return count;
 }
@@ -2109,6 +2138,9 @@
 	if (!of_find_property(dev->of_node, "iommus", NULL))
 		return 0;
 
+	if (!of_device_is_compatible(dev->of_node, "iommu-debug-test"))
+		return 0;
+
 	/* Hold a reference count */
 	if (!iommu_group_get(dev))
 		return 0;
@@ -2116,6 +2148,7 @@
 	ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
 	if (!ddev)
 		return -ENODEV;
+	mutex_init(&ddev->clk_lock);
 	ddev->dev = dev;
 	dir = debugfs_create_dir(dev_name(dev), debugfs_tests_dir);
 	if (!dir) {
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 26e03ba..787bda3 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -625,6 +625,15 @@
 	  To compile this driver as a module, choose 'm' here: the module
 	  will be called leds-powernv.
 
+config LEDS_QTI_TRI_LED
+	tristate "LED support for Qualcomm Technologies, Inc. TRI_LED"
+	depends on LEDS_CLASS && MFD_SPMI_PMIC && PWM && OF
+	help
+	  This driver supports the TRI_LED module found in Qualcomm
+	  Technologies, Inc. PMIC chips. TRI_LED supports 3 LED drivers
+	  at max and each is controlled by a PWM channel used for dimming
+	  or blinking.
+
 config LEDS_SYSCON
 	bool "LED support for LEDs on system controllers"
 	depends on LEDS_CLASS=y
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 5514391..96df61b 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -61,6 +61,7 @@
 obj-$(CONFIG_LEDS_MAX8997)		+= leds-max8997.o
 obj-$(CONFIG_LEDS_LM355x)		+= leds-lm355x.o
 obj-$(CONFIG_LEDS_BLINKM)		+= leds-blinkm.o
+obj-$(CONFIG_LEDS_QTI_TRI_LED)		+= leds-qti-tri-led.o
 obj-$(CONFIG_LEDS_SYSCON)		+= leds-syscon.o
 obj-$(CONFIG_LEDS_VERSATILE)		+= leds-versatile.o
 obj-$(CONFIG_LEDS_MENF21BMC)		+= leds-menf21bmc.o
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 1a2aea9..7cf17c9 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -99,11 +99,8 @@
 
 #define	VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us)	(val_us / 8)
 #define	VPH_DROOP_HYST_MV_TO_VAL(val_mv)	(val_mv / 25)
-#define	VPH_DROOP_THRESH_MV_TO_VAL(val_mv)	((val_mv / 100) - 25)
 #define	VPH_DROOP_THRESH_VAL_TO_UV(val)		((val + 25) * 100000)
 #define	MITIGATION_THRSH_MA_TO_VAL(val_ma)	(val_ma / 100)
-#define	CURRENT_MA_TO_REG_VAL(curr_ma, ires_ua)	((curr_ma * 1000) / ires_ua - 1)
-#define	SAFETY_TMR_TO_REG_VAL(duration_ms)	((duration_ms / 10) - 1)
 #define	THERMAL_HYST_TEMP_TO_VAL(val, divisor)	(val / divisor)
 
 #define	FLASH_LED_ISC_WARMUP_DELAY_SHIFT	6
@@ -317,6 +314,14 @@
 	FLASH_LED_IRES7P5_MAX_CURR_MA, FLASH_LED_IRES5P0_MAX_CURR_MA
 };
 
+static inline int get_current_reg_code(int target_curr_ma, int ires_ua)
+{
+	if (!ires_ua || !target_curr_ma || (target_curr_ma < (ires_ua / 1000)))
+		return 0;
+
+	return DIV_ROUND_UP(target_curr_ma * 1000, ires_ua) - 1;
+}
+
 static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
 {
 	int rc;
@@ -542,7 +547,7 @@
 		return rc;
 
 	if (led->pdata->led1n2_iclamp_low_ma) {
-		val = CURRENT_MA_TO_REG_VAL(led->pdata->led1n2_iclamp_low_ma,
+		val = get_current_reg_code(led->pdata->led1n2_iclamp_low_ma,
 						led->fnode[LED1].ires_ua);
 		rc = qpnp_flash_led_masked_write(led,
 				FLASH_LED_REG_LED1N2_ICLAMP_LOW(led->base),
@@ -552,7 +557,7 @@
 	}
 
 	if (led->pdata->led1n2_iclamp_mid_ma) {
-		val = CURRENT_MA_TO_REG_VAL(led->pdata->led1n2_iclamp_mid_ma,
+		val = get_current_reg_code(led->pdata->led1n2_iclamp_mid_ma,
 						led->fnode[LED1].ires_ua);
 		rc = qpnp_flash_led_masked_write(led,
 				FLASH_LED_REG_LED1N2_ICLAMP_MID(led->base),
@@ -562,7 +567,7 @@
 	}
 
 	if (led->pdata->led3_iclamp_low_ma) {
-		val = CURRENT_MA_TO_REG_VAL(led->pdata->led3_iclamp_low_ma,
+		val = get_current_reg_code(led->pdata->led3_iclamp_low_ma,
 						led->fnode[LED3].ires_ua);
 		rc = qpnp_flash_led_masked_write(led,
 				FLASH_LED_REG_LED3_ICLAMP_LOW(led->base),
@@ -572,7 +577,7 @@
 	}
 
 	if (led->pdata->led3_iclamp_mid_ma) {
-		val = CURRENT_MA_TO_REG_VAL(led->pdata->led3_iclamp_mid_ma,
+		val = get_current_reg_code(led->pdata->led3_iclamp_mid_ma,
 						led->fnode[LED3].ires_ua);
 		rc = qpnp_flash_led_masked_write(led,
 				FLASH_LED_REG_LED3_ICLAMP_MID(led->base),
@@ -992,7 +997,7 @@
 	}
 	fnode->current_ma = prgm_current_ma;
 	fnode->cdev.brightness = prgm_current_ma;
-	fnode->current_reg_val = CURRENT_MA_TO_REG_VAL(prgm_current_ma,
+	fnode->current_reg_val = get_current_reg_code(prgm_current_ma,
 					fnode->ires_ua);
 	fnode->led_on = prgm_current_ma != 0;
 
@@ -1103,10 +1108,11 @@
 		return rc;
 	}
 
-	/* Iterate over all leds for this switch node */
+	/* Iterate over all active leds for this switch node */
 	val = 0;
 	for (i = 0; i < led->num_fnodes; i++)
-		if (snode->led_mask & BIT(led->fnode[i].id))
+		if (led->fnode[i].led_on &&
+				snode->led_mask & BIT(led->fnode[i].id))
 			val |= led->fnode[i].ires_idx << (led->fnode[i].id * 2);
 
 	rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base),
@@ -1430,6 +1436,22 @@
 	return atomic_notifier_chain_unregister(&irq_notifier_list, nb);
 }
 
+static inline u8 get_safety_timer_code(u32 duration_ms)
+{
+	if (!duration_ms)
+		return 0;
+
+	return (duration_ms / 10) - 1;
+}
+
+static inline u8 get_vph_droop_thresh_code(u32 val_mv)
+{
+	if (!val_mv)
+		return 0;
+
+	return (val_mv / 100) - 25;
+}
+
 static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
 			struct flash_node_data *fnode, struct device_node *node)
 {
@@ -1521,8 +1543,9 @@
 	fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED;
 	rc = of_property_read_u32(node, "qcom,duration-ms", &val);
 	if (!rc) {
-		fnode->duration = (u8)(SAFETY_TMR_TO_REG_VAL(val) |
-					FLASH_LED_SAFETY_TMR_ENABLE);
+		fnode->duration = get_safety_timer_code(val);
+		if (fnode->duration)
+			fnode->duration |= FLASH_LED_SAFETY_TMR_ENABLE;
 	} else if (rc == -EINVAL) {
 		if (fnode->type == FLASH_LED_TYPE_FLASH) {
 			pr_err("Timer duration is required for flash LED\n");
@@ -1968,7 +1991,7 @@
 	rc = of_property_read_u32(node, "qcom,vph-droop-threshold-mv", &val);
 	if (!rc) {
 		led->pdata->vph_droop_threshold =
-			VPH_DROOP_THRESH_MV_TO_VAL(val);
+			get_vph_droop_thresh_code(val);
 	} else if (rc != -EINVAL) {
 		pr_err("Unable to read VPH droop threshold, rc=%d\n", rc);
 		return rc;
diff --git a/drivers/leds/leds-qti-tri-led.c b/drivers/leds/leds-qti-tri-led.c
new file mode 100644
index 0000000..ab5e876
--- /dev/null
+++ b/drivers/leds/leds-qti-tri-led.c
@@ -0,0 +1,512 @@
+/* Copyright (c) 2018, 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/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define TRILED_REG_TYPE			0x04
+#define TRILED_REG_SUBTYPE		0x05
+#define TRILED_REG_EN_CTL		0x46
+
+/* TRILED_REG_EN_CTL */
+#define TRILED_EN_CTL_MASK		GENMASK(7, 5)
+#define TRILED_EN_CTL_MAX_BIT		7
+
+#define TRILED_TYPE			0x19
+#define TRILED_SUBTYPE_LED3H0L12	0x02
+#define TRILED_SUBTYPE_LED2H0L12	0x03
+#define TRILED_SUBTYPE_LED1H2L12	0x04
+
+#define TRILED_NUM_MAX			3
+
+#define PWM_PERIOD_DEFAULT_NS		1000000
+#define LED_BLINK_ON_MS			125
+#define LED_BLINK_OFF_MS		875
+
+struct pwm_setting {
+	u32	pre_period_ns;
+	u32	period_ns;
+	u32	duty_ns;
+};
+
+struct led_setting {
+	u32			on_ms;
+	u32			off_ms;
+	enum led_brightness	brightness;
+	bool			blink;
+};
+
+struct qpnp_led_dev {
+	struct led_classdev	cdev;
+	struct pwm_device	*pwm_dev;
+	struct pwm_setting	pwm_setting;
+	struct led_setting	led_setting;
+	struct qpnp_tri_led_chip	*chip;
+	struct mutex		lock;
+	const char		*label;
+	const char		*default_trigger;
+	u8			id;
+	bool			blinking;
+};
+
+struct qpnp_tri_led_chip {
+	struct device		*dev;
+	struct regmap		*regmap;
+	struct qpnp_led_dev	*leds;
+	struct mutex		bus_lock;
+	int			num_leds;
+	u16			reg_base;
+	u8			subtype;
+};
+
+static int qpnp_tri_led_read(struct qpnp_tri_led_chip *chip, u16 addr, u8 *val)
+{
+	int rc;
+	unsigned int tmp;
+
+	mutex_lock(&chip->bus_lock);
+	rc = regmap_read(chip->regmap, chip->reg_base + addr, &tmp);
+	if (rc < 0)
+		dev_err(chip->dev, "Read addr 0x%x failed, rc=%d\n", addr, rc);
+	else
+		*val = (u8)tmp;
+	mutex_unlock(&chip->bus_lock);
+
+	return rc;
+}
+
+static int qpnp_tri_led_masked_write(struct qpnp_tri_led_chip *chip,
+				u16 addr, u8 mask, u8 val)
+{
+	int rc;
+
+	mutex_lock(&chip->bus_lock);
+	rc = regmap_update_bits(chip->regmap, chip->reg_base + addr, mask, val);
+	if (rc < 0)
+		dev_err(chip->dev, "Update addr 0x%x to val 0x%x with mask 0x%x failed, rc=%d\n",
+					addr, val, mask, rc);
+	mutex_unlock(&chip->bus_lock);
+
+	return rc;
+}
+
+static int __tri_led_config_pwm(struct qpnp_led_dev *led,
+				struct pwm_setting *pwm)
+{
+	struct pwm_state pstate;
+	int rc;
+
+	pwm_get_state(led->pwm_dev, &pstate);
+	pstate.enabled = !!(pwm->duty_ns != 0);
+	pstate.period = pwm->period_ns;
+	pstate.duty_cycle = pwm->duty_ns;
+	rc = pwm_apply_state(led->pwm_dev, &pstate);
+
+	if (rc < 0)
+		dev_err(led->chip->dev, "Apply PWM state for %s led failed, rc=%d\n",
+					led->cdev.name, rc);
+
+	return rc;
+}
+
+static int __tri_led_set(struct qpnp_led_dev *led)
+{
+	int rc = 0;
+	u8 val = 0, mask = 0;
+
+	rc = __tri_led_config_pwm(led, &led->pwm_setting);
+	if (rc < 0) {
+		dev_err(led->chip->dev, "Configure PWM for %s led failed, rc=%d\n",
+					led->cdev.name, rc);
+		return rc;
+	}
+
+	mask |= 1 << (TRILED_EN_CTL_MAX_BIT - led->id);
+
+	if (led->pwm_setting.duty_ns == 0)
+		val = 0;
+	else
+		val = mask;
+
+	rc = qpnp_tri_led_masked_write(led->chip, TRILED_REG_EN_CTL,
+							mask, val);
+	if (rc < 0)
+		dev_err(led->chip->dev, "Update addr 0x%x failed, rc=%d\n",
+					TRILED_REG_EN_CTL, rc);
+
+	return rc;
+}
+
+static int qpnp_tri_led_set(struct qpnp_led_dev *led)
+{
+	u32 on_ms, off_ms, period_ns, duty_ns;
+	enum led_brightness brightness = led->led_setting.brightness;
+	int rc = 0;
+
+	if (led->led_setting.blink) {
+		on_ms = led->led_setting.on_ms;
+		off_ms = led->led_setting.off_ms;
+		if (on_ms > INT_MAX / NSEC_PER_MSEC)
+			duty_ns = INT_MAX - 1;
+		else
+			duty_ns = on_ms * NSEC_PER_MSEC;
+
+		if (on_ms + off_ms > INT_MAX / NSEC_PER_MSEC) {
+			period_ns = INT_MAX;
+			duty_ns = (period_ns / (on_ms + off_ms)) * on_ms;
+		} else {
+			period_ns = (on_ms + off_ms) * NSEC_PER_MSEC;
+		}
+
+		if (period_ns < duty_ns && duty_ns != 0)
+			period_ns = duty_ns + 1;
+	} else {
+		/* Use initial period if no blinking is required */
+		period_ns = led->pwm_setting.pre_period_ns;
+
+		if (period_ns > INT_MAX / brightness)
+			duty_ns = (period_ns / LED_FULL) * brightness;
+		else
+			duty_ns = (period_ns * brightness) / LED_FULL;
+
+		if (period_ns < duty_ns && duty_ns != 0)
+			period_ns = duty_ns + 1;
+	}
+	dev_dbg(led->chip->dev, "PWM settings for %s led: period = %dns, duty = %dns\n",
+				led->cdev.name, period_ns, duty_ns);
+
+	led->pwm_setting.duty_ns = duty_ns;
+	led->pwm_setting.period_ns = period_ns;
+
+	rc = __tri_led_set(led);
+	if (rc < 0) {
+		dev_err(led->chip->dev, "__tri_led_set %s failed, rc=%d\n",
+				led->cdev.name, rc);
+		return rc;
+	}
+
+	if (led->led_setting.blink) {
+		led->cdev.brightness = LED_FULL;
+		led->blinking = true;
+	} else {
+		led->cdev.brightness = led->led_setting.brightness;
+		led->blinking = false;
+	}
+
+	return rc;
+}
+
+static int qpnp_tri_led_set_brightness(struct led_classdev *led_cdev,
+		enum led_brightness brightness)
+{
+	struct qpnp_led_dev *led =
+		container_of(led_cdev, struct qpnp_led_dev, cdev);
+	int rc = 0;
+
+	mutex_lock(&led->lock);
+	if (brightness > LED_FULL)
+		brightness = LED_FULL;
+
+	if (brightness == led->led_setting.brightness &&
+				!led->blinking) {
+		mutex_unlock(&led->lock);
+		return 0;
+	}
+
+	led->led_setting.brightness = brightness;
+	if (!!brightness)
+		led->led_setting.off_ms = 0;
+	else
+		led->led_setting.on_ms = 0;
+	led->led_setting.blink = false;
+
+	rc = qpnp_tri_led_set(led);
+	if (rc)
+		dev_err(led->chip->dev, "Set led failed for %s, rc=%d\n",
+				led->label, rc);
+
+	mutex_unlock(&led->lock);
+
+	return rc;
+}
+
+static enum led_brightness qpnp_tri_led_get_brightness(
+			struct led_classdev *led_cdev)
+{
+	return led_cdev->brightness;
+}
+
+static int qpnp_tri_led_set_blink(struct led_classdev *led_cdev,
+		unsigned long *on_ms, unsigned long *off_ms)
+{
+	struct qpnp_led_dev *led =
+		container_of(led_cdev, struct qpnp_led_dev, cdev);
+	int rc = 0;
+
+	mutex_lock(&led->lock);
+	if (led->blinking && *on_ms == led->led_setting.on_ms &&
+			*off_ms == led->led_setting.off_ms) {
+		dev_dbg(led_cdev->dev, "Ignore, on/off setting is not changed: on %lums, off %lums\n",
+						*on_ms, *off_ms);
+		mutex_unlock(&led->lock);
+		return 0;
+	}
+
+	if (*on_ms == 0) {
+		led->led_setting.blink = false;
+		led->led_setting.brightness = LED_OFF;
+	} else if (*off_ms == 0) {
+		led->led_setting.blink = false;
+		led->led_setting.brightness = led->cdev.brightness;
+	} else {
+		led->led_setting.on_ms = *on_ms;
+		led->led_setting.off_ms = *off_ms;
+		led->led_setting.blink = true;
+	}
+
+	rc = qpnp_tri_led_set(led);
+	if (rc)
+		dev_err(led->chip->dev, "Set led failed for %s, rc=%d\n",
+				led->label, rc);
+
+	mutex_unlock(&led->lock);
+	return rc;
+}
+
+static int qpnp_tri_led_register(struct qpnp_tri_led_chip *chip)
+{
+	struct qpnp_led_dev *led;
+	int rc, i, j;
+
+	for (i = 0; i < chip->num_leds; i++) {
+		led = &chip->leds[i];
+		mutex_init(&led->lock);
+		led->cdev.name = led->label;
+		led->cdev.max_brightness = LED_FULL;
+		led->cdev.brightness_set_blocking = qpnp_tri_led_set_brightness;
+		led->cdev.brightness_get = qpnp_tri_led_get_brightness;
+		led->cdev.blink_set = qpnp_tri_led_set_blink;
+		led->cdev.default_trigger = led->default_trigger;
+		led->cdev.brightness = LED_OFF;
+		led->cdev.blink_delay_on = LED_BLINK_ON_MS;
+		led->cdev.blink_delay_off = LED_BLINK_OFF_MS;
+
+		rc = devm_led_classdev_register(chip->dev, &led->cdev);
+		if (rc < 0) {
+			dev_err(chip->dev, "%s led class device registering failed, rc=%d\n",
+							led->label, rc);
+			goto destroy;
+		}
+	}
+
+	return 0;
+destroy:
+	for (j = 0; j <= i; j++)
+		mutex_destroy(&chip->leds[i].lock);
+
+	return rc;
+}
+
+static int qpnp_tri_led_hw_init(struct qpnp_tri_led_chip *chip)
+{
+	int rc = 0;
+	u8 val;
+
+	rc = qpnp_tri_led_read(chip, TRILED_REG_TYPE, &val);
+	if (rc < 0) {
+		dev_err(chip->dev, "Read REG_TYPE failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (val != TRILED_TYPE) {
+		dev_err(chip->dev, "invalid subtype(%d)\n", val);
+		return -ENODEV;
+	}
+
+	rc = qpnp_tri_led_read(chip, TRILED_REG_SUBTYPE, &val);
+	if (rc < 0) {
+		dev_err(chip->dev, "Read REG_SUBTYPE failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	chip->subtype = val;
+
+	return 0;
+}
+
+static int qpnp_tri_led_parse_dt(struct qpnp_tri_led_chip *chip)
+{
+	struct device_node *node = chip->dev->of_node, *child_node;
+	struct qpnp_led_dev *led;
+	struct pwm_args pargs;
+	const __be32 *addr;
+	int rc, id, i = 0;
+
+	addr = of_get_address(chip->dev->of_node, 0, NULL, NULL);
+	if (!addr) {
+		dev_err(chip->dev, "Getting address failed\n");
+		return -EINVAL;
+	}
+	chip->reg_base = be32_to_cpu(addr[0]);
+
+	chip->num_leds = of_get_available_child_count(node);
+	if (chip->num_leds == 0) {
+		dev_err(chip->dev, "No led child node defined\n");
+		return -ENODEV;
+	}
+
+	if (chip->num_leds > TRILED_NUM_MAX) {
+		dev_err(chip->dev, "can't support %d leds(max %d)\n",
+				chip->num_leds, TRILED_NUM_MAX);
+		return -EINVAL;
+	}
+
+	chip->leds = devm_kcalloc(chip->dev, chip->num_leds,
+			sizeof(struct qpnp_led_dev), GFP_KERNEL);
+	if (!chip->leds)
+		return -ENOMEM;
+
+	for_each_available_child_of_node(node, child_node) {
+		rc = of_property_read_u32(child_node, "led-sources", &id);
+		if (rc) {
+			dev_err(chip->dev, "Get led-sources failed, rc=%d\n",
+							rc);
+			return rc;
+		}
+
+		if (id >= TRILED_NUM_MAX) {
+			dev_err(chip->dev, "only support 0~%d current source\n",
+					TRILED_NUM_MAX - 1);
+			return -EINVAL;
+		}
+
+		led = &chip->leds[i++];
+		led->chip = chip;
+		led->id = id;
+		led->label =
+			of_get_property(child_node, "label", NULL) ? :
+							child_node->name;
+
+		led->pwm_dev =
+			devm_of_pwm_get(chip->dev, child_node, NULL);
+		if (IS_ERR(led->pwm_dev)) {
+			rc = PTR_ERR(led->pwm_dev);
+			if (rc != -EPROBE_DEFER)
+				dev_err(chip->dev, "Get pwm device for %s led failed, rc=%d\n",
+							led->label, rc);
+			return rc;
+		}
+
+		pwm_get_args(led->pwm_dev, &pargs);
+		if (pargs.period == 0)
+			led->pwm_setting.pre_period_ns = PWM_PERIOD_DEFAULT_NS;
+		else
+			led->pwm_setting.pre_period_ns = pargs.period;
+
+		led->default_trigger = of_get_property(child_node,
+				"linux,default-trigger", NULL);
+	}
+
+	return rc;
+}
+
+static int qpnp_tri_led_probe(struct platform_device *pdev)
+{
+	struct qpnp_tri_led_chip *chip;
+	int rc = 0;
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->dev = &pdev->dev;
+	chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
+	if (!chip->regmap) {
+		dev_err(chip->dev, "Getting regmap failed\n");
+		return -EINVAL;
+	}
+
+	rc = qpnp_tri_led_parse_dt(chip);
+	if (rc < 0) {
+		dev_err(chip->dev, "Devicetree properties parsing failed, rc=%d\n",
+								rc);
+		return rc;
+	}
+
+	mutex_init(&chip->bus_lock);
+
+	rc = qpnp_tri_led_hw_init(chip);
+	if (rc) {
+		dev_err(chip->dev, "HW initialization failed, rc=%d\n", rc);
+		goto destroy;
+	}
+
+	dev_set_drvdata(chip->dev, chip);
+	rc = qpnp_tri_led_register(chip);
+	if (rc < 0) {
+		dev_err(chip->dev, "Registering LED class devices failed, rc=%d\n",
+								rc);
+		goto destroy;
+	}
+
+	dev_dbg(chip->dev, "Tri-led module with subtype 0x%x is detected\n",
+					chip->subtype);
+	return 0;
+destroy:
+	mutex_destroy(&chip->bus_lock);
+	dev_set_drvdata(chip->dev, NULL);
+
+	return rc;
+}
+
+static int qpnp_tri_led_remove(struct platform_device *pdev)
+{
+	int i;
+	struct qpnp_tri_led_chip *chip = dev_get_drvdata(&pdev->dev);
+
+	mutex_destroy(&chip->bus_lock);
+	for (i = 0; i < chip->num_leds; i++)
+		mutex_destroy(&chip->leds[i].lock);
+	dev_set_drvdata(chip->dev, NULL);
+	return 0;
+}
+
+static const struct of_device_id qpnp_tri_led_of_match[] = {
+	{ .compatible = "qcom,tri-led",},
+	{ },
+};
+
+static struct platform_driver qpnp_tri_led_driver = {
+	.driver		= {
+		.name		= "qcom,tri-led",
+		.of_match_table	= qpnp_tri_led_of_match,
+	},
+	.probe		= qpnp_tri_led_probe,
+	.remove		= qpnp_tri_led_remove,
+};
+module_platform_driver(qpnp_tri_led_driver);
+
+MODULE_DESCRIPTION("QTI TRI_LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("leds:qpnp-tri-led");
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 69c8cb0..b897813 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -50,8 +50,7 @@
 #include <linux/ipc_logging.h>
 #include <linux/msm_pcie.h>
 
-#define PCIE_VENDOR_ID_RCP		0x17cb
-#define PCIE_DEVICE_ID_RCP		0x0106
+#define PCIE_VENDOR_ID_QCOM		0x17cb
 
 #define PCIE20_L1SUB_CONTROL1		0x1E4
 #define PCIE20_PARF_DBI_BASE_ADDR       0x350
@@ -63,7 +62,6 @@
 
 #define PCIE_N_SW_RESET(n)			(PCS_PORT(n) + 0x00)
 #define PCIE_N_POWER_DOWN_CONTROL(n)		(PCS_PORT(n) + 0x04)
-#define PCIE_N_PCS_STATUS(n)			(PCS_PORT(n) + 0x174)
 
 #define PCIE_GEN3_COM_INTEGLOOP_GAIN1_MODE0	0x0154
 #define PCIE_GEN3_L0_DRVR_CTRL0			0x080c
@@ -71,7 +69,6 @@
 #define PCIE_GEN3_L0_BIST_ERR_CNT1_STATUS	0x08a8
 #define PCIE_GEN3_L0_BIST_ERR_CNT2_STATUS	0x08ac
 #define PCIE_GEN3_L0_DEBUG_BUS_STATUS4		0x08bc
-#define PCIE_GEN3_PCIE_PHY_PCS_STATUS		0x1aac
 
 #define PCIE20_PARF_SYS_CTRL	     0x00
 #define PCIE20_PARF_PM_CTRL		0x20
@@ -590,6 +587,7 @@
 	uint32_t			switch_latency;
 	uint32_t			wr_halt_size;
 	uint32_t			slv_addr_space_size;
+	uint32_t			phy_status_offset;
 	uint32_t			cpl_timeout;
 	uint32_t			current_bdf;
 	uint32_t			perst_delay_us_min;
@@ -996,11 +994,7 @@
 
 static bool pcie_phy_is_ready(struct msm_pcie_dev_t *dev)
 {
-	u32 pos = (dev->max_link_speed == GEN2_SPEED) ?
-		PCIE_N_PCS_STATUS(dev->rc_idx) :
-		PCIE_GEN3_PCIE_PHY_PCS_STATUS;
-
-	if (readl_relaxed(dev->phy + pos) & BIT(6))
+	if (readl_relaxed(dev->phy + dev->phy_status_offset) & BIT(6))
 		return false;
 	else
 		return true;
@@ -1258,6 +1252,8 @@
 		dev->wr_halt_size);
 	PCIE_DBG_FS(dev, "slv_addr_space_size: 0x%x\n",
 		dev->slv_addr_space_size);
+	PCIE_DBG_FS(dev, "phy_status_offset: 0x%x\n",
+		dev->phy_status_offset);
 	PCIE_DBG_FS(dev, "cpl_timeout: 0x%x\n",
 		dev->cpl_timeout);
 	PCIE_DBG_FS(dev, "current_bdf: 0x%x\n",
@@ -5812,6 +5808,21 @@
 		"RC%d: slv-addr-space-size: 0x%x.\n",
 		rc_idx, msm_pcie_dev[rc_idx].slv_addr_space_size);
 
+	msm_pcie_dev[rc_idx].phy_status_offset = 0;
+	ret = of_property_read_u32(pdev->dev.of_node,
+				"qcom,phy-status-offset",
+				&msm_pcie_dev[rc_idx].phy_status_offset);
+	if (ret) {
+		PCIE_ERR(&msm_pcie_dev[rc_idx],
+			"RC%d: failed to get PCIe PHY status offset.\n",
+			rc_idx);
+		goto decrease_rc_num;
+	} else {
+		PCIE_DBG(&msm_pcie_dev[rc_idx],
+			"RC%d: phy-status-offset: 0x%x.\n",
+			rc_idx, msm_pcie_dev[rc_idx].phy_status_offset);
+	}
+
 	msm_pcie_dev[rc_idx].cpl_timeout = 0;
 	ret = of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,cpl-timeout",
@@ -6208,10 +6219,10 @@
 	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);
 
 	PCIE_DBG(pcie_dev, "hdr_type %d\n", dev->hdr_type);
-	if (dev->hdr_type == 1)
+	if (pci_is_root_bus(dev->bus))
 		dev->class = (dev->class & 0xff) | (PCI_CLASS_BRIDGE_PCI << 8);
 }
-DECLARE_PCI_FIXUP_EARLY(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+DECLARE_PCI_FIXUP_EARLY(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID,
 			msm_pcie_fixup_early);
 
 /* Suspend the PCIe link */
@@ -6294,7 +6305,8 @@
 
 	PCIE_DBG(pcie_dev, "RC%d\n", pcie_dev->rc_idx);
 
-	if (pcie_dev->link_status != MSM_PCIE_LINK_ENABLED)
+	if (pcie_dev->link_status != MSM_PCIE_LINK_ENABLED ||
+		!pci_is_root_bus(dev->bus))
 		return;
 
 	spin_lock_irqsave(&pcie_dev->cfg_lock,
@@ -6319,7 +6331,7 @@
 
 	mutex_unlock(&pcie_dev->recovery_lock);
 }
-DECLARE_PCI_FIXUP_SUSPEND(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+DECLARE_PCI_FIXUP_SUSPEND(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID,
 			  msm_pcie_fixup_suspend);
 
 /* Resume the PCIe link */
@@ -6393,7 +6405,7 @@
 	PCIE_DBG(pcie_dev, "RC%d\n", pcie_dev->rc_idx);
 
 	if ((pcie_dev->link_status != MSM_PCIE_LINK_DISABLED) ||
-		pcie_dev->user_suspend)
+		pcie_dev->user_suspend || !pci_is_root_bus(dev->bus))
 		return;
 
 	mutex_lock(&pcie_dev->recovery_lock);
@@ -6405,7 +6417,7 @@
 
 	mutex_unlock(&pcie_dev->recovery_lock);
 }
-DECLARE_PCI_FIXUP_RESUME(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+DECLARE_PCI_FIXUP_RESUME(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID,
 				 msm_pcie_fixup_resume);
 
 static void msm_pcie_fixup_resume_early(struct pci_dev *dev)
@@ -6416,7 +6428,7 @@
 	PCIE_DBG(pcie_dev, "RC%d\n", pcie_dev->rc_idx);
 
 	if ((pcie_dev->link_status != MSM_PCIE_LINK_DISABLED) ||
-		pcie_dev->user_suspend)
+		pcie_dev->user_suspend || !pci_is_root_bus(dev->bus))
 		return;
 
 	mutex_lock(&pcie_dev->recovery_lock);
@@ -6427,7 +6439,7 @@
 
 	mutex_unlock(&pcie_dev->recovery_lock);
 }
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID,
 				 msm_pcie_fixup_resume_early);
 
 int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr, void *user,
diff --git a/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c b/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c
index 613bed3..2723a35 100644
--- a/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c
+++ b/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 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
@@ -140,7 +140,7 @@
 	ipa_rm_it_handles[resource_name].work_in_progress = false;
 	pwlock = &(ipa_rm_it_handles[resource_name].w_lock);
 	name = ipa_rm_it_handles[resource_name].w_lock_name;
-	snprintf(name, MAX_WS_NAME, "IPA_RM%d\n", resource_name);
+	snprintf(name, MAX_WS_NAME, "IPA_RM%d", resource_name);
 	wakeup_source_init(pwlock, name);
 	INIT_DELAYED_WORK(&ipa_rm_it_handles[resource_name].work,
 			  ipa_rm_inactivity_timer_func);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index c0fe730..90edd2b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -222,7 +222,13 @@
 	tx_pkt->no_unmap_dma = true;
 	tx_pkt->sys = sys;
 	spin_lock_bh(&sys->spinlock);
+	if (unlikely(!sys->nop_pending)) {
+		spin_unlock_bh(&sys->spinlock);
+		kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
+		return;
+	}
 	list_add_tail(&tx_pkt->link, &sys->head_desc_list);
+	sys->nop_pending = false;
 	spin_unlock_bh(&sys->spinlock);
 
 	memset(&nop_xfer, 0, sizeof(nop_xfer));
@@ -273,6 +279,7 @@
 	int result;
 	u32 mem_flag = GFP_ATOMIC;
 	const struct ipa_gsi_ep_config *gsi_ep_cfg;
+	bool send_nop = false;
 
 	if (unlikely(!in_atomic))
 		mem_flag = GFP_KERNEL;
@@ -410,10 +417,14 @@
 	}
 	kfree(gsi_xfer_elem_array);
 
+	if (sys->use_comm_evt_ring && !sys->nop_pending) {
+		sys->nop_pending = true;
+		send_nop = true;
+	}
 	spin_unlock_bh(&sys->spinlock);
 
 	/* set the timer for sending the NOP descriptor */
-	if (sys->use_comm_evt_ring && !hrtimer_active(&sys->db_timer)) {
+	if (send_nop) {
 		ktime_t time = ktime_set(0, IPA_TX_SEND_COMPL_NOP_DELAY_NS);
 
 		IPADBG_LOW("scheduling timer for ch %lu\n",
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index d7d74a3..03e224b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -626,6 +626,7 @@
 	struct delayed_work switch_to_intr_work;
 	enum ipa3_sys_pipe_policy policy;
 	bool use_comm_evt_ring;
+	bool nop_pending;
 	int (*pyld_hdlr)(struct sk_buff *skb, struct ipa3_sys_context *sys);
 	struct sk_buff * (*get_skb)(unsigned int len, gfp_t flags);
 	void (*free_skb)(struct sk_buff *skb);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 1782fdc..9974b87 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -1117,7 +1117,7 @@
 			true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
-			{ 7, 0, 8, 16, IPA_EE_UC } },
+			{ 6, 2, 8, 16, IPA_EE_UC } },
 	[IPA_4_0][IPA_CLIENT_USB_PROD]            = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			true,
@@ -1153,13 +1153,7 @@
 			true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
-			{ 9, 1, 8, 16, IPA_EE_UC } },
-	[IPA_4_0][IPA_CLIENT_Q6_LAN_PROD]         = {
-			true, IPA_v4_0_GROUP_UL_DL,
-			true,
-			IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR,
-			{ 6, 2, 12, 24, IPA_EE_Q6 } },
+			{ 9, 0, 8, 16, IPA_EE_UC } },
 	[IPA_4_0][IPA_CLIENT_Q6_WAN_PROD]         = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			true,
@@ -1196,13 +1190,13 @@
 			true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
-			{7, 0, 8, 16, IPA_EE_UC } },
+			{ 7, 9, 8, 16, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_TEST4_PROD]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			true,
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_DDR,
-			{ 8, 10, 8, 16, IPA_EE_AP } },
+			{8, 10, 8, 16, IPA_EE_AP } },
 
 
 	[IPA_4_0][IPA_CLIENT_WLAN1_CONS]          = {
@@ -1210,7 +1204,7 @@
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 18, 2, 6, 9, IPA_EE_UC } },
+			{ 18, 3, 6, 9, IPA_EE_UC } },
 	[IPA_4_0][IPA_CLIENT_WLAN2_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
@@ -1258,7 +1252,7 @@
 			true,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 22, 3, 17, 17, IPA_EE_UC } },
+			{ 22, 1, 17, 17, IPA_EE_UC } },
 	[IPA_4_0][IPA_CLIENT_Q6_LAN_CONS]         = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
@@ -1284,25 +1278,25 @@
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 12, 2, 5, 5, IPA_EE_AP } },
+			{ 11, 6, 9, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_TEST1_CONS]           = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR,
-			{ 12, 2, 5, 5, IPA_EE_AP } },
+			QMB_MASTER_SELECT_PCIE,
+			{ 11, 6, 9, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_TEST2_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 18, 2, 6, 9, IPA_EE_UC } },
+			{ 12, 2, 5, 5, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_TEST3_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR,
-			{ 20, 13, 9, 9, IPA_EE_AP } },
+			QMB_MASTER_SELECT_PCIE,
+			{ 19, 12, 9, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_TEST4_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
@@ -1318,12 +1312,6 @@
 			{ 31, 31, 8, 8, IPA_EE_AP } },
 
 	/* IPA_4_0_MHI */
-	[IPA_4_0_MHI][IPA_CLIENT_USB_PROD]            = {
-			false, IPA_EP_NOT_ALLOCATED,
-			true,
-			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR,
-			{ -1, -1, -1, -1, -1 } },
 	[IPA_4_0_MHI][IPA_CLIENT_APPS_WAN_PROD]   = {
 			true, IPA_v4_0_MHI_GROUP_DDR,
 			true,
@@ -1342,12 +1330,6 @@
 			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
 			QMB_MASTER_SELECT_PCIE,
 			{ 1, 0, 8, 16, IPA_EE_AP } },
-	[IPA_4_0_MHI][IPA_CLIENT_Q6_LAN_PROD]         = {
-			true, IPA_v4_0_MHI_GROUP_DDR,
-			true,
-			IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
-			QMB_MASTER_SELECT_DDR,
-			{ 6, 2, 12, 24, IPA_EE_Q6 } },
 	[IPA_4_0_MHI][IPA_CLIENT_Q6_WAN_PROD]         = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			true,
@@ -1404,18 +1386,7 @@
 			QMB_MASTER_SELECT_DDR,
 			{ 8, 10, 8, 16, IPA_EE_AP } },
 
-	[IPA_4_0_MHI][IPA_CLIENT_USB_CONS]            = {
-			false, IPA_EP_NOT_ALLOCATED,
-			false,
-			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR,
-			{ -1, -1, -1, -1, -1 } },
-	[IPA_4_0_MHI][IPA_CLIENT_USB_DPL_CONS]        = {
-			false, IPA_EP_NOT_ALLOCATED,
-			false,
-			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR,
-			{ -1, -1, -1, -1, -1 } },
+
 	[IPA_4_0_MHI][IPA_CLIENT_APPS_LAN_CONS]       = {
 			true, IPA_v4_0_MHI_GROUP_DDR,
 			false,
@@ -1470,25 +1441,25 @@
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 12, 2, 5, 5, IPA_EE_AP } },
+			{ 11, 6, 9, 9, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_TEST1_CONS]           = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR,
-			{ 12, 2, 5, 5, IPA_EE_AP } },
+			QMB_MASTER_SELECT_PCIE,
+			{ 11, 6, 9, 9, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_TEST2_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_PCIE,
-			{ 18, 11, 6, 9, IPA_EE_AP } },
+			QMB_MASTER_SELECT_DDR,
+			{ 12, 2, 5, 5, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_TEST3_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
-			QMB_MASTER_SELECT_DDR,
-			{ 20, 13, 9, 9, IPA_EE_AP } },
+			QMB_MASTER_SELECT_PCIE,
+			{ 19, 12, 9, 9, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_TEST4_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
index bc4df04..7a93e0e 100644
--- a/drivers/platform/msm/msm_ext_display.c
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -44,6 +44,20 @@
 	EXTCON_NONE,
 };
 
+static int msm_ext_disp_find_index(struct extcon_dev *edev,
+		enum msm_ext_disp_type id)
+{
+	int i;
+
+	/* Find the the index of extcon cable in edev->supported_cable */
+	for (i = 0; i < edev->max_supported; i++) {
+		if (edev->supported_cable[i] == id)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
 static int msm_ext_disp_extcon_register(struct msm_ext_disp *ext_disp)
 {
 	int ret = 0;
@@ -145,7 +159,8 @@
 		enum msm_ext_disp_cable_state new_state)
 {
 	int ret = 0;
-	int state;
+	int state, index;
+	enum msm_ext_disp_cable_state current_state;
 
 	if (!ext_disp->ops) {
 		pr_err("codec not registered, skip notification\n");
@@ -154,13 +169,27 @@
 	}
 
 	state = ext_disp->audio_sdev.state;
-	ret = extcon_set_state_sync(&ext_disp->audio_sdev,
-			ext_disp->current_disp, !!new_state);
 
-	pr_debug("Audio state %s %d\n",
-			ext_disp->audio_sdev.state == state ?
-			"is same" : "switched to",
-			ext_disp->audio_sdev.state);
+	index = msm_ext_disp_find_index(&ext_disp->audio_sdev, type);
+	if (index < 0 || index >= ext_disp->audio_sdev.max_supported) {
+		pr_err("invalid index\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	if (state & BIT(index))
+		current_state = EXT_DISPLAY_CABLE_CONNECT;
+	else
+		current_state = EXT_DISPLAY_CABLE_DISCONNECT;
+
+	if (current_state == new_state) {
+		ret = -EEXIST;
+		pr_debug("same state\n");
+	} else {
+		ret = extcon_set_state_sync(&ext_disp->audio_sdev,
+			ext_disp->current_disp, !!new_state);
+		pr_debug("state changed to %d\n", new_state);
+	}
 end:
 	return ret;
 }
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e7d13ae..8e367c5 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -350,6 +350,16 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-rcar.
 
+config PWM_QTI_LPG
+	tristate "Qualcomm Technologies, Inc. LPG driver"
+	depends on  MFD_SPMI_PMIC && OF
+	help
+	  This driver supports the LPG (Light Pulse Generator) module found in
+	  Qualcomm Technologies, Inc. PMIC chips. Each LPG channel can be
+	  configured to operate in PWM mode to output a fixed amplitude with
+	  variable duty cycle or in LUT (Look up table) mode to output PWM
+	  signal with a modulated amplitude.
+
 config PWM_RENESAS_TPU
 	tristate "Renesas TPU PWM support"
 	depends on ARCH_RENESAS || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 24c1baf..9453eb0 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -33,6 +33,7 @@
 obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
 obj-$(CONFIG_PWM_QPNP)		+= pwm-qpnp.o
 obj-$(CONFIG_PWM_RCAR)		+= pwm-rcar.o
+obj-$(CONFIG_PWM_QTI_LPG)	+= pwm-qti-lpg.o
 obj-$(CONFIG_PWM_RENESAS_TPU)	+= pwm-renesas-tpu.o
 obj-$(CONFIG_PWM_ROCKCHIP)	+= pwm-rockchip.o
 obj-$(CONFIG_PWM_SAMSUNG)	+= pwm-samsung.o
diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c
new file mode 100644
index 0000000..328f4b6
--- /dev/null
+++ b/drivers/pwm/pwm-qti-lpg.c
@@ -0,0 +1,570 @@
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define REG_SIZE_PER_LPG	0x100
+
+#define REG_LPG_PWM_SIZE_CLK		0x41
+#define REG_LPG_PWM_FREQ_PREDIV_CLK	0x42
+#define REG_LPG_PWM_TYPE_CONFIG		0x43
+#define REG_LPG_PWM_VALUE_LSB		0x44
+#define REG_LPG_PWM_VALUE_MSB		0x45
+#define REG_LPG_ENABLE_CONTROL		0x46
+#define REG_LPG_PWM_SYNC		0x47
+
+/* REG_LPG_PWM_SIZE_CLK */
+#define LPG_PWM_SIZE_MASK		BIT(4)
+#define LPG_PWM_SIZE_SHIFT		4
+#define LPG_PWM_CLK_FREQ_SEL_MASK	GENMASK(1, 0)
+
+/* REG_LPG_PWM_FREQ_PREDIV_CLK */
+#define LPG_PWM_FREQ_PREDIV_MASK	GENMASK(6, 5)
+#define LPG_PWM_FREQ_PREDIV_SHIFT	5
+#define LPG_PWM_FREQ_EXPONENT_MASK	GENMASK(2, 0)
+
+/* REG_LPG_PWM_TYPE_CONFIG */
+#define LPG_PWM_EN_GLITCH_REMOVAL_MASK	BIT(5)
+
+/* REG_LPG_PWM_VALUE_LSB */
+#define LPG_PWM_VALUE_LSB_MASK		GENMASK(7, 0)
+
+/* REG_LPG_PWM_VALUE_MSB */
+#define LPG_PWM_VALUE_MSB_MASK		BIT(0)
+
+/* REG_LPG_ENABLE_CONTROL */
+#define LPG_EN_LPG_OUT_BIT		BIT(7)
+#define LPG_PWM_SRC_SELECT_MASK		BIT(2)
+#define LPG_PWM_SRC_SELECT_SHIFT	2
+#define LPG_EN_RAMP_GEN_MASK		BIT(1)
+#define LPG_EN_RAMP_GEN_SHIFT		1
+
+/* REG_LPG_PWM_SYNC */
+#define LPG_PWM_VALUE_SYNC		BIT(0)
+
+#define NUM_PWM_SIZE			2
+#define NUM_PWM_CLK			3
+#define NUM_CLK_PREDIV			4
+#define NUM_PWM_EXP			8
+
+enum {
+	LUT_PATTERN = 0,
+	PWM_OUTPUT,
+};
+
+static const int pwm_size[NUM_PWM_SIZE] = {6, 9};
+static const int clk_freq_hz[NUM_PWM_CLK] = {1024, 32768, 19200000};
+static const int clk_prediv[NUM_CLK_PREDIV] = {1, 3, 5, 6};
+static const int pwm_exponent[NUM_PWM_EXP] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+struct lpg_pwm_config {
+	u32	pwm_size;
+	u32	pwm_clk;
+	u32	prediv;
+	u32	clk_exp;
+	u16	pwm_value;
+	u32	best_period_ns;
+};
+
+struct qpnp_lpg_channel {
+	struct qpnp_lpg_chip		*chip;
+	struct lpg_pwm_config		pwm_config;
+	u32				lpg_idx;
+	u32				reg_base;
+	u8				src_sel;
+	int				current_period_ns;
+	int				current_duty_ns;
+};
+
+struct qpnp_lpg_chip {
+	struct pwm_chip		pwm_chip;
+	struct regmap		*regmap;
+	struct device		*dev;
+	struct qpnp_lpg_channel	*lpgs;
+	struct mutex		bus_lock;
+	u32			num_lpgs;
+};
+
+static int qpnp_lpg_write(struct qpnp_lpg_channel *lpg, u16 addr, u8 val)
+{
+	int rc;
+
+	mutex_lock(&lpg->chip->bus_lock);
+	rc = regmap_write(lpg->chip->regmap, lpg->reg_base + addr, val);
+	if (rc < 0)
+		dev_err(lpg->chip->dev, "Write addr 0x%x with value %d failed, rc=%d\n",
+				lpg->reg_base + addr, val, rc);
+	mutex_unlock(&lpg->chip->bus_lock);
+
+	return rc;
+}
+
+static int qpnp_lpg_masked_write(struct qpnp_lpg_channel *lpg,
+				u16 addr, u8 mask, u8 val)
+{
+	int rc;
+
+	mutex_lock(&lpg->chip->bus_lock);
+	rc = regmap_update_bits(lpg->chip->regmap, lpg->reg_base + addr,
+							mask, val);
+	if (rc < 0)
+		dev_err(lpg->chip->dev, "Update addr 0x%x to val 0x%x with mask 0x%x failed, rc=%d\n",
+				lpg->reg_base + addr, val, mask, rc);
+	mutex_unlock(&lpg->chip->bus_lock);
+
+	return rc;
+}
+
+static struct qpnp_lpg_channel *pwm_dev_to_qpnp_lpg(struct pwm_chip *pwm_chip,
+				struct pwm_device *pwm) {
+
+	struct qpnp_lpg_chip *chip = container_of(pwm_chip,
+			struct qpnp_lpg_chip, pwm_chip);
+	u32 hw_idx = pwm->hwpwm;
+
+	if (hw_idx >= chip->num_lpgs) {
+		dev_err(chip->dev, "hw index %d out of range [0-%d]\n",
+				hw_idx, chip->num_lpgs - 1);
+		return NULL;
+	}
+
+	return &chip->lpgs[hw_idx];
+}
+
+static int __find_index_in_array(int member, const int array[], int length)
+{
+	int i;
+
+	for (i = 0; i < length; i++) {
+		if (member == array[i])
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int qpnp_lpg_set_pwm_config(struct qpnp_lpg_channel *lpg)
+{
+	int rc;
+	u8 val, mask;
+	int pwm_size_idx, pwm_clk_idx, prediv_idx, clk_exp_idx;
+
+	pwm_size_idx = __find_index_in_array(lpg->pwm_config.pwm_size,
+			pwm_size, ARRAY_SIZE(pwm_size));
+	pwm_clk_idx = __find_index_in_array(lpg->pwm_config.pwm_clk,
+			clk_freq_hz, ARRAY_SIZE(clk_freq_hz));
+	prediv_idx = __find_index_in_array(lpg->pwm_config.prediv,
+			clk_prediv, ARRAY_SIZE(clk_prediv));
+	clk_exp_idx = __find_index_in_array(lpg->pwm_config.clk_exp,
+			pwm_exponent, ARRAY_SIZE(pwm_exponent));
+
+	if (pwm_size_idx < 0 || pwm_clk_idx < 0
+			|| prediv_idx < 0 || clk_exp_idx < 0)
+		return -EINVAL;
+
+	/* pwm_clk_idx is 1 bit lower than the register value */
+	pwm_clk_idx += 1;
+	val = pwm_size_idx << LPG_PWM_SIZE_SHIFT | pwm_clk_idx;
+	mask = LPG_PWM_SIZE_MASK | LPG_PWM_CLK_FREQ_SEL_MASK;
+	rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_SIZE_CLK, mask, val);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write LPG_PWM_SIZE_CLK failed, rc=%d\n",
+							rc);
+		return rc;
+	}
+
+	val = prediv_idx << LPG_PWM_FREQ_PREDIV_SHIFT | clk_exp_idx;
+	mask = LPG_PWM_FREQ_PREDIV_MASK | LPG_PWM_FREQ_EXPONENT_MASK;
+	rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_FREQ_PREDIV_CLK, mask, val);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write LPG_PWM_FREQ_PREDIV_CLK failed, rc=%d\n",
+							rc);
+		return rc;
+	}
+
+	val = lpg->pwm_config.pwm_value & LPG_PWM_VALUE_LSB_MASK;
+	rc = qpnp_lpg_write(lpg, REG_LPG_PWM_VALUE_LSB, val);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write LPG_PWM_VALUE_LSB failed, rc=%d\n",
+							rc);
+		return rc;
+	}
+
+	val = lpg->pwm_config.pwm_value >> 8;
+	mask = LPG_PWM_VALUE_MSB_MASK;
+	rc = qpnp_lpg_masked_write(lpg, REG_LPG_PWM_VALUE_MSB, mask, val);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write LPG_PWM_VALUE_MSB failed, rc=%d\n",
+							rc);
+		return rc;
+	}
+
+	val = LPG_PWM_VALUE_SYNC;
+	rc = qpnp_lpg_write(lpg, REG_LPG_PWM_SYNC, val);
+	if (rc < 0) {
+		dev_err(lpg->chip->dev, "Write LPG_PWM_SYNC failed, rc=%d\n",
+							rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void __qpnp_lpg_calc_pwm_period(int period_ns,
+			struct lpg_pwm_config *pwm_config)
+{
+	struct lpg_pwm_config configs[NUM_PWM_SIZE];
+	int i, j, m, n;
+	int tmp1, tmp2;
+	int clk_period_ns = 0, pwm_clk_period_ns;
+	int clk_delta_ns = INT_MAX, min_clk_delta_ns = INT_MAX;
+	int pwm_period_delta = INT_MAX, min_pwm_period_delta = INT_MAX;
+	int pwm_size_step;
+
+	/*
+	 *              (2^pwm_size) * (2^pwm_exp) * prediv * NSEC_PER_SEC
+	 * pwm_period = ---------------------------------------------------
+	 *                               clk_freq_hz
+	 *
+	 * Searching the closest settings for the requested PWM period.
+	 */
+	for (n = 0; n < ARRAY_SIZE(pwm_size); n++) {
+		pwm_clk_period_ns = period_ns >> pwm_size[n];
+		for (i = ARRAY_SIZE(clk_freq_hz) - 1; i >= 0; i--) {
+			for (j = 0; j < ARRAY_SIZE(clk_prediv); j++) {
+				for (m = 0; m < ARRAY_SIZE(pwm_exponent); m++) {
+					tmp1 = 1 << pwm_exponent[m];
+					tmp1 *= clk_prediv[j];
+					tmp2 = NSEC_PER_SEC / clk_freq_hz[i];
+
+					clk_period_ns = tmp1 * tmp2;
+
+					clk_delta_ns = abs(pwm_clk_period_ns
+						- clk_period_ns);
+					/*
+					 * Find the closest setting for
+					 * PWM frequency predivide value
+					 */
+					if (clk_delta_ns < min_clk_delta_ns) {
+						min_clk_delta_ns
+							= clk_delta_ns;
+						configs[n].pwm_clk
+							= clk_freq_hz[i];
+						configs[n].prediv
+							= clk_prediv[j];
+						configs[n].clk_exp
+							= pwm_exponent[m];
+						configs[n].pwm_size
+							= pwm_size[n];
+						configs[n].best_period_ns
+							= clk_period_ns;
+					}
+				}
+			}
+		}
+
+		configs[n].best_period_ns *= 1 << pwm_size[n];
+		/* Find the closest setting for PWM period */
+		if (min_clk_delta_ns < INT_MAX >> pwm_size[n])
+			pwm_period_delta = min_clk_delta_ns << pwm_size[n];
+		else
+			pwm_period_delta = INT_MAX;
+		if (pwm_period_delta < min_pwm_period_delta) {
+			min_pwm_period_delta = pwm_period_delta;
+			memcpy(pwm_config, &configs[n],
+					sizeof(struct lpg_pwm_config));
+		}
+	}
+
+	/* Larger PWM size can achieve better resolution for PWM duty */
+	for (n = ARRAY_SIZE(pwm_size) - 1; n > 0; n--) {
+		if (pwm_config->pwm_size >= pwm_size[n])
+			break;
+		pwm_size_step = pwm_size[n] - pwm_config->pwm_size;
+		if (pwm_config->clk_exp >= pwm_size_step) {
+			pwm_config->pwm_size = pwm_size[n];
+			pwm_config->clk_exp -= pwm_size_step;
+		}
+	}
+	pr_debug("PWM setting for period_ns %d: pwm_clk = %dHZ, prediv = %d, exponent = %d, pwm_size = %d\n",
+			period_ns, pwm_config->pwm_clk, pwm_config->prediv,
+			pwm_config->clk_exp, pwm_config->pwm_size);
+	pr_debug("Actual period: %dns\n", pwm_config->best_period_ns);
+}
+
+static void __qpnp_lpg_calc_pwm_duty(int period_ns, int duty_ns,
+			struct lpg_pwm_config *pwm_config)
+{
+	u16 pwm_value, max_pwm_value;
+
+	if ((1 << pwm_config->pwm_size) > (INT_MAX / duty_ns))
+		pwm_value = duty_ns / (period_ns >> pwm_config->pwm_size);
+	else
+		pwm_value = (duty_ns << pwm_config->pwm_size) / period_ns;
+
+	max_pwm_value = (1 << pwm_config->pwm_size) - 1;
+	if (pwm_value > max_pwm_value)
+		pwm_value = max_pwm_value;
+	pwm_config->pwm_value = pwm_value;
+}
+
+static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip,
+		struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	struct qpnp_lpg_channel *lpg;
+	int rc = 0;
+
+	lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
+	if (lpg == NULL) {
+		dev_err(pwm_chip->dev, "lpg not found\n");
+		return -ENODEV;
+	}
+
+	if (duty_ns > period_ns) {
+		dev_err(pwm_chip->dev, "Duty %dns is larger than period %dns\n",
+						duty_ns, period_ns);
+		return -EINVAL;
+	}
+
+	if (period_ns != lpg->current_period_ns)
+		__qpnp_lpg_calc_pwm_period(period_ns, &lpg->pwm_config);
+
+	if (period_ns != lpg->current_period_ns ||
+			duty_ns != lpg->current_duty_ns)
+		__qpnp_lpg_calc_pwm_duty(period_ns, duty_ns, &lpg->pwm_config);
+
+	rc = qpnp_lpg_set_pwm_config(lpg);
+	if (rc < 0)
+		dev_err(pwm_chip->dev, "Config PWM failed for channel %d, rc=%d\n",
+						lpg->lpg_idx, rc);
+
+	return rc;
+}
+
+static int qpnp_lpg_pwm_enable(struct pwm_chip *pwm_chip,
+				struct pwm_device *pwm)
+{
+	struct qpnp_lpg_channel *lpg;
+	int rc = 0;
+	u8 mask, val;
+
+	lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
+	if (lpg == NULL) {
+		dev_err(pwm_chip->dev, "lpg not found\n");
+		return -ENODEV;
+	}
+
+	mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT;
+	val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT | LPG_EN_LPG_OUT_BIT;
+
+	rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val);
+	if (rc < 0)
+		dev_err(pwm_chip->dev, "Enable PWM output failed for channel %d, rc=%d\n",
+						lpg->lpg_idx, rc);
+
+	return rc;
+}
+
+static void qpnp_lpg_pwm_disable(struct pwm_chip *pwm_chip,
+				struct pwm_device *pwm)
+{
+	struct qpnp_lpg_channel *lpg;
+	int rc;
+	u8 mask, val;
+
+	lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
+	if (lpg == NULL) {
+		dev_err(pwm_chip->dev, "lpg not found\n");
+		return;
+	}
+
+	mask = LPG_PWM_SRC_SELECT_MASK | LPG_EN_LPG_OUT_BIT;
+	val = lpg->src_sel << LPG_PWM_SRC_SELECT_SHIFT;
+
+	rc = qpnp_lpg_masked_write(lpg, REG_LPG_ENABLE_CONTROL, mask, val);
+	if (rc < 0)
+		dev_err(pwm_chip->dev, "Disable PWM output failed for channel %d, rc=%d\n",
+						lpg->lpg_idx, rc);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void qpnp_lpg_pwm_dbg_show(struct pwm_chip *pwm_chip, struct seq_file *s)
+{
+	struct qpnp_lpg_channel *lpg;
+	struct lpg_pwm_config *cfg;
+	struct pwm_device *pwm;
+	int i;
+
+	for (i = 0; i < pwm_chip->npwm; i++) {
+		pwm = &pwm_chip->pwms[i];
+
+		lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm);
+		if (lpg == NULL) {
+			dev_err(pwm_chip->dev, "lpg not found\n");
+			return;
+		}
+
+		if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
+			seq_printf(s, "LPG %d is requested by %s\n",
+					lpg->lpg_idx + 1, pwm->label);
+		} else {
+			seq_printf(s, "LPG %d is free\n",
+					lpg->lpg_idx + 1);
+			continue;
+		}
+
+		if (pwm_is_enabled(pwm)) {
+			seq_puts(s, "  enabled\n");
+		} else {
+			seq_puts(s, "  disabled\n");
+			continue;
+		}
+
+		cfg = &lpg->pwm_config;
+		seq_printf(s, "     clk = %dHz\n", cfg->pwm_clk);
+		seq_printf(s, "     pwm_size = %d\n", cfg->pwm_size);
+		seq_printf(s, "     prediv = %d\n", cfg->prediv);
+		seq_printf(s, "     exponent = %d\n", cfg->clk_exp);
+		seq_printf(s, "     pwm_value = %d\n", cfg->pwm_value);
+		seq_printf(s, "  Requested period: %dns, best period = %dns\n",
+				pwm_get_period(pwm), cfg->best_period_ns);
+	}
+}
+#endif
+
+static const struct pwm_ops qpnp_lpg_pwm_ops = {
+	.config = qpnp_lpg_pwm_config,
+	.enable = qpnp_lpg_pwm_enable,
+	.disable = qpnp_lpg_pwm_disable,
+#ifdef CONFIG_DEBUG_FS
+	.dbg_show = qpnp_lpg_pwm_dbg_show,
+#endif
+	.owner = THIS_MODULE,
+};
+
+static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip)
+{
+	int rc = 0, i;
+	u64 base, length;
+	const __be32 *addr;
+
+	addr = of_get_address(chip->dev->of_node, 0, NULL, NULL);
+	if (!addr) {
+		dev_err(chip->dev, "Getting address failed\n");
+		return -EINVAL;
+	}
+	base = be32_to_cpu(addr[0]);
+	length = be32_to_cpu(addr[1]);
+
+	chip->num_lpgs = length / REG_SIZE_PER_LPG;
+	chip->lpgs = devm_kcalloc(chip->dev, chip->num_lpgs,
+			sizeof(*chip->lpgs), GFP_KERNEL);
+	if (!chip->lpgs)
+		return -ENOMEM;
+
+	for (i = 0; i < chip->num_lpgs; i++) {
+		chip->lpgs[i].chip = chip;
+		chip->lpgs[i].lpg_idx = i;
+		chip->lpgs[i].reg_base = base + i * REG_SIZE_PER_LPG;
+		chip->lpgs[i].src_sel = PWM_OUTPUT;
+	}
+
+	return rc;
+}
+
+static int qpnp_lpg_probe(struct platform_device *pdev)
+{
+	int rc;
+	struct qpnp_lpg_chip *chip;
+
+	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->dev = &pdev->dev;
+	chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
+	if (!chip->regmap) {
+		dev_err(chip->dev, "Getting regmap failed\n");
+		return -EINVAL;
+	}
+
+	rc = qpnp_lpg_parse_dt(chip);
+	if (rc < 0) {
+		dev_err(chip->dev, "Devicetree properties parsing failed, rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	dev_set_drvdata(chip->dev, chip);
+
+	mutex_init(&chip->bus_lock);
+	chip->pwm_chip.dev = chip->dev;
+	chip->pwm_chip.base = -1;
+	chip->pwm_chip.npwm = chip->num_lpgs;
+	chip->pwm_chip.ops = &qpnp_lpg_pwm_ops;
+
+	rc = pwmchip_add(&chip->pwm_chip);
+	if (rc < 0) {
+		dev_err(chip->dev, "Add pwmchip failed, rc=%d\n", rc);
+		mutex_destroy(&chip->bus_lock);
+	}
+
+	return rc;
+}
+
+static int qpnp_lpg_remove(struct platform_device *pdev)
+{
+	struct qpnp_lpg_chip *chip = dev_get_drvdata(&pdev->dev);
+	int rc = 0;
+
+	rc = pwmchip_remove(&chip->pwm_chip);
+	if (rc < 0)
+		dev_err(chip->dev, "Remove pwmchip failed, rc=%d\n", rc);
+
+	mutex_destroy(&chip->bus_lock);
+	dev_set_drvdata(chip->dev, NULL);
+
+	return rc;
+}
+
+static const struct of_device_id qpnp_lpg_of_match[] = {
+	{ .compatible = "qcom,pwm-lpg",},
+	{ },
+};
+
+static struct platform_driver qpnp_lpg_driver = {
+	.driver		= {
+		.name		= "qcom,pwm-lpg",
+		.of_match_table	= qpnp_lpg_of_match,
+	},
+	.probe		= qpnp_lpg_probe,
+	.remove		= qpnp_lpg_remove,
+};
+module_platform_driver(qpnp_lpg_driver);
+
+MODULE_DESCRIPTION("QTI LPG driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("pwm:pwm-lpg");
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index a28644d..2fb95fe 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -2262,8 +2262,6 @@
 
 	set_bit(ICNSS_FW_READY, &penv->state);
 
-	icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_READY, NULL);
-
 	icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state);
 
 	icnss_hw_power_off(penv);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 63ce902..d5e79f1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -55,6 +55,12 @@
  */
 #define CFG80211_ROAMED_API_UNIFIED 1
 
+/* Indicate backport support for DBS scan control */
+#define CFG80211_SCAN_DBS_CONTROL_SUPPORT 1
+
+/* Indicate backport support for per chain rssi scan */
+#define CFG80211_SCAN_PER_CHAIN_RSSI_SUPPORT 1
+
 /**
  * DOC: Introduction
  *
@@ -1742,6 +1748,8 @@
  *	by %parent_bssid.
  * @parent_bssid: the BSS according to which %parent_tsf is set. This is set to
  *	the BSS that requested the scan in which the beacon/probe was received.
+ * @chains: bitmask for filled values in @chain_signal.
+ * @chain_signal: per-chain signal strength of last received BSS in dBm.
  */
 struct cfg80211_inform_bss {
 	struct ieee80211_channel *chan;
@@ -1750,6 +1758,8 @@
 	u64 boottime_ns;
 	u64 parent_tsf;
 	u8 parent_bssid[ETH_ALEN] __aligned(2);
+	u8 chains;
+	s8 chain_signal[IEEE80211_MAX_CHAINS];
 };
 
 /**
@@ -1793,6 +1803,8 @@
  *	that holds the beacon data. @beacon_ies is still valid, of course, and
  *	points to the same data as hidden_beacon_bss->beacon_ies in that case.
  * @signal: signal strength value (type depends on the wiphy's signal_type)
+ * @chains: bitmask for filled values in @chain_signal.
+ * @chain_signal: per-chain signal strength of last received BSS in dBm.
  * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
  */
 struct cfg80211_bss {
@@ -1811,6 +1823,8 @@
 	u16 capability;
 
 	u8 bssid[ETH_ALEN];
+	u8 chains;
+	s8 chain_signal[IEEE80211_MAX_CHAINS];
 
 	u8 priv[0] __aligned(sizeof(void *));
 };
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index ad38816..31b4cce 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 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
@@ -23,7 +23,6 @@
 #endif
 
 enum icnss_uevent {
-	ICNSS_UEVENT_FW_READY,
 	ICNSS_UEVENT_FW_CRASHED,
 	ICNSS_UEVENT_FW_DOWN,
 };
diff --git a/include/sound/wcd-dsp-mgr.h b/include/sound/wcd-dsp-mgr.h
index 7ba1817..52b52c4 100644
--- a/include/sound/wcd-dsp-mgr.h
+++ b/include/sound/wcd-dsp-mgr.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, 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
@@ -80,6 +80,7 @@
 
 	/* Software generated signal indicating debug dumps to be collected */
 	WDSP_DEBUG_DUMP,
+	WDSP_DEBUG_DUMP_INTERNAL,
 };
 
 /*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9fbdc11..3092188 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3782,6 +3782,9 @@
  *	@NL80211_BSS_PARENT_BSSID. (u64).
  * @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
  *	is set.
+ * @NL80211_BSS_CHAIN_SIGNAL: per-chain signal strength of last BSS update.
+ *	Contains a nested array of signal strength attributes (u8, dBm),
+ *	using the nesting index as the antenna number.
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -3805,6 +3808,7 @@
 	NL80211_BSS_PAD,
 	NL80211_BSS_PARENT_TSF,
 	NL80211_BSS_PARENT_BSSID,
+	NL80211_BSS_CHAIN_SIGNAL,
 
 	/* keep last */
 	__NL80211_BSS_AFTER_LAST,
@@ -4835,6 +4839,27 @@
  *	RSSI threshold values to monitor rather than exactly one threshold.
  * @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key
  *	authentication with %NL80211_CMD_CONNECT.
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK: Device wants to do 4-way
+ *	handshake with PSK in station mode (PSK is passed as part of the connect
+ *	and associate commands), doing it in the host might not be supported.
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X: Device wants to do doing 4-way
+ *	handshake with 802.1X in station mode (will pass EAP frames to the host
+ *	and accept the set_pmk/del_pmk commands), doing it in the host might not
+ *	be supported.
+ * @NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME: Driver is capable of overriding
+ *	the max channel attribute in the FILS request params IE with the
+ *	actual dwell time.
+ * @NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP: Driver accepts broadcast probe
+ *	response
+ * @NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE: Driver supports sending
+ *	the first probe request in each channel at rate of at least 5.5Mbps.
+ * @NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: Driver supports
+ *	probe request tx deferral and suppression
+ * @NL80211_EXT_FEATURE_MFP_OPTIONAL: Driver supports the %NL80211_MFP_OPTIONAL
+ *	value in %NL80211_ATTR_USE_MFP.
+ * @NL80211_EXT_FEATURE_LOW_SPAN_SCAN: Driver supports low span scan.
+ * @NL80211_EXT_FEATURE_LOW_POWER_SCAN: Driver supports low power scan.
+ * @NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN: Driver supports high accuracy scan.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4855,6 +4880,16 @@
 	NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
 	NL80211_EXT_FEATURE_CQM_RSSI_LIST,
 	NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
+	NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,
+	NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X,
+	NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME,
+	NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP,
+	NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE,
+	NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
+	NL80211_EXT_FEATURE_MFP_OPTIONAL,
+	NL80211_EXT_FEATURE_LOW_SPAN_SCAN,
+	NL80211_EXT_FEATURE_LOW_POWER_SCAN,
+	NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
@@ -4915,6 +4950,10 @@
  * of NL80211_CMD_TRIGGER_SCAN and NL80211_CMD_START_SCHED_SCAN
  * requests.
  *
+ * NL80211_SCAN_FLAG_LOW_SPAN, NL80211_SCAN_FLAG_LOW_POWER, and
+ * NL80211_SCAN_FLAG_HIGH_ACCURACY flags are exclusive of each other, i.e., only
+ * one of them can be used in the request.
+ *
  * @NL80211_SCAN_FLAG_LOW_PRIORITY: scan request has low priority
  * @NL80211_SCAN_FLAG_FLUSH: flush cache before scanning
  * @NL80211_SCAN_FLAG_AP: force a scan even if the interface is configured
@@ -4931,12 +4970,29 @@
  *	locally administered 1, multicast 0) is assumed.
  *	This flag must not be requested when the feature isn't supported, check
  *	the nl80211 feature flags for the device.
+ *	SSID and/or RSSI.
+ * @NL80211_SCAN_FLAG_LOW_SPAN: Span corresponds to the total time taken to
+ *	accomplish the scan. Thus, this flag intends the driver to perform the
+ *	scan request with lesser span/duration. It is specific to the driver
+ *	implementations on how this is accomplished. Scan accuracy may get
+ *	impacted with this flag.
+ * @NL80211_SCAN_FLAG_LOW_POWER: This flag intends the scan attempts to consume
+ *	optimal possible power. Drivers can resort to their specific means to
+ *	optimize the power. Scan accuracy may get impacted with this flag.
+ * @NL80211_SCAN_FLAG_HIGH_ACCURACY: Accuracy here intends to the extent of scan
+ *	results obtained. Thus HIGH_ACCURACY scan flag aims to get maximum
+ *	possible scan results. This flag hints the driver to use the best
+ *	possible scan configuration to improve the accuracy in scanning.
+ *	Latency and power use may get impacted with this flag.
  */
 enum nl80211_scan_flags {
 	NL80211_SCAN_FLAG_LOW_PRIORITY			= 1<<0,
 	NL80211_SCAN_FLAG_FLUSH				= 1<<1,
 	NL80211_SCAN_FLAG_AP				= 1<<2,
 	NL80211_SCAN_FLAG_RANDOM_ADDR			= 1<<3,
+	NL80211_SCAN_FLAG_LOW_SPAN			= 1<<8,
+	NL80211_SCAN_FLAG_LOW_POWER			= 1<<9,
+	NL80211_SCAN_FLAG_HIGH_ACCURACY			= 1<<10,
 };
 
 /**
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 59fcdbe..7b02ae6 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1051,8 +1051,13 @@
  */
 static struct rq *__migrate_task(struct rq *rq, struct task_struct *p, int dest_cpu)
 {
-	if (unlikely(!cpu_active(dest_cpu)))
-		return rq;
+	if (p->flags & PF_KTHREAD) {
+		if (unlikely(!cpu_online(dest_cpu)))
+			return rq;
+	} else {
+		if (unlikely(!cpu_active(dest_cpu)))
+			return rq;
+	}
 
 	/* Affinity changed (again). */
 	if (!cpumask_test_cpu(dest_cpu, tsk_cpus_allowed(p)))
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 645b472..73f11c4 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -2178,9 +2178,8 @@
  * the rt_loop_next will cause the iterator to perform another scan.
  *
  */
-static int rto_next_cpu(struct rq *rq)
+static int rto_next_cpu(struct root_domain *rd)
 {
-	struct root_domain *rd = rq->rd;
 	int next;
 	int cpu;
 
@@ -2256,7 +2255,7 @@
 	 * Otherwise it is finishing up and an ipi needs to be sent.
 	 */
 	if (rq->rd->rto_cpu < 0)
-		cpu = rto_next_cpu(rq);
+		cpu = rto_next_cpu(rq->rd);
 
 	raw_spin_unlock(&rq->rd->rto_lock);
 
@@ -2269,6 +2268,8 @@
 /* Called from hardirq context */
 void rto_push_irq_work_func(struct irq_work *work)
 {
+	struct root_domain *rd =
+		container_of(work, struct root_domain, rto_push_work);
 	struct rq *rq;
 	int cpu;
 
@@ -2284,18 +2285,18 @@
 		raw_spin_unlock(&rq->lock);
 	}
 
-	raw_spin_lock(&rq->rd->rto_lock);
+	raw_spin_lock(&rd->rto_lock);
 
 	/* Pass the IPI to the next rt overloaded queue */
-	cpu = rto_next_cpu(rq);
+	cpu = rto_next_cpu(rd);
 
-	raw_spin_unlock(&rq->rd->rto_lock);
+	raw_spin_unlock(&rd->rto_lock);
 
 	if (cpu < 0)
 		return;
 
 	/* Try the next RT overloaded CPU */
-	irq_work_queue_on(&rq->rd->rto_push_work, cpu);
+	irq_work_queue_on(&rd->rto_push_work, cpu);
 }
 #endif /* HAVE_RT_PUSH_IPI */
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d8387b1..8f9bd38 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6701,8 +6701,17 @@
 	if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
 		request->flags = nla_get_u32(
 			info->attrs[NL80211_ATTR_SCAN_FLAGS]);
-		if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
-		    !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) {
+		if (((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) &&
+		     !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) ||
+		    ((request->flags & NL80211_SCAN_FLAG_LOW_SPAN) &&
+		     !wiphy_ext_feature_isset(wiphy,
+				      NL80211_EXT_FEATURE_LOW_SPAN_SCAN)) ||
+		    ((request->flags & NL80211_SCAN_FLAG_LOW_POWER) &&
+		     !wiphy_ext_feature_isset(wiphy,
+				      NL80211_EXT_FEATURE_LOW_POWER_SCAN)) ||
+		    ((request->flags & NL80211_SCAN_FLAG_HIGH_ACCURACY) &&
+		     !wiphy_ext_feature_isset(wiphy,
+		      NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN))) {
 			err = -EOPNOTSUPP;
 			goto out_free;
 		}
@@ -7585,6 +7594,11 @@
 			      intbss->ts_boottime, NL80211_BSS_PAD))
 		goto nla_put_failure;
 
+	if (!nl80211_put_signal(msg, intbss->pub.chains,
+				intbss->pub.chain_signal,
+				NL80211_BSS_CHAIN_SIGNAL))
+		goto nla_put_failure;
+
 	switch (rdev->wiphy.signal_type) {
 	case CFG80211_SIGNAL_TYPE_MBM:
 		if (nla_put_u32(msg, NL80211_BSS_SIGNAL_MBM, res->signal))
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 35ad69f..ad8611b 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -904,6 +904,9 @@
 		found->ts = tmp->ts;
 		found->ts_boottime = tmp->ts_boottime;
 		found->parent_tsf = tmp->parent_tsf;
+		found->pub.chains = tmp->pub.chains;
+		memcpy(found->pub.chain_signal, tmp->pub.chain_signal,
+		       IEEE80211_MAX_CHAINS);
 		ether_addr_copy(found->parent_bssid, tmp->parent_bssid);
 	} else {
 		struct cfg80211_internal_bss *new;
@@ -1156,6 +1159,8 @@
 	tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
 	tmp.ts_boottime = data->boottime_ns;
 	tmp.parent_tsf = data->parent_tsf;
+	tmp.pub.chains = data->chains;
+	memcpy(tmp.pub.chain_signal, data->chain_signal, IEEE80211_MAX_CHAINS);
 	ether_addr_copy(tmp.parent_bssid, data->parent_bssid);
 
 	signal_valid = abs(data->chan->center_freq - channel->center_freq) <=