Merge "xhci-plat: Use correct dev to get usb-phy handle"
diff --git a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
index 105dcac..30961be 100644
--- a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
@@ -7,7 +7,7 @@
 Required Properties:
 - compatible:	The bus devices need to be compatible with
 		"qcom,mdm2-modem", "qcom,ext-mdm9x25", "qcom,ext-mdm9x35", "qcom, ext-mdm9x45",
-		"qcom,ext-mdm9x55".
+		"qcom,ext-mdm9x55", "qcom,ext-sdxpoorwills".
 
 Required named gpio properties:
 - qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor
diff --git a/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt b/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt
new file mode 100644
index 0000000..28f6e7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/msm-machine-name.txt
@@ -0,0 +1,63 @@
+Msm Machine Name
+
+Machine name is used to:
+	1. show up in the beginning of kernel message.
+	Example:
+		[    0.000000] Machine: Qualcomm Technologies, Inc. MSM8953 PMI8950 MTP
+	2. show up as arch description when do dump stack.
+	Example:
+		[    1.222319] WARNING: CPU: 2 PID: 1 at kernel/lib/debugobjects.c:263 debug_print_object+0xa8/0xb0
+		[    1.222334] Modules linked in:
+		[    1.222362] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.9.65+ #71
+		[    1.222376] Hardware name: Qualcomm Technologies, Inc. MSM8953 PMI8950 MTP (DT)
+		[    1.222392] task: ffffffc0ed1b0080 task.stack: ffffffc0ed1b8000
+		[    1.222408] PC is at debug_print_object+0xa8/0xb0
+		[    1.222424] LR is at debug_print_object+0xa8/0xb0
+
+Msm machine name is a string concatenated from:
+	1. constant string contain msm information: "Qualcomm Technologies, Inc.".
+	2. string of device tree property "qcom,msm-name".
+	3. string of device tree property "qcom,pmic-name".
+	4. string of device tree property "model".
+
+The reason for using msm machine Name is single board overlay device tree
+may applied to multiple soc device trees. The "model" property in soc device
+tree is overwritten with board overlay device tree. So the final string in
+"model" property can only contain Board information. And "qcom,msm-name"
+and "qcom,pmic-name" property is introduced.
+
+Optional properties:
+- qcom,msm-name: The name string of MSM SoC chip
+- qcom,pmic-name: The name string of MSM Pmic chip
+
+Required properties:
+- model: in soc device tree
+	Contain the soc and pmic information.
+	Will be overwritten by model string in board overlay device tree.
+	It will be used in bootloader for debug purpose.
+- model: in board overlay device tree
+	Contain the board information. It is the final model string that
+	kernel can see.
+
+Note:
+When device tree property qcom,msm-name and qcom,pmic-name exist, it will
+use concatenated msm machine name string for final machine name.
+When device tree property qcom,msm-name and qcom,pmic-name doesn't exist,
+it will use model property string for final machine name.
+
+Example:
+* In soc device tree:
+	/ {
+		model = "Qualcomm Technologies, Inc. APQ 8953 + PMI8950 SOC";
+		compatible = "qcom,apq8053";
+		qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
+		qcom,pmic-name = "PMI8950";
+		qcom,msm-id = <293 0x0>;
+		qcom,msm-name = "APQ8053";
+	};
+* In board overlay device tree:
+	/ {
+		model = "MTP";
+		compatible = "qcom,mtp";
+	};
+
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index b3d4d44..9bc8168 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -110,6 +110,12 @@
 - SDM450
   compatible = "qcom,sdm450"
 
+- SDM632
+  compatible = "qcom,sdm632"
+
+- SDA632
+  compatible = "qcom,sda632"
+
 - MSM8937
   compatible = "qcom,msm8937"
 
@@ -321,6 +327,7 @@
 compatible = "qcom,sdm450-mtp"
 compatible = "qcom,sdm450-cdp"
 compatible = "qcom,sdm450-qrd"
+compatible = "qcom,sdm632-rumi"
 compatible = "qcom,mdm9640-cdp"
 compatible = "qcom,mdm9640-mtp"
 compatible = "qcom,mdm9640-rumi"
diff --git a/Documentation/devicetree/bindings/cnss/cnss-wlan.txt b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt
new file mode 100644
index 0000000..9dff08d
--- /dev/null
+++ b/Documentation/devicetree/bindings/cnss/cnss-wlan.txt
@@ -0,0 +1,75 @@
+* Qualcomm Technologies, Inc. ConNectivity SubSystem Platform Driver
+
+This platform driver adds support for the CNSS subsystem used for PCIe
+based Wi-Fi devices. It also adds support to integrate PCIe WLAN module
+to subsystem restart framework. Apart from that, it also manages the
+3.3V voltage regulator, WLAN Enable GPIO signal and PCIe link dynamically
+with support for suspend and resume by retaining the PCI config space
+states when PCIe link is shutdown. The main purpose of this device tree
+entry below is to invoke the CNSS platform driver and provide handle to
+the WLAN enable GPIO, 3.3V fixed voltage regulator resources. It also
+provides the reserved RAM dump memory location and size.
+
+Required properties:
+  - compatible: "qcom,cnss" for QCA6174 device
+                "qcom,cnss-qca6290" for QCA6290 device
+  - wlan-en-gpio: WLAN_EN GPIO signal specified by the chip specifications
+  - vdd-wlan-supply: phandle to the regulator device tree node
+  - pinctrl-names: Names corresponding to the numbered pinctrl states
+  - pinctrl-<n>: Pinctrl states as described in
+                 bindings/pinctrl/pinctrl-bindings.txt
+  - qcom,wlan-rc-num: PCIe root complex number which WLAN chip is attached to
+
+Optional properties:
+  - qcom,notify-modem-status: Boolean property to decide whether modem
+                              notification should be enabled or not in this
+                              platform
+  - wlan-soc-swreg-supply: phandle to the external 1.15V regulator for QCA6174
+  - wlan-ant-switch-supply: phandle to the 2.7V regulator for the antenna
+                            switch of QCA6174
+  - qcom,wlan-uart-access: Boolean property to decide whether QCA6174
+                           has exclusive access to UART.
+  - vdd-wlan-io-supply: phandle to the 1.8V IO regulator for QCA6174
+  - vdd-wlan-xtal-supply: phandle to the 1.8V XTAL regulator for QCA6174
+  - vdd-wlan-xtal-aon-supply: phandle to the LDO-4 regulator. This is needed
+                              on platforms where XTAL regulator depends on
+                              always on regulator in VDDmin.
+  - vdd-wlan-core-supply: phandle to the 1.3V CORE regulator for QCA6174
+  - vdd-wlan-sp2t-supply: phandle to the 2.7V SP2T regulator for QCA6174
+  - qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
+                                 format to be used for allocations associated
+                                 between WLAN/PCIe and SMMU
+  - qcom,wlan-ramdump-dynamic: To enable CNSS RAMDUMP collection
+                               by providing the size of CNSS DUMP
+  - reg: Memory regions defined as starting address and size
+  - reg-names: Names of the memory regions defined in reg entry
+  - wlan-bootstrap-gpio: WLAN_BOOTSTRAP GPIO signal specified by QCA6174
+                         which should be drived depending on platforms
+  - qcom,is-dual-wifi-enabled: Boolean property to control wlan enable(wlan-en)
+                               gpio on dual-wifi platforms.
+  - vdd-wlan-en-supply: WLAN_EN fixed regulator specified by QCA6174
+                        specifications.
+  - qcom,wlan-en-vreg-support: Boolean property to decide the whether the
+                               WLAN_EN pin is a gpio or fixed regulator.
+  - qcom,mhi: phandle to indicate the device which needs MHI support.
+  - qcom,cap-tsf-gpio: WLAN_TSF_CAPTURED GPIO signal specified by the chip
+                       specifications, should be drived depending on products
+
+Example:
+
+    qcom,cnss@0d400000 {
+        compatible = "qcom,cnss";
+        reg = <0x0d400000 0x200000>;
+        reg-names = "ramdump";
+        qcom,wlan-ramdump-dynamic = <0x200000>;
+        wlan-en-gpio = <&msmgpio 82 0>;
+        vdd-wlan-supply = <&wlan_vreg>;
+        qcom,notify-modem-status;
+        wlan-soc-swreg-supply = <&pma8084_l27>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&cnss_default>;
+        qcom,wlan-rc-num = <0>;
+        qcom,wlan-smmu-iova-address = <0 0x10000000>;
+        qcom,mhi = <&mhi_wlan>;
+        qcom,cap-tsf-gpio = <&tlmm 126 1>;
+    };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
index 42e97f7..c7268ef 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
@@ -80,6 +80,13 @@
 			  or disabled.
 - qcom,auto-calibration-enable : A boolean property which enables auto-calibration
 				 of the WLED sink configuration.
+- qcom,wled-brightness-map	: Array of brightness map codes of size 256.
+				  These codes will be mapped to the brightness
+				  level requested in the scale of 0-4095. Code
+				  entry is of 16 bit size.
+- qcom,wled-stepper-en	: A boolean property to specify if stepper algorithm
+			  needs to be enabled. This needs the brightness map
+			  table to be specified.
 
 Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
 - qcom,loop-comp-res-kohm	: control to select the compensation resistor in kohm. default is 320.
@@ -123,4 +130,5 @@
 		qcom,en-phase-stag;
 		qcom,led-strings-list = [00 01 02 03];
 		qcom,en-ext-pfet-sc-pro;
+		qcom,wled-brightness-map = /bits/ 16  <0 . . 4095>;
 	};
diff --git a/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt b/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt
new file mode 100644
index 0000000..5bb85a4
--- /dev/null
+++ b/Documentation/devicetree/bindings/platform/msm/gpio-usbdetect.txt
@@ -0,0 +1,25 @@
+GPIO USB VBUS Detection
+
+Discrete USB VBUS detection circuitry can be connected to the AP or PMICs.
+Such circuits can be used to detect the when a USB cable is connected to
+an upstream port such as a standard host or a wall charger by detecting
+the presence of VBUS voltage. The GPIO can be configured to trigger an
+interrupt, and allow the software driver to in turn notify the USB
+subsytem using the power_supply framework.
+
+Required Properties:
+ - compatible: must be "qcom,gpio-usbdetect"
+ - qcom,vbus-det-gpio: GPIO from which VBUS detection can be read from.
+ - interrupts: an interrupt triggered by the output of the detection circuit
+ - interrupt-names: must be "vbus_det_irq"
+
+Optional Properties:
+ - vin-supply: phandle to a regulator that powers this circuit, if needed
+
+Example:
+
+	usb_detect {
+		compatible = "qcom,gpio-usbdetect";
+		qcom,vbus-det-gpio = <&pm8084 2 0>;
+                vin-supply = <&vbus_det_reg>;
+	};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi
new file mode 100644
index 0000000..0b94534
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi
@@ -0,0 +1,183 @@
+/*
+ * 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 <dt-bindings/clock/qcom,gcc-sdxpoorwills.h>
+
+&soc {
+	pcie0: qcom,pcie@1c00000 {
+		compatible = "qcom,pci-msm";
+		cell-index = <0>;
+
+		reg = <0x01c00000 0x2000>,
+		      <0x01c02000 0x1000>,
+		      <0x40000000 0xf1d>,
+		      <0x40000f20 0xa8>,
+		      <0x40001000 0x1000>,
+		      <0x40100000 0x100000>,
+		      <0x40200000 0x100000>,
+		      <0x40300000 0x1d00000>,
+		      <0x01fce008 0x4>;
+
+		reg-names = "parf", "phy", "dm_core", "elbi", "iatu",
+				"conf", "io", "bars", "tcsr";
+
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>,
+			<0x02000000 0x0 0x40300000 0x40300000 0x0 0x1d00000>;
+		interrupt-parent = <&pcie0>;
+		interrupts = <0 1 2 3 4 5>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0xffffffff>;
+		interrupt-map = <0 0 0 0 &intc 0 119 0
+				0 0 0 1 &intc 0 141 0
+				0 0 0 2 &intc 0 142 0
+				0 0 0 3 &intc 0 143 0
+				0 0 0 4 &intc 0 144 0
+				0 0 0 5 &intc 0 140 0>;
+
+		interrupt-names = "int_msi", "int_a", "int_b", "int_c",
+				"int_d", "int_global_int";
+
+		qcom,phy-sequence = <0x840 0x03 0x0
+				0x094 0x08 0x0
+				0x154 0x33 0x0
+				0x058 0x0f 0x0
+				0x0a4 0x42 0x0
+				0x1bc 0x11 0x0
+				0x0bc 0x82 0x0
+				0x0d4 0x03 0x0
+				0x0d0 0x55 0x0
+				0x0cc 0x55 0x0
+				0x0b0 0x1a 0x0
+				0x0ac 0x0a 0x0
+				0x158 0x01 0x0
+				0x074 0x06 0x0
+				0x07c 0x16 0x0
+				0x084 0x36 0x0
+				0x1b0 0x1e 0x0
+				0x1ac 0xb9 0x0
+				0x050 0x07 0x0
+				0x29c 0x12 0x0
+				0x284 0x05 0x0
+				0x234 0xd9 0x0
+				0x238 0xcc 0x0
+				0x51c 0x03 0x0
+				0x518 0x1c 0x0
+				0x524 0x14 0x0
+				0x4ec 0x0e 0x0
+				0x4f0 0x4a 0x0
+				0x4f4 0x0f 0x0
+				0x5b4 0x04 0x0
+				0x434 0x7f 0x0
+				0x444 0x70 0x0
+				0x510 0x17 0x0
+				0x4d8 0x01 0x0
+				0x598 0xe0 0x0
+				0x59c 0xc8 0x0
+				0x5a0 0xc8 0x0
+				0x5a4 0x09 0x0
+				0x5a8 0xb1 0x0
+				0x584 0x24 0x0
+				0x588 0xe4 0x0
+				0x58c 0xec 0x0
+				0x590 0x39 0x0
+				0x594 0x36 0x0
+				0x570 0xef 0x0
+				0x574 0xef 0x0
+				0x578 0x2f 0x0
+				0x57c 0xd3 0x0
+				0x580 0x40 0x0
+				0x4fc 0x00 0x0
+				0x4f8 0xc0 0x0
+				0x9a4 0x01 0x0
+				0xc90 0x00 0x0
+				0xc40 0x01 0x0
+				0xc48 0x01 0x0
+				0xca0 0x11 0x0
+				0x048 0x90 0x0
+				0xc1c 0xc1 0x0
+				0x988 0x88 0x0
+				0x998 0x08 0x0
+				0x8dc 0x0d 0x0
+				0x800 0x00 0x0
+				0x844 0x03 0x0>;
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&pcie0_clkreq_default
+			&pcie0_perst_default
+			&pcie0_wake_default>;
+
+		perst-gpio = <&tlmm 57 0>;
+		wake-gpio = <&tlmm 53 0>;
+
+		gdsc-vdd-supply = <&gdsc_pcie>;
+		vreg-1.8-supply = <&pmxpoorwills_l1>;
+		vreg-0.9-supply = <&pmxpoorwills_l4>;
+		vreg-cx-supply = <&pmxpoorwills_s5_level>;
+
+		qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>;
+		qcom,vreg-0.9-voltage-level = <872000 872000 24000>;
+		qcom,vreg-cx-voltage-level = <RPMH_REGULATOR_LEVEL_MAX
+						RPMH_REGULATOR_LEVEL_SVS 0>;
+
+		qcom,l0s-supported;
+		qcom,l1-supported;
+		qcom,l1ss-supported;
+		qcom,aux-clk-sync;
+
+		qcom,ep-latency = <10>;
+
+		qcom,slv-addr-space-size = <0x40000000>;
+
+		qcom,cpl-timeout = <0x2>;
+
+		qcom,boot-option = <0x1>;
+
+		linux,pci-domain = <0>;
+
+		qcom,use-19p2mhz-aux-clk;
+
+		qcom,msm-bus,name = "pcie0";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<45 512 0 0>,
+				<45 512 500 800>;
+
+		clocks = <&clock_gcc GCC_PCIE_PIPE_CLK>,
+			<&clock_rpmh RPMH_CXO_CLK>,
+			<&clock_gcc GCC_PCIE_AUX_CLK>,
+			<&clock_gcc GCC_PCIE_CFG_AHB_CLK>,
+			<&clock_gcc GCC_PCIE_MSTR_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_SLV_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_0_CLKREF_CLK>,
+			<&clock_gcc GCC_PCIE_SLV_Q2A_AXI_CLK>,
+			<&clock_gcc GCC_PCIE_SLEEP_CLK>,
+			<&clock_gcc GCC_PCIE_PHY_REFGEN_CLK>;
+
+		clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src",
+				"pcie_0_aux_clk", "pcie_0_cfg_ahb_clk",
+				"pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk",
+				"pcie_0_ldo", "pcie_0_slv_q2a_axi_clk",
+				"pcie_0_sleep_clk", "pcie_phy_refgen_clk";
+
+		max-clock-frequency-hz = <0>, <0>, <0>, <0>, <0>, <0>,
+					<0>, <0>, <0>, <0>, <100000000>;
+
+		resets = <&clock_gcc GCC_PCIE_BCR>,
+			<&clock_gcc GCC_PCIE_PHY_BCR>;
+
+		reset-names = "pcie_0_core_reset",
+				"pcie_0_phy_reset";
+	};
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index fa9c4f8..1e212b7 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.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
@@ -382,6 +382,44 @@
 			};
 		};
 
+		pcie0 {
+			pcie0_clkreq_default: pcie0_clkreq_default {
+				mux {
+					pins = "gpio56";
+					function = "pcie_clkreq";
+				};
+				config {
+					pins = "gpio56";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			pcie0_perst_default: pcie0_perst_default {
+				mux {
+					pins = "gpio57";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio57";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			pcie0_wake_default: pcie0_wake_default {
+				mux {
+					pins = "gpio53";
+					function = "gpio";
+				};
+				config {
+					pins = "gpio53";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+		};
+
 		/* HS UART CONFIGURATION */
 
 		blsp1_uart1a: blsp1_uart1a {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 322e2cc..0fc20dd 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.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
@@ -67,7 +67,7 @@
 		#address-cells = <1>;
 
 		CPU0: cpu@0 {
-			device-type = "cpu";
+			device_type = "cpu";
 			compatible = "arm,cortex-a7";
 			reg = <0x0>;
 			#cooling-cells = <2>;
@@ -76,6 +76,7 @@
 
 	aliases {
 		qpic_nand1 = &qnand_1;
+		pci-domain0 = &pcie0;
 		sdhc1 = &sdhc_1; /* SDC1 eMMC/SD/SDIO slot */
 	};
 
@@ -771,6 +772,14 @@
 		mbox-desc-offset = <0x0>;
 		#mbox-cells = <1>;
 	};
+
+	usb_detect: qcom,gpio-usbdetect {
+		compatible = "qcom,gpio-usbdetect";
+		interrupt-parent = <&spmi_bus>;
+		interrupts = <0x0 0x0d 0x0 IRQ_TYPE_NONE>;
+		interrupt-names = "vbus_det_irq";
+		status = "disabled";
+	};
 };
 
 #include "pmxpoorwills.dtsi"
@@ -778,6 +787,7 @@
 #include "sdxpoorwills-regulator.dtsi"
 #include "sdxpoorwills-smp2p.dtsi"
 #include "sdxpoorwills-usb.dtsi"
+#include "sdxpoorwills-pcie.dtsi"
 #include "sdxpoorwills-bus.dtsi"
 #include "sdxpoorwills-thermal.dtsi"
 #include "sdxpoorwills-audio.dtsi"
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 9d60c9e..d375cc3 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -304,6 +304,9 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
@@ -325,6 +328,7 @@
 CONFIG_REGULATOR_MEM_ACC=y
 CONFIG_REGULATOR_MSM_GFX_LDO=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 36c8651..3b6f240 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -314,6 +314,9 @@
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_QPNP_PIN=y
 CONFIG_GPIO_QPNP_PIN_DEBUG=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_QPNP_FG=y
 CONFIG_SMB135X_CHARGER=y
@@ -335,6 +338,7 @@
 CONFIG_REGULATOR_MEM_ACC=y
 CONFIG_REGULATOR_MSM_GFX_LDO=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 834dfb8..7a85ac6 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -309,6 +309,7 @@
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_REVID=y
+CONFIG_GPIO_USB_DETECT=y
 CONFIG_USB_BAM=y
 CONFIG_MSM_CLK_RPMH=y
 CONFIG_MDM_GCC_SDXPOORWILLS=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 760d4d4..b4b4ba9 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -308,6 +308,7 @@
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_QPNP_REVID=y
+CONFIG_GPIO_USB_DETECT=y
 CONFIG_MSM_CLK_RPMH=y
 CONFIG_MDM_GCC_SDXPOORWILLS=y
 CONFIG_MDM_CLOCK_CPU_SDXPOORWILLS=y
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 062c484..906623e 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -22,6 +22,7 @@
 
 extern unsigned int user_debug;
 extern char* (*arch_read_hardware_id)(void);
+const char * __init arch_read_machine_name(void);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 877f461..09dd8ff 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -1174,7 +1174,7 @@
 
 	return 0;
 }
-subsys_initcall(topology_init);
+postcore_initcall(topology_init);
 
 #ifdef CONFIG_HAVE_PROC_CPU
 static int __init proc_cpu_init(void)
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index b2adfb4..d4b94da 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -41,7 +41,10 @@
 		sda845-v2.1-qrd-overlay.dtbo \
 		sda845-v2.1-4k-panel-cdp-overlay.dtbo \
 		sda845-v2.1-4k-panel-mtp-overlay.dtbo \
-		sda845-v2.1-4k-panel-qrd-overlay.dtbo
+		sda845-v2.1-4k-panel-qrd-overlay.dtbo \
+		sda845-v2.1-cdp-sdxpoorwills-overlay.dtbo \
+		sda845-v2.1-mtp-sdxpoorwills-overlay.dtbo \
+		sda845-v2-mtp-sdxpoorwills-overlay.dtbo
 
 sdm845-cdp-overlay.dtbo-base := sdm845.dtb
 sdm845-mtp-overlay.dtbo-base := sdm845.dtb
@@ -81,6 +84,9 @@
 sda845-v2.1-4k-panel-cdp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-mtp-overlay.dtbo-base := sda845-v2.1.dtb
 sda845-v2.1-4k-panel-qrd-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2.1-cdp-sdxpoorwills-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2.1-mtp-sdxpoorwills-overlay.dtbo-base := sda845-v2.1.dtb
+sda845-v2-mtp-sdxpoorwills-overlay.dtbo-base := sda845-v2.dtb
 else
 dtb-$(CONFIG_ARCH_SDM845) += sdm845-sim.dtb \
 	sdm845-rumi.dtb \
@@ -124,6 +130,8 @@
 		sda670-mtp-overlay.dtbo \
 		sda670-pm660a-cdp-overlay.dtbo \
 		sda670-pm660a-mtp-overlay.dtbo \
+		sdm670-tasha-codec-cdp-overlay.dtbo \
+		sdm670-pm660a-tasha-codec-cdp-overlay.dtbo \
 		qcs605-cdp-overlay.dtbo \
 		qcs605-mtp-overlay.dtbo \
 		qcs605-360camera-overlay.dtbo \
@@ -149,6 +157,8 @@
 sdm670-usbc-external-codec-mtp-overlay.dtbo-base := sdm670.dtb
 sdm670-usbc-external-codec-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
 sdm670-usbc-external-codec-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-tasha-codec-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-pm660a-tasha-codec-cdp-overlay.dtbo-base := sdm670.dtb
 sda670-cdp-overlay.dtbo-base := sda670.dtb
 sda670-mtp-overlay.dtbo-base := sda670.dtb
 sda670-pm660a-cdp-overlay.dtbo-base := sda670.dtb
@@ -181,6 +191,8 @@
 	sdm670-usbc-pm660a-mtp.dtb \
 	sda670-mtp.dtb \
 	sda670-cdp.dtb \
+	sdm670-tasha-codec-cdp.dtb \
+	sdm670-pm660a-tasha-codec-cdp.dtb \
 	sda670-pm660a-mtp.dtb \
 	sda670-pm660a-cdp.dtb \
 	qcs605-360camera.dtb \
@@ -191,6 +203,52 @@
 endif
 
 ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+dtbo-$(CONFIG_ARCH_MSM8953) += msm8953-mtp-overlay.dtbo \
+	msm8953-cdp-overlay.dtbo \
+	msm8953-rcm-overlay.dtbo \
+	msm8953-ipc-overlay.dtbo \
+	msm8953-qrd-overlay.dtbo \
+	msm8953-iot-mtp-overlay.dtbo \
+	msm8953-ext-codec-mtp-overlay.dtbo \
+	msm8953-ext-codec-rcm-overlay.dtbo \
+	msm8953-cdp-1200p-overlay.dtbo
+
+dtbo-$(CONFIG_ARCH_SDM450) += msm8953-mtp-overlay.dtbo \
+	msm8953-cdp-overlay.dtbo \
+	msm8953-rcm-overlay.dtbo \
+	msm8953-qrd-overlay.dtbo \
+	msm8953-iot-mtp-overlay.dtbo
+
+msm8953-mtp-overlay.dtbo-base := sdm450.dtb \
+	msm8953.dtb \
+	apq8053.dtb \
+	msm8953-pmi8940.dtb \
+	msm8953-pmi8937.dtb \
+	sdm450-pmi8940.dtb \
+	sdm450-pmi8937.dtb
+msm8953-cdp-overlay.dtbo-base := sdm450.dtb \
+	msm8953.dtb \
+	apq8053.dtb \
+	msm8953-pmi8940.dtb \
+	msm8953-pmi8937.dtb
+msm8953-rcm-overlay.dtbo-base := sdm450.dtb \
+	msm8953.dtb \
+	apq8053.dtb
+msm8953-ipc-overlay.dtbo-base := msm8953.dtb \
+	apq8053.dtb
+msm8953-qrd-overlay.dtbo-base := sdm450.dtb \
+	msm8953.dtb
+msm8953-iot-mtp-overlay.dtbo-base := sdm450.dtb \
+	msm8953.dtb \
+	apq8053.dtb
+msm8953-ext-codec-mtp-overlay.dtbo-base := msm8953.dtb \
+	apq8053.dtb \
+	msm8953-pmi8940.dtb \
+	msm8953-pmi8937.dtb
+msm8953-ext-codec-rcm-overlay.dtbo-base := msm8953.dtb \
+	apq8053.dtb
+msm8953-cdp-1200p-overlay.dtbo-base := msm8953.dtb
+
 else
 dtb-$(CONFIG_ARCH_MSM8953) += msm8953-cdp.dtb \
 	msm8953-mtp.dtb \
@@ -225,6 +283,9 @@
 	sdm450-qrd-sku4.dtb \
 	sdm450-pmi632-cdp-s2.dtb \
 	sdm450-pmi632-mtp-s3.dtb
+
+dtb-$(CONFIG_ARCH_SDM632) += sdm632-rumi.dtb
+
 endif
 
 always		:= $(dtb-y)
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dts b/arch/arm64/boot/dts/qcom/apq8053.dts
new file mode 100644
index 0000000..bf9e2f2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053.dts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. APQ8053 + PMI8950 SOC";
+	compatible = "qcom,apq8053";
+	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
+	qcom,pmic-name = "PMI8950";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053.dtsi b/arch/arm64/boot/dts/qcom/apq8053.dtsi
index 15a1595..4600dc1 100644
--- a/arch/arm64/boot/dts/qcom/apq8053.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053.dtsi
@@ -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
@@ -12,9 +12,10 @@
  */
 #include "msm8953.dtsi"
 / {
-	model = "Qualcomm Technologies, Inc. APQ 8953";
+	model = "Qualcomm Technologies, Inc. APQ8053";
 	compatible = "qcom,apq8053";
 	qcom,msm-id = <304 0x0>;
+	qcom,msm-name = "APQ8053";
 };
 
 &secure_mem {
diff --git a/arch/arm64/boot/dts/qcom/external-soc.dtsi b/arch/arm64/boot/dts/qcom/external-soc.dtsi
new file mode 100644
index 0000000..e6609c0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/external-soc.dtsi
@@ -0,0 +1,37 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdm3: qcom,mdm3 {
+		compatible = "qcom,ext-sdxpoorwills";
+		cell-index = <0>;
+		#address-cells = <0>;
+		interrupt-parent = <&mdm3>;
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0xffffffff>;
+		interrupt-names =
+			"err_fatal_irq",
+			"status_irq",
+			"mdm2ap_vddmin_irq";
+		/* modem attributes */
+		qcom,ramdump-delays-ms = <2000>;
+		qcom,ramdump-timeout-ms = <120000>;
+		qcom,vddmin-modes = "normal";
+		qcom,vddmin-drive-strength = <8>;
+		qcom,sfr-query;
+		qcom,sysmon-id = <20>;
+		qcom,ssctl-instance-id = <0x10>;
+		qcom,support-shutdown;
+		qcom,pil-force-shutdown;
+		status = "disabled";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts
new file mode 100644
index 0000000..03ec7b5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp-1200p-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-cdp.dtsi"
+
+/ {
+	model = "CDP 1200P";
+	qcom,board-id = <1 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts
new file mode 100644
index 0000000..145a40c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-cdp-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-cdp.dtsi"
+
+/ {
+	model = "CDP";
+	qcom,board-id = <1 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
index d202d99..42d21f4 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
@@ -290,7 +290,7 @@
 };
 
 &soc {
-	cpuss_dump {
+	cpuss_dump: cpuss_dump {
 		compatible = "qcom,cpuss-dump";
 		qcom,l2_dump0 {
 			/* L2 cache dump for A53 cluster */
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts
new file mode 100644
index 0000000..08a343e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-mtp-overlay.dts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-mtp.dtsi"
+
+/ {
+	model = "Ext Codec MTP";
+	qcom,board-id= <8 1>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts
new file mode 100644
index 0000000..45fdf06
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-ext-codec-rcm-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-cdp.dtsi"
+
+/ {
+	model = "Ext Codec RCM";
+	qcom,board-id = <21 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
index 96e8591..fb7cfdd 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-gpu.dtsi
@@ -140,6 +140,9 @@
 		/* Context aware jump target power level */
 		qcom,ca-target-pwrlevel = <3>;
 
+		/* Enable gpu cooling device */
+		#cooling-cells = <2>;
+
 		/* GPU Mempools */
 		qcom,gpu-mempools {
 			#address-cells= <1>;
diff --git a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts
new file mode 100644
index 0000000..fec135d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-mtp.dtsi"
+
+/ {
+	model = "IOT MTP";
+	qcom,board-id = <8 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts
new file mode 100644
index 0000000..3f957da
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-ipc-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-ipc.dtsi"
+
+/ {
+	model = "IPC";
+	qcom,board-id = <12 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
new file mode 100644
index 0000000..49956df
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-mtp.dtsi"
+
+/ {
+	model = "MTP";
+	qcom,board-id = <8 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
index a45bb66..eec350d 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
@@ -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
@@ -48,6 +48,31 @@
 				};
 			};
 
+			uart1_console_active: uart1_console_active {
+				mux {
+					pins = "gpio20", "gpio21";
+					function = "blsp_uart6";
+				};
+
+				config {
+					pins = "gpio20", "gpio21";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			uart1_console_sleep: uart1_console_sleep {
+				mux {
+					pins = "gpio20", "gpio21";
+					function = "blsp_uart6";
+				};
+
+				config {
+					pins = "gpio20", "gpio21";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
 		};
 		cci {
 			cci0_active: cci0_active {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
new file mode 100644
index 0000000..a9f64a4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8937.dts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8937 SOC";
+	compatible = "qcom,msm8953";
+	qcom,pmic-id = <0x010016 0x020037 0x0 0x0>;
+	qcom,pmic-name = "PMI8937";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
new file mode 100644
index 0000000..e9c80a0d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8940.dts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8940 SOC";
+	compatible = "qcom,msm8953";
+	qcom,pmic-id = <0x010016 0x020040 0x0 0x0>;
+	qcom,pmic-name = "PMI8940";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts
new file mode 100644
index 0000000..7f5fc4e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-qrd-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-qrd-sku3.dtsi"
+
+/ {
+	model = "QRD SKU3";
+	qcom,board-id = <0xb 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts b/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts
new file mode 100644
index 0000000..dbb7f57
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-rcm-overlay.dts
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "msm8953-cdp.dtsi"
+
+/ {
+	model = "RCM";
+	qcom,board-id = <21 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
index 208ef41..d5a6f52 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-thermal.dtsi
@@ -265,6 +265,14 @@
 				type = "passive";
 			};
 		};
+		cooling-maps {
+			gpu_cdev0 {
+				trip = <&gpu_trip0>;
+				cooling-device =
+					<&msm_gpu THERMAL_NO_LIMIT
+						THERMAL_NO_LIMIT>;
+			};
+		};
 	};
 
 	deca-cpu-max-step {
@@ -589,6 +597,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&mdm_core_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&mdm_core_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -619,6 +631,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&qdsp_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&qdsp_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -649,6 +665,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&camera_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&camera_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -679,6 +699,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&cpu4_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&cpu4_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -709,6 +733,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&cpu5_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&cpu5_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -739,6 +767,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&cpu6_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&cpu6_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -769,6 +801,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&cpu7_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&cpu7_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -799,6 +835,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&apc1_l2_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&apc1_l2_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -829,6 +869,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&cpu0_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&cpu0_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -859,6 +903,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&cpu1_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&cpu1_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -889,6 +937,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&cpu2_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&cpu2_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -919,6 +971,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&cpu3_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&cpu3_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -949,6 +1005,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&apc0_l2_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&apc0_l2_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -979,6 +1039,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&gpu0_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&gpu0_trip>;
 				cooling-device = <&cx_cdev 0 0>;
@@ -1009,6 +1073,10 @@
 				cooling-device = <&CPU0 (THERMAL_MAX_LIMIT - 4)
 						(THERMAL_MAX_LIMIT - 4)>;
 			};
+			gpu_vdd_cdev {
+				trip = <&gpu1_trip>;
+				cooling-device = <&msm_gpu 2 2>;
+			};
 			cx_vdd_cdev {
 				trip = <&gpu1_trip>;
 				cooling-device = <&cx_cdev 0 0>;
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dts b/arch/arm64/boot/dts/qcom/msm8953.dts
new file mode 100644
index 0000000..ddf2218
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953.dts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "msm8953.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 SOC";
+	compatible = "qcom,msm8953";
+	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
+	qcom,pmic-name = "PMI8950";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 0d7932b..a142840 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -19,9 +19,10 @@
 #include <dt-bindings/clock/msm-clocks-8953.h>
 
 / {
-	model = "Qualcomm Technologies, Inc. MSM 8953";
+	model = "Qualcomm Technologies, Inc. MSM8953";
 	compatible = "qcom,msm8953";
 	qcom,msm-id = <293 0x0>;
+	qcom,msm-name = "MSM8953";
 	interrupt-parent = <&intc>;
 
 	chosen {
@@ -507,6 +508,16 @@
 		status = "disabled";
 	};
 
+	blsp1_serial1: serial@78b0000 {
+		compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+		reg = <0x78b0000 0x200>;
+		interrupts = <0 108 0>;
+		clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+			<&clock_gcc clk_gcc_blsp1_ahb_clk>;
+		clock-names = "core", "iface";
+		status = "disabled";
+	};
+
 	dma_blsp1: qcom,sps-dma@7884000 { /* BLSP1 */
 		#dma-cells = <4>;
 		compatible = "qcom,sps-dma";
@@ -1070,7 +1081,7 @@
 		rpm-channel-type = <15>; /* SMD_APPS_RPM */
 		};
 
-	qcom,wdt@b017000 {
+	wdog: qcom,wdt@b017000 {
 		compatible = "qcom,msm-watchdog";
 		reg = <0xb017000 0x1000>;
 		reg-names = "wdt-base";
diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi
index 1f8d20e..aff92a8 100644
--- a/arch/arm64/boot/dts/qcom/pm8005.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8005.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
@@ -25,11 +25,12 @@
 			reg = <0x100 0x100>;
 		};
 
-		qcom,temp-alarm@2400 {
+		pm8005_tz: qcom,temp-alarm@2400 {
 			compatible = "qcom,qpnp-temp-alarm";
 			reg = <0x2400 0x100>;
 			interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
 			label = "pm8005_tz";
+			#thermal-sensor-cells = <0>;
 		};
 
 		pm8005_gpios: pinctrl@c000 {
@@ -79,3 +80,28 @@
 		};
 	};
 };
+
+&thermal_zones {
+	pm8005_tz {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm8005_tz>;
+		trips {
+			pm8005-trip0 {
+				temperature = <105000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm8005-trip1 {
+				temperature = <125000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm8005-trip2 {
+				temperature = <145000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8937.dtsi b/arch/arm64/boot/dts/qcom/pm8937.dtsi
index 086a929..6a61445 100644
--- a/arch/arm64/boot/dts/qcom/pm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8937.dtsi
@@ -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
@@ -14,8 +14,8 @@
 &spmi_bus {
 
 	qcom,pm8937@0 {
-		spmi-slave-container;
-		reg = <0x0>;
+		compatible ="qcom,spmi-pmic";
+		reg = <0x0 SPMI_USID>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
@@ -27,10 +27,10 @@
 		qcom,power-on@800 {
 			compatible = "qcom,qpnp-power-on";
 			reg = <0x800 0x100>;
-			interrupts = <0x0 0x8 0x0>,
-				<0x0 0x8 0x1>,
-				<0x0 0x8 0x4>,
-				<0x0 0x8 0x5>;
+			interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>,
+				     <0x0 0x8 0x1 IRQ_TYPE_NONE>,
+				     <0x0 0x8 0x4 IRQ_TYPE_NONE>,
+				     <0x0 0x8 0x5 IRQ_TYPE_NONE>;
 			interrupt-names = "kpdpwr", "resin",
 				"resin-bark", "kpdpwr-resin-bark";
 			qcom,pon-dbc-delay = <15625>;
@@ -52,7 +52,7 @@
 		pm8937_temp_alarm: qcom,temp-alarm@2400 {
 			compatible = "qcom,qpnp-temp-alarm";
 			reg = <0x2400 0x100>;
-			interrupts = <0x0 0x24 0x0>;
+			interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
 			label = "pm8937_tz";
 			qcom,channel-num = <8>;
 			qcom,threshold-set = <0>;
@@ -65,7 +65,6 @@
 		};
 
 		pm8937_rtc: qcom,pm8937_rtc {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-rtc";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -78,110 +77,37 @@
 
 			qcom,pm8937_rtc_alarm@6100 {
 				reg = <0x6100 0x100>;
-				interrupts = <0x0 0x61 0x1>;
+				interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
 			};
 		};
 
 		pm8937_mpps: mpps {
-			compatible = "qcom,qpnp-pin";
-			spmi-dev-container;
+			compatible = "qcom,spmi-mpp";
+			reg = <0xa000 0x400>;
+			interrupts = <0x0 0xa0 0 IRQ_TYPE_NONE>,
+				     <0x0 0xa1 0 IRQ_TYPE_NONE>,
+				     <0x0 0xa2 0 IRQ_TYPE_NONE>,
+				     <0x0 0xa3 0 IRQ_TYPE_NONE>;
+			interrupt-names = "pm8937_mpp1", "pm8937_mpp2",
+					  "pm8937_mpp3", "pm8937_mpp4";
 			gpio-controller;
 			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pm8937-mpp";
-
-			mpp@a000 {
-				reg = <0xa000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			mpp@a100 {
-				/* MPP2 - PA_THERM config */
-				reg = <0xa100 0x100>;
-				qcom,pin-num = <2>;
-				qcom,mode = <4>; /* AIN input */
-				qcom,invert = <1>; /* Enable MPP */
-				qcom,ain-route = <1>; /* AMUX 6 */
-				qcom,master-en = <1>;
-				qcom,src-sel = <0>; /* Function constant */
-			};
-
-			mpp@a200 {
-				reg = <0xa200 0x100>;
-				qcom,pin-num = <3>;
-				status = "disabled";
-			};
-
-			mpp@a300 {
-				/* MPP4 - CASE_THERM config */
-				reg = <0xa300 0x100>;
-				qcom,pin-num = <4>;
-				qcom,mode = <4>; /* AIN input */
-				qcom,invert = <1>; /* Enable MPP */
-				qcom,ain-route = <3>; /* AMUX 8 */
-				qcom,master-en = <1>;
-				qcom,src-sel = <0>; /* Function constant */
-			};
 		};
 
 		pm8937_gpios: gpios {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-pin";
+			compatible = "qcom,spmi-gpio";
+			reg = <0xc000 0x800>;
+			interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>,
+				     <0x0 0xc1 0 IRQ_TYPE_NONE>,
+				     <0x0 0xc4 0 IRQ_TYPE_NONE>,
+				     <0x0 0xc6 0 IRQ_TYPE_NONE>,
+				     <0x0 0xc7 0 IRQ_TYPE_NONE>;
+			interrupt-names = "pm8937_gpio1", "pm8937_gpio2",
+					  "pm8937_gpio5", "pmi8937_gpio7",
+					  "pm8937_gpio8";
 			gpio-controller;
 			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pm8937-gpio";
-
-			gpio@c000 {
-				reg = <0xc000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			gpio@c100 {
-				reg = <0xc100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-
-			gpio@c200 {
-				reg = <0xc200 0x100>;
-				qcom,pin-num = <3>;
-				status = "disabled";
-			};
-
-			gpio@c300 {
-				reg = <0xc300 0x100>;
-				qcom,pin-num = <4>;
-				status = "disabled";
-			};
-
-			gpio@c400 {
-				reg = <0xc400 0x100>;
-				qcom,pin-num = <5>;
-				status = "disabled";
-			};
-
-			gpio@c500 {
-				reg = <0xc500 0x100>;
-				qcom,pin-num = <6>;
-				status = "disabled";
-			};
-
-			gpio@c600 {
-				reg = <0xc600 0x100>;
-				qcom,pin-num = <7>;
-				status = "disabled";
-			};
-
-			gpio@c700 {
-				reg = <0xc700 0x100>;
-				qcom,pin-num = <8>;
-				status = "disabled";
-			};
+			qcom,gpios-disallowed = <3 4 6>;
 		};
 
 		pm8937_vadc: vadc@3100 {
@@ -189,7 +115,7 @@
 			reg = <0x3100 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <0x0 0x31 0x0>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
@@ -326,9 +252,9 @@
 			reg = <0x3400 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts =	<0x0 0x34 0x0>,
-					<0x0 0x34 0x3>,
-					<0x0 0x34 0x4>;
+			interrupts =	<0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x34 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x34 0x4 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names =	"eoc-int-en-set",
 						"high-thr-en-set",
 						"low-thr-en-set";
@@ -365,8 +291,8 @@
 	};
 
 	pm8937_1: qcom,pm8937@1 {
-		spmi-slave-container;
-		reg = <0x1>;
+		compatible = "qcom,spmi-pmic";
+		reg = <0x1 SPMI_USID>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index 6b557e9..074b7da 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -32,6 +32,162 @@
 			qcom,secondary-pon-reset;
 		};
 
+		pmi632_vadc: vadc@3100 {
+			compatible = "qcom,qpnp-vadc-hc";
+			reg = <0x3100 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "eoc-int-en-set";
+			qcom,adc-vdd-reference = <1875>;
+			qcom,adc-full-scale-code = <0x70e4>;
+
+			chan@0 {
+				label = "ref_gnd";
+				reg = <0>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@1 {
+				label = "ref_1250v";
+				reg = <1>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@83 {
+				label = "vph_pwr";
+				reg = <0x83>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@84 {
+				label = "vbat_sns";
+				reg = <0x84>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <1>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@6 {
+				label = "die_temp";
+				reg = <6>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <19>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@7 {
+				label = "usb_in_i";
+				reg = <7>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <21>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@8 {
+				label = "usb_in_v";
+				reg = <8>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <8>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@9 {
+				label = "chg_temp";
+				reg = <9>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <18>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@4a {
+				label = "bat_therm";
+				reg = <0x4a>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <17>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@4b {
+				label = "bat_id";
+				reg = <0x4b>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+			chan@4c {
+				label = "xo_therm";
+				reg = <0x4c>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "ratiometric";
+				qcom,scale-function = <4>;
+				qcom,hw-settle-time = <8>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+
+			chan@1e {
+				label = "mid_chg";
+				reg = <0x1e>;
+				qcom,decimation = <2>;
+				qcom,pre-div-channel-scaling = <3>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+				qcom,cal-val = <0>;
+			};
+
+		};
+
 		pmi632_tz: qcom,temp-alarm@2400 {
 			compatible = "qcom,qpnp-temp-alarm";
 			reg = <0x2400 0x100>;
@@ -123,5 +279,30 @@
 			#pwm-cells = <2>;
 			status = "disabled";
 		};
+
+		pmi632_lcdb: qpnp-lcdb@ec00 {
+			compatible = "qcom,qpnp-lcdb-regulator";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0xec00 0x100>;
+			interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "sc-irq";
+
+			qcom,pmic-revid = <&pmi632_revid>;
+
+			lcdb_ldo_vreg: ldo {
+				label = "ldo";
+				regulator-name = "lcdb_ldo";
+				regulator-min-microvolt = <4000000>;
+				regulator-max-microvolt = <6000000>;
+			};
+
+			lcdb_ncp_vreg: ncp {
+				label = "ncp";
+				regulator-name = "lcdb_ncp";
+				regulator-min-microvolt = <4000000>;
+				regulator-max-microvolt = <6000000>;
+			};
+		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
index d5b9945..a7aa08a 100644
--- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
@@ -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
@@ -16,8 +16,8 @@
 &spmi_bus {
 
 	qcom,pmi8937@2 {
-		spmi-slave-container;
-		reg = <0x2>;
+		compatible ="qcom,spmi-pmic";
+		reg = <0x2 SPMI_USID>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
@@ -45,7 +45,7 @@
 			reg = <0x3100 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <0x2 0x31 0x0>;
+			interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
@@ -141,35 +141,19 @@
 		};
 
 		pmi8937_mpps: mpps {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-pin";
+			compatible = "qcom,spmi-mpp";
+			reg = <0xa000 0x400>;
+			interrupts = <0x2 0xa0 0 IRQ_TYPE_NONE>,
+				     <0x2 0xa1 0 IRQ_TYPE_NONE>,
+				     <0x2 0xa2 0 IRQ_TYPE_NONE>,
+				     <0x2 0xa3 0 IRQ_TYPE_NONE>;
+			interrupt-names = "pmi8937_mpp1", "pmi8937_mpp2",
+					  "pmi8937_mpp3", "pmi8937_mpp4";
 			gpio-controller;
 			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pmi8937-mpp";
-
-			mpp@a000 {
-				reg = <0xa000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			mpp@a100 {
-				reg = <0xa100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-
-			mpp@a300 {
-				reg = <0xa300 0x100>;
-				qcom,pin-num = <4>;
-				status = "disabled";
-			};
 		};
 
 		pmi8937_charger: qcom,qpnp-smbcharger {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -191,14 +175,14 @@
 
 			qcom,chgr@1000 {
 				reg = <0x1000 0x100>;
-				interrupts =	<0x2 0x10 0x0>,
-						<0x2 0x10 0x1>,
-						<0x2 0x10 0x2>,
-						<0x2 0x10 0x3>,
-						<0x2 0x10 0x4>,
-						<0x2 0x10 0x5>,
-						<0x2 0x10 0x6>,
-						<0x2 0x10 0x7>;
+				interrupts =	<0x2 0x10 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"chg-error",
 							"chg-inhibit",
@@ -212,9 +196,9 @@
 
 			qcom,otg@1100 {
 				reg = <0x1100 0x100>;
-				interrupts =	<0x2 0x11 0x0>,
-						<0x2 0x11 0x1>,
-						<0x2 0x11 0x3>;
+				interrupts =	<0x2 0x11 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x11 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x11 0x3 IRQ_TYPE_NONE>;
 				interrupt-names =	"otg-fail",
 							"otg-oc",
 						"usbid-change";
@@ -222,14 +206,14 @@
 
 			qcom,bat-if@1200 {
 				reg = <0x1200 0x100>;
-				interrupts =	<0x2 0x12 0x0>,
-						<0x2 0x12 0x1>,
-						<0x2 0x12 0x2>,
-						<0x2 0x12 0x3>,
-					<0x2 0x12 0x4>,
-						<0x2 0x12 0x5>,
-						<0x2 0x12 0x6>,
-						<0x2 0x12 0x7>;
+				interrupts =	<0x2 0x12 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"batt-hot",
 							"batt-warm",
@@ -243,10 +227,10 @@
 
 			qcom,usb-chgpth@1300 {
 				reg = <0x1300 0x100>;
-				interrupts =	<0x2 0x13 0x0>,
-						<0x2 0x13 0x1>,
-					<0x2 0x13 0x2>,
-						<0x2 0x13 0x5>;
+				interrupts =	<0x2 0x13 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x5 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"usbin-uv",
 						"usbin-ov",
@@ -256,20 +240,20 @@
 
 			qcom,dc-chgpth@1400 {
 				reg = <0x1400 0x100>;
-				interrupts =	<0x2 0x14 0x0>,
-						<0x2 0x14 0x1>;
+				interrupts =	<0x2 0x14 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x14 0x1 IRQ_TYPE_NONE>;
 				interrupt-names =	"dcin-uv",
 							"dcin-ov";
 			};
 
 			qcom,chgr-misc@1600 {
 				reg = <0x1600 0x100>;
-				interrupts =	<0x2 0x16 0x0>,
-						<0x2 0x16 0x1>,
-						<0x2 0x16 0x2>,
-					<0x2 0x16 0x3>,
-						<0x2 0x16 0x4>,
-						<0x2 0x16 0x5>;
+				interrupts =	<0x2 0x16 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x5 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"power-ok",
 							"temp-shutdown",
@@ -285,7 +269,6 @@
 		};
 
 		pmi8937_fg: qcom,fg {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -303,13 +286,13 @@
 			qcom,fg-soc@4000 {
 			status = "okay";
 				reg = <0x4000 0x100>;
-				interrupts =	<0x2 0x40 0x0>,
-						<0x2 0x40 0x1>,
-						<0x2 0x40 0x2>,
-						<0x2 0x40 0x3>,
-						<0x2 0x40 0x4>,
-						<0x2 0x40 0x5>,
-						<0x2 0x40 0x6>;
+				interrupts =	<0x2 0x40 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x6 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"high-soc",
 							"low-soc",
@@ -322,14 +305,14 @@
 
 			qcom,fg-batt@4100 {
 				reg = <0x4100 0x100>;
-				interrupts =	<0x2 0x41 0x0>,
-						<0x2 0x41 0x1>,
-					<0x2 0x41 0x2>,
-						<0x2 0x41 0x3>,
-						<0x2 0x41 0x4>,
-						<0x2 0x41 0x5>,
-						<0x2 0x41 0x6>,
-						<0x2 0x41 0x7>;
+				interrupts =	<0x2 0x41 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"soft-cold",
 							"soft-hot",
@@ -348,8 +331,8 @@
 			qcom,fg-memif@4400 {
 				status = "okay";
 				reg = <0x4400 0x100>;
-				interrupts =	<0x2 0x44 0x0>,
-						<0x2 0x44 0x2>;
+				interrupts =	<0x2 0x44 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x44 0x2 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"mem-avail",
 							"data-rcvry-sug";
@@ -360,8 +343,8 @@
 			compatible = "qcom,msm-bcl";
 			reg = <0x4200 0xff>;
 			reg-names = "fg_user_adc";
-			interrupts = <0x2 0x42 0x0>,
-					<0x2 0x42 0x1>;
+			interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+				     <0x2 0x42 0x1 IRQ_TYPE_NONE>;
 			interrupt-names = "bcl-high-ibat-int",
 					"bcl-low-vbat-int";
 			qcom,vbat-scaling-factor = <39000>;
@@ -384,8 +367,8 @@
 	};
 
 	qcom,pmi8937@3 {
-		spmi-slave-container;
-		reg = <0x3>;
+		compatible ="qcom,spmi-pmic";
+		reg = <0x3 SPMI_USID>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
@@ -405,7 +388,7 @@
 				<0xd900 0x100>;
 			reg-names = "qpnp-wled-ctrl-base",
 					"qpnp-wled-sink-base";
-			interrupts = <0x3 0xd8 0x2>;
+			interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "sc-irq";
 			status = "okay";
 			linux,name = "wled";
@@ -424,6 +407,7 @@
 			qcom,fs-curr-ua = <20000>;
 			qcom,led-strings-list = [00 01];
 			qcom,en-ext-pfet-sc-pro;
+			qcom,pmic-revid = <&pmi8937_revid>;
 			qcom,cons-sync-write-delay-us = <1000>;
 		};
 
@@ -510,8 +494,8 @@
 		pmi_haptic: qcom,haptic@c000 {
 			compatible = "qcom,qpnp-haptic";
 			reg = <0xc000 0x100>;
-			interrupts = <0x3 0xc0 0x0>,
-				<0x3 0xc0 0x1>;
+			interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
 			interrupt-names = "sc-irq", "play-irq";
 			qcom,pmic-revid = <&pmi8937_revid>;
 			vcc_pon-supply = <&pon_perph_reg>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8940.dtsi b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
index 59001ba..c6d5c87 100644
--- a/arch/arm64/boot/dts/qcom/pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8940.dtsi
@@ -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
@@ -14,10 +14,9 @@
 #include <dt-bindings/msm/power-on.h>
 
 &spmi_bus {
-
 	qcom,pmi8940@2 {
-		spmi-slave-container;
-		reg = <0x2>;
+		compatible ="qcom,spmi-pmic";
+		reg = <0x2 SPMI_USID>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
@@ -45,7 +44,7 @@
 			reg = <0x3100 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <0x2 0x31 0x0>;
+			interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
@@ -141,35 +140,19 @@
 		};
 
 		pmi8940_mpps: mpps {
-			spmi-dev-container;
-			compatible = "qcom,qpnp-pin";
+			compatible = "qcom,spmi-mpp";
+			reg = <0xa000 0x400>;
+			interrupts = <0x2 0xa0 0 IRQ_TYPE_NONE>,
+				     <0x2 0xa1 0 IRQ_TYPE_NONE>,
+				     <0x2 0xa2 0 IRQ_TYPE_NONE>,
+				     <0x2 0xa3 0 IRQ_TYPE_NONE>;
+			interrupt-names = "pmi8940_mpp1", "pmi8940_mpp2",
+					  "pmi8940_mpp3", "pmi8940_mpp4";
 			gpio-controller;
 			#gpio-cells = <2>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			label = "pmi8940-mpp";
-
-			mpp@a000 {
-				reg = <0xa000 0x100>;
-				qcom,pin-num = <1>;
-				status = "disabled";
-			};
-
-			mpp@a100 {
-				reg = <0xa100 0x100>;
-				qcom,pin-num = <2>;
-				status = "disabled";
-			};
-
-			mpp@a300 {
-				reg = <0xa300 0x100>;
-				qcom,pin-num = <4>;
-				status = "disabled";
-			};
 		};
 
 		pmi8940_charger: qcom,qpnp-smbcharger {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -188,14 +171,14 @@
 
 			qcom,chgr@1000 {
 				reg = <0x1000 0x100>;
-				interrupts =	<0x2 0x10 0x0>,
-						<0x2 0x10 0x1>,
-						<0x2 0x10 0x2>,
-						<0x2 0x10 0x3>,
-						<0x2 0x10 0x4>,
-						<0x2 0x10 0x5>,
-						<0x2 0x10 0x6>,
-						<0x2 0x10 0x7>;
+				interrupts =	<0x2 0x10 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"chg-error",
 							"chg-inhibit",
@@ -209,9 +192,9 @@
 
 			qcom,otg@1100 {
 				reg = <0x1100 0x100>;
-				interrupts =	<0x2 0x11 0x0>,
-						<0x2 0x11 0x1>,
-						<0x2 0x11 0x3>;
+				interrupts =	<0x2 0x11 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x11 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x11 0x3 IRQ_TYPE_NONE>;
 				interrupt-names =	"otg-fail",
 							"otg-oc",
 						"usbid-change";
@@ -219,14 +202,14 @@
 
 			qcom,bat-if@1200 {
 				reg = <0x1200 0x100>;
-				interrupts =	<0x2 0x12 0x0>,
-						<0x2 0x12 0x1>,
-						<0x2 0x12 0x2>,
-						<0x2 0x12 0x3>,
-					<0x2 0x12 0x4>,
-						<0x2 0x12 0x5>,
-						<0x2 0x12 0x6>,
-						<0x2 0x12 0x7>;
+				interrupts =	<0x2 0x12 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"batt-hot",
 							"batt-warm",
@@ -240,10 +223,10 @@
 
 			qcom,usb-chgpth@1300 {
 				reg = <0x1300 0x100>;
-				interrupts =	<0x2 0x13 0x0>,
-						<0x2 0x13 0x1>,
-					<0x2 0x13 0x2>,
-						<0x2 0x13 0x5>;
+				interrupts =	<0x2 0x13 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x5 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"usbin-uv",
 						"usbin-ov",
@@ -253,20 +236,20 @@
 
 			qcom,dc-chgpth@1400 {
 				reg = <0x1400 0x100>;
-				interrupts =	<0x2 0x14 0x0>,
-						<0x2 0x14 0x1>;
+				interrupts =	<0x2 0x14 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x14 0x1 IRQ_TYPE_NONE>;
 				interrupt-names =	"dcin-uv",
 							"dcin-ov";
 			};
 
 			qcom,chgr-misc@1600 {
 				reg = <0x1600 0x100>;
-				interrupts =	<0x2 0x16 0x0>,
-						<0x2 0x16 0x1>,
-						<0x2 0x16 0x2>,
-					<0x2 0x16 0x3>,
-						<0x2 0x16 0x4>,
-						<0x2 0x16 0x5>;
+				interrupts =	<0x2 0x16 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x5 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"power-ok",
 							"temp-shutdown",
@@ -282,7 +265,6 @@
 		};
 
 		pmi8940_fg: qcom,fg {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -300,13 +282,13 @@
 			qcom,fg-soc@4000 {
 			status = "okay";
 				reg = <0x4000 0x100>;
-				interrupts =	<0x2 0x40 0x0>,
-						<0x2 0x40 0x1>,
-						<0x2 0x40 0x2>,
-						<0x2 0x40 0x3>,
-						<0x2 0x40 0x4>,
-						<0x2 0x40 0x5>,
-						<0x2 0x40 0x6>;
+				interrupts =	<0x2 0x40 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x6 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"high-soc",
 							"low-soc",
@@ -319,14 +301,14 @@
 
 			qcom,fg-batt@4100 {
 				reg = <0x4100 0x100>;
-				interrupts =	<0x2 0x41 0x0>,
-						<0x2 0x41 0x1>,
-					<0x2 0x41 0x2>,
-						<0x2 0x41 0x3>,
-						<0x2 0x41 0x4>,
-						<0x2 0x41 0x5>,
-						<0x2 0x41 0x6>,
-						<0x2 0x41 0x7>;
+				interrupts =	<0x2 0x41 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"soft-cold",
 							"soft-hot",
@@ -345,8 +327,8 @@
 			qcom,fg-memif@4400 {
 				status = "okay";
 				reg = <0x4400 0x100>;
-				interrupts =	<0x2 0x44 0x0>,
-						<0x2 0x44 0x2>;
+				interrupts =	<0x2 0x44 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x44 0x2 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"mem-avail",
 							"data-rcvry-sug";
@@ -357,8 +339,8 @@
 			compatible = "qcom,msm-bcl";
 			reg = <0x4200 0xff>;
 			reg-names = "fg_user_adc";
-			interrupts = <0x2 0x42 0x0>,
-					<0x2 0x42 0x1>;
+			interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+				     <0x2 0x42 0x1 IRQ_TYPE_NONE>;
 			interrupt-names = "bcl-high-ibat-int",
 					"bcl-low-vbat-int";
 			qcom,vbat-scaling-factor = <39000>;
@@ -381,8 +363,8 @@
 	};
 
 	qcom,pmi8940@3 {
-		spmi-slave-container;
-		reg = <0x3>;
+		compatible ="qcom,spmi-pmic";
+		reg = <0x3 SPMI_USID>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
@@ -398,10 +380,10 @@
 
 		labibb: qpnp-labibb-regulator {
 			status = "disabled";
-			spmi-dev-container;
 			compatible = "qcom,qpnp-labibb-regulator";
 			#address-cells = <1>;
 			#size-cells = <1>;
+			qcom,qpnp-labibb-mode = "lcd";
 			qcom,pmic-revid = <&pmi8940_revid>;
 
 			ibb_regulator: qcom,ibb@dc00 {
@@ -475,7 +457,7 @@
 				<0xd900 0x100>;
 			reg-names = "qpnp-wled-ctrl-base",
 					"qpnp-wled-sink-base";
-			interrupts = <0x3 0xd8 0x2>;
+			interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "sc-irq";
 			status = "okay";
 			linux,name = "wled";
@@ -495,6 +477,7 @@
 			qcom,en-phase-stag;
 			qcom,led-strings-list = [00 01];
 			qcom,en-ext-pfet-sc-pro;
+			qcom,pmic-revid = <&pmi8940_revid>;
 			qcom,cons-sync-write-delay-us = <1000>;
 		};
 
@@ -581,8 +564,8 @@
 		pmi_haptic: qcom,haptic@c000 {
 			compatible = "qcom,qpnp-haptic";
 			reg = <0xc000 0x100>;
-			interrupts = <0x3 0xc0 0x0>,
-				<0x3 0xc0 0x1>;
+			interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
 			interrupt-names = "sc-irq", "play-irq";
 			qcom,pmic-revid = <&pmi8940_revid>;
 			vcc_pon-supply = <&pon_perph_reg>;
diff --git a/arch/arm64/boot/dts/qcom/sda632.dtsi b/arch/arm64/boot/dts/qcom/sda632.dtsi
new file mode 100644
index 0000000..8a71b19
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda632.dtsi
@@ -0,0 +1,24 @@
+/*
+ * 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 "sdm632.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA632";
+	compatible = "qcom,sda632";
+	qcom,msm-id = <350 0x0>;
+};
+
+&secure_mem {
+	status = "disabled";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
new file mode 100644
index 0000000..944ca3b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
@@ -0,0 +1,271 @@
+/* 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
+ * 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.
+ */
+
+&mdm3 {
+	pinctrl-names = "default", "mdm_active", "mdm_suspend";
+	pinctrl-0 = <&ap2mdm_pon_reset_default>;
+	pinctrl-1 = <&ap2mdm_active &mdm2ap_active>;
+	pinctrl-2 = <&ap2mdm_sleep &mdm2ap_sleep>;
+	interrupt-map = <0 &tlmm 24 0x3
+			1 &tlmm 21 0x3>;
+	qcom,mdm2ap-errfatal-gpio = <&tlmm 24 0x00>;
+	qcom,ap2mdm-errfatal-gpio = <&tlmm 23 0x00>;
+	qcom,mdm2ap-status-gpio   = <&tlmm 22 0x00>;
+	qcom,ap2mdm-status-gpio   = <&tlmm 21 0x00>;
+	qcom,ap2mdm-soft-reset-gpio = <&pm8998_gpios 10 0>;
+	qcom,mdm-link-info = "0304_00.01.00";
+	status = "ok";
+};
+
+&pm8998_gpios {
+	ap2mdm_pon_reset {
+		ap2mdm_pon_reset_default: ap2mdm_pon_reset_default {
+			/* MDM PON conrol*/
+			pins = "gpio10";
+			function = "normal";
+			output-low;
+			power-source = <0>;
+		};
+	};
+};
+
+&pil_modem {
+	status = "disabled";
+};
+
+&pcie0_wake_default {
+	config {
+	       /delete-property/ bias-pull-down;
+	};
+};
+
+&led_flash_rear {
+	status = "disabled";
+};
+
+&led_flash_front {
+	status = "disabled";
+};
+
+&ois_rear {
+	status = "disabled";
+};
+
+&eeprom_rear {
+	status = "disabled";
+};
+
+&eeprom_rear_aux {
+	status = "disabled";
+};
+
+&eeprom_front {
+	status = "disabled";
+};
+
+&soc {
+	qcom,cam-req-mgr {
+		status = "disabled";
+	};
+
+	cam_csiphy0: qcom,csiphy@ac65000 {
+		status = "disabled";
+	};
+
+	cam_csiphy1: qcom,csiphy@ac66000 {
+		status = "disabled";
+	};
+
+	cam_csiphy2: qcom,csiphy@ac67000 {
+		status = "disabled";
+	};
+
+	cam_cci: qcom,cci@ac4a000 {
+		status = "disabled";
+
+		i2c_freq_100Khz: qcom,i2c_standard_mode {
+			status = "disabled";
+		};
+
+		i2c_freq_400Khz: qcom,i2c_fast_mode {
+			status = "disabled";
+		};
+
+		i2c_freq_custom: qcom,i2c_custom_mode {
+			status = "disabled";
+		};
+
+		i2c_freq_1Mhz: qcom,i2c_fast_plus_mode {
+			status = "disabled";
+		};
+	};
+
+	qcom,cam_smmu {
+		status = "disabled";
+
+		msm_cam_smmu_ife {
+			ife_iova_mem_map: iova-mem-map {
+				iova-mem-region-io {
+					status = "disabled";
+				};
+			};
+		};
+
+		msm_cam_smmu_jpeg {
+			jpeg_iova_mem_map: iova-mem-map {
+				iova-mem-region-io {
+					status = "disabled";
+				};
+			};
+		};
+
+		msm_cam_smmu_icp {
+			icp_iova_mem_map: iova-mem-map {
+				iova-mem-region-firmware {
+					status = "disabled";
+				};
+
+				iova-mem-region-shared {
+					status = "disabled";
+				};
+
+				iova-mem-region-io {
+					status = "disabled";
+				};
+			};
+		};
+
+		msm_cam_smmu_cpas_cdm {
+			cpas_cdm_iova_mem_map: iova-mem-map {
+				iova-mem-region-io {
+					status = "disabled";
+				};
+			};
+		};
+
+		msm_cam_smmu_fd {
+			fd_iova_mem_map: iova-mem-map {
+				iova-mem-region-io {
+					status = "disabled";
+				};
+			};
+		};
+	};
+
+	qcom,cam-cpas@ac40000 {
+		status = "disabled";
+	};
+
+	qcom,cam-cdm-intf {
+		status = "disabled";
+	};
+
+	qcom,cpas-cdm0@ac48000 {
+		status = "disabled";
+	};
+
+	qcom,cam-isp {
+		status = "disabled";
+	};
+
+	cam_csid0: qcom,csid0@acb3000 {
+		status = "disabled";
+	};
+
+	cam_vfe0: qcom,vfe0@acaf000 {
+		status = "disabled";
+	};
+
+	cam_csid1: qcom,csid1@acba000 {
+		status = "disabled";
+	};
+
+	cam_vfe1: qcom,vfe1@acb6000 {
+		status = "disabled";
+	};
+
+	cam_csid_lite: qcom,csid-lite@acc8000 {
+		status = "disabled";
+	};
+
+	cam_vfe_lite: qcom,vfe-lite@acc4000 {
+		status = "disabled";
+	};
+
+	qcom,cam-icp {
+		status = "disabled";
+	};
+
+	cam_a5: qcom,a5@ac00000 {
+		status = "disabled";
+	};
+
+	cam_ipe0: qcom,ipe0 {
+		status = "disabled";
+	};
+
+	cam_ipe1: qcom,ipe1 {
+		status = "disabled";
+	};
+
+	cam_bps: qcom,bps {
+		status = "disabled";
+	};
+
+	clock_camcc: qcom,camcc@ad00000 {
+		status = "disabled";
+	};
+
+	qcom,cam-jpeg {
+		status = "disabled";
+	};
+
+	cam_jpeg_enc: qcom,jpegenc@ac4e000 {
+		status = "disabled";
+	};
+
+	cam_jpeg_dma: qcom,jpegdma@0xac52000 {
+		status = "disabled";
+	};
+
+	qcom,cam-fd {
+		status = "disabled";
+	};
+
+	cam_fd: qcom,fd@ac5a000  {
+		status = "disabled";
+	};
+
+	qcom,cam-sensor@0 {
+		status = "disabled";
+	};
+
+	qcom,cam-sensor@1 {
+		status = "disabled";
+	};
+
+	qcom,cam-sensor@2 {
+		status = "disabled";
+	};
+
+	qcom,cam-sensor@3 {
+		status = "disabled";
+	};
+
+	cam_csiphy3: qcom,csiphy@ac68000 {
+		status = "disabled";
+	};
+};
+
+&wil6210 {
+	status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts
new file mode 100644
index 0000000..5377813
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-mtp-sdxpoorwills-overlay.dts
@@ -0,0 +1,34 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "external-soc.dtsi"
+#include "sda845-sdxpoorwills.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA845 v2 + SDXPOORWILLS MTP";
+	compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp";
+	qcom,msm-id = <341 0x20000>;
+	qcom,board-id = <8 5>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts
new file mode 100644
index 0000000..10e4a32
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-cdp-sdxpoorwills-overlay.dts
@@ -0,0 +1,34 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-cdp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "external-soc.dtsi"
+#include "sda845-sdxpoorwills.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA845 v2.1 + SDXPOORWILLS CDP";
+	compatible = "qcom,sda845-cdp", "qcom,sda845", "qcom,cdp";
+	qcom,msm-id = <341 0x20001>;
+	qcom,board-id = <1 2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts b/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts
new file mode 100644
index 0000000..09fa20f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda845-v2.1-mtp-sdxpoorwills-overlay.dts
@@ -0,0 +1,34 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm845-sde-display.dtsi"
+#include "sdm845-mtp.dtsi"
+#include "sdm845-audio-overlay.dtsi"
+#include "external-soc.dtsi"
+#include "sda845-sdxpoorwills.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDA845 v2.1 + SDXPOORWILLS MTP";
+	compatible = "qcom,sda845-mtp", "qcom,sda845", "qcom,mtp";
+	qcom,msm-id = <341 0x20001>;
+	qcom,board-id = <8 5>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
new file mode 100644
index 0000000..700e950
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8937.dts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "sdm450.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM450 + PMI8937 SOC";
+	compatible = "qcom,sdm450";
+	qcom,pmic-id = <0x010016 0x020037 0x0 0x0>;
+	qcom,pmic-name = "PMI8937";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
new file mode 100644
index 0000000..f50d177
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi8940.dts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "sdm450.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM450 + PMI8940 SOC";
+	compatible = "qcom,sdm450";
+	qcom,pmic-id = <0x010016 0x020040 0x0 0x0>;
+	qcom,pmic-name = "PMI8940";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dts b/arch/arm64/boot/dts/qcom/sdm450.dts
new file mode 100644
index 0000000..b829b81
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm450.dts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "sdm450.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM450 + PMI8950 SOC";
+	compatible = "qcom,sdm450";
+	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
+	qcom,pmic-name = "PMI8950";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dtsi b/arch/arm64/boot/dts/qcom/sdm450.dtsi
index 2f3e8c4..3e24714 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450.dtsi
@@ -17,6 +17,7 @@
 	model = "Qualcomm Technologies, Inc. SDM450";
 	compatible = "qcom,sdm450";
 	qcom,msm-id = <338 0x0>;
+	qcom,msm-name = "SDM450";
 };
 
 &CPU4 {
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
new file mode 100644
index 0000000..031fd7e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
@@ -0,0 +1,267 @@
+/*
+ * 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.
+ */
+
+/ {
+	/delete-node/ cpus;
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&CPU0>;
+				};
+				core1 {
+					cpu = <&CPU1>;
+				};
+				core2 {
+					cpu = <&CPU2>;
+				};
+				core3 {
+					cpu = <&CPU3>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&CPU4>;
+				};
+				core1 {
+					cpu = <&CPU5>;
+				};
+				core2 {
+					cpu = <&CPU6>;
+				};
+				core3 {
+					cpu = <&CPU7>;
+				};
+			};
+		};
+
+		CPU0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			reg = <0x0 0x0>;
+			enable-method = "psci";
+			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+			next-level-cache = <&L2_0>;
+			L2_0: l2-cache {
+			      compatible = "arm,arch-cache";
+			      cache-level = <2>;
+			      /* A53 L2 dump not supported */
+			      qcom,dump-size = <0x0>;
+			};
+			L1_I_0: l1-icache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_D_0: l1-dcache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_TLB_0: l1-tlb {
+				qcom,dump-size = <0x2800>;
+			};
+		};
+
+		CPU1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			enable-method = "psci";
+			reg = <0x0 0x1>;
+			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+			next-level-cache = <&L2_0>;
+			L1_I_1: l1-icache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_D_1: l1-dcache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_TLB_1: l1-tlb {
+				qcom,dump-size = <0x2800>;
+			};
+		};
+
+		CPU2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			enable-method = "psci";
+			reg = <0x0 0x2>;
+			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+			next-level-cache = <&L2_0>;
+			L1_I_2: l1-icache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_D_2: l1-dcache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_TLB_2: l1-tlb {
+				qcom,dump-size = <0x2800>;
+			};
+		};
+
+		CPU3: cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			enable-method = "psci";
+			reg = <0x0 0x3>;
+			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
+			next-level-cache = <&L2_0>;
+			L1_I_3: l1-icache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_D_3: l1-dcache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_TLB_3: l1-tlb {
+				qcom,dump-size = <0x2800>;
+			};
+		};
+
+		CPU4: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,armv8";
+			enable-method = "psci";
+			reg = <0x0 0x100>;
+			efficiency = <1638>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			next-level-cache = <&L2_1>;
+			L2_1: l2-cache {
+			      compatible = "arm,arch-cache";
+			      cache-level = <2>;
+			};
+			L1_I_100: l1-icache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x12000>;
+			};
+			L1_D_100: l1-dcache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_TLB_100: l1-tlb {
+				qcom,dump-size = <0x4800>;
+			};
+		};
+
+		CPU5: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53","arm,armv8";
+			enable-method = "psci";
+			reg = <0x0 0x101>;
+			efficiency = <1638>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			next-level-cache = <&L2_1>;
+			L1_I_101: l1-icache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x12000>;
+			};
+			L1_D_101: l1-dcache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_TLB_101: l1-tlb {
+				qcom,dump-size = <0x4800>;
+			};
+		};
+
+		CPU6: cpu@102 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53","arm,armv8";
+			enable-method = "psci";
+			reg = <0x0 0x102>;
+			efficiency = <1638>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			next-level-cache = <&L2_1>;
+			L1_I_102: l1-icache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x12000>;
+			};
+			L1_D_102: l1-dcache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_TLB_102: l1-tlb {
+				qcom,dump-size = <0x4800>;
+			};
+		};
+
+		CPU7: cpu@103 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53","arm,armv8";
+			enable-method = "psci";
+			reg = <0x0 0x103>;
+			efficiency = <1638>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
+			next-level-cache = <&L2_1>;
+			L1_I_103: l1-icache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x12000>;
+			};
+			L1_D_103: l1-dcache {
+			      compatible = "arm,arch-cache";
+			      qcom,dump-size = <0x9040>;
+			};
+			L1_TLB_103: l1-tlb {
+				qcom,dump-size = <0x4800>;
+			};
+		};
+	};
+};
+
+&cpuss_dump {
+	qcom,l1_tlb_dump0 {
+		qcom,dump-node = <&L1_TLB_0>;
+		qcom,dump-id = <0x20>;
+	};
+	qcom,l1_tlb_dump1 {
+		qcom,dump-node = <&L1_TLB_1>;
+		qcom,dump-id = <0x21>;
+	};
+	qcom,l1_tlb_dump2 {
+		qcom,dump-node = <&L1_TLB_2>;
+		qcom,dump-id = <0x22>;
+	};
+	qcom,l1_tlb_dump3 {
+		qcom,dump-node = <&L1_TLB_3>;
+		qcom,dump-id = <0x23>;
+	};
+	qcom,l1_tlb_dump100 {
+		qcom,dump-node = <&L1_TLB_100>;
+		qcom,dump-id = <0x24>;
+	};
+	qcom,l1_tlb_dump101 {
+		qcom,dump-node = <&L1_TLB_101>;
+		qcom,dump-id = <0x25>;
+	};
+	qcom,l1_tlb_dump102 {
+		qcom,dump-node = <&L1_TLB_102>;
+		qcom,dump-id = <0x26>;
+	};
+	qcom,l1_tlb_dump103 {
+		qcom,dump-node = <&L1_TLB_103>;
+		qcom,dump-id = <0x27>;
+	};
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm632-rumi.dts b/arch/arm64/boot/dts/qcom/sdm632-rumi.dts
new file mode 100644
index 0000000..5a6f88a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-rumi.dts
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "sdm632.dtsi"
+#include "sdm632-rumi.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632 RUMI";
+	compatible = "qcom,sdm632-rumi", "qcom,sdm632", "qcom,rumi";
+	qcom,board-id = <15 0>;
+	qcom,pmic-id = <0 0 0 0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi
new file mode 100644
index 0000000..3ba8a4d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-rumi.dtsi
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+&blsp1_serial1 {
+	status = "ok";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_console_active>;
+};
+
+&wdog {
+	status = "disabled";
+};
+
+&modem_mem {
+	status = "disabled";
+};
+
+&adsp_fw_mem {
+	status = "disabled";
+};
+
+&wcnss_fw_mem {
+	status = "disabled";
+};
+
+&venus_mem {
+	status = "disabled";
+};
+
+&secure_mem {
+	status = "disabled";
+};
+
+&qseecom_mem {
+	status = "disabled";
+};
+
+&adsp_mem {
+	status = "disabled";
+};
+
+&dfps_data_mem {
+	status = "disabled";
+};
+
+&cont_splash_mem {
+	status = "disabled";
+};
+
+&gpu_mem {
+	status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi
new file mode 100644
index 0000000..3ebd50e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi
@@ -0,0 +1,22 @@
+/*
+ * 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 "msm8953.dtsi"
+#include "sdm632-cpu.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM632";
+	compatible = "qcom,sdm632";
+	qcom,msm-id = <349 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 1f40e20..715affd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -229,6 +229,7 @@
 	qcom,cam_smmu {
 		compatible = "qcom,msm-cam-smmu";
 		status = "ok";
+		non-fatal-fault-disabled;
 
 		msm_cam_smmu_lrme {
 			compatible = "qcom,msm-cam-smmu-cb";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts
new file mode 100644
index 0000000..15fadc6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp-overlay.dts
@@ -0,0 +1,74 @@
+/* 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A + Tasha Codec CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <1 5>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_panel_pwr_supply_labibb_amoled {
+	qcom,panel-supply-entry@2 {
+		reg = <2>;
+		qcom,supply-name = "lab";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6100000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@3 {
+		reg = <3>;
+		qcom,supply-name = "ibb";
+		qcom,supply-min-voltage = <4000000>;
+		qcom,supply-max-voltage = <6300000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@4 {
+		reg = <4>;
+		qcom,supply-name = "oledb";
+		qcom,supply-min-voltage = <5000000>;
+		qcom,supply-max-voltage = <8100000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+};
+
+&dsi_rm67195_amoled_fhd_cmd_display {
+	qcom,dsi-display-active;
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+	oledb-supply = <&pm660a_oledb>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts
new file mode 100644
index 0000000..ec906ee
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-tasha-codec-cdp.dts
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+#include "sdm670-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A Tasha Codec CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,board-id = <1 5>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&dsi_panel_pwr_supply_labibb_amoled {
+	qcom,panel-supply-entry@2 {
+		reg = <2>;
+		qcom,supply-name = "lab";
+		qcom,supply-min-voltage = <4600000>;
+		qcom,supply-max-voltage = <6100000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@3 {
+		reg = <3>;
+		qcom,supply-name = "ibb";
+		qcom,supply-min-voltage = <4000000>;
+		qcom,supply-max-voltage = <6300000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+
+	qcom,panel-supply-entry@4 {
+		reg = <4>;
+		qcom,supply-name = "oledb";
+		qcom,supply-min-voltage = <5000000>;
+		qcom,supply-max-voltage = <8100000>;
+		qcom,supply-enable-load = <100000>;
+		qcom,supply-disable-load = <100>;
+	};
+};
+
+&dsi_rm67195_amoled_fhd_cmd_display {
+	qcom,dsi-display-active;
+	lab-supply = <&lab_regulator>;
+	ibb-supply = <&ibb_regulator>;
+	oledb-supply = <&pm660a_oledb>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts
new file mode 100644
index 0000000..cc772cd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp-overlay.dts
@@ -0,0 +1,33 @@
+/* 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.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "sdm670-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Tasha Codec CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <1 5>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts
new file mode 100644
index 0000000..e862911
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-tasha-codec-cdp.dts
@@ -0,0 +1,27 @@
+/* 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.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "sdm670-audio-overlay.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L Tasha Codec CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,board-id = <1 5>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
index 8cbc84f..a0fa9cf 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.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
@@ -471,7 +471,7 @@
 			};
 			gpu_vdd_cdev {
 				trip = <&aoss0_trip>;
-				cooling-device = <&msm_gpu 4 4>;
+				cooling-device = <&msm_gpu 0 0>;
 			};
 			cx_vdd_cdev {
 				trip = <&aoss0_trip>;
@@ -496,606 +496,6 @@
 		};
 	};
 
-	cpu0-silver-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 1>;
-		tracks-low;
-		trips {
-			cpu0_trip: cpu0-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&cpu0_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&cpu0_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&cpu0_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&cpu0_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&cpu0_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&cpu0_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&cpu0_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&cpu0_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpu1-silver-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 2>;
-		tracks-low;
-		trips {
-			cpu1_trip: cpu1-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&cpu1_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&cpu1_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&cpu1_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&cpu1_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&cpu1_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&cpu1_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&cpu1_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&cpu1_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpu2-silver-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 3>;
-		tracks-low;
-		trips {
-			cpu2_trip: cpu2-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&cpu2_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&cpu2_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&cpu2_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&cpu2_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&cpu2_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&cpu2_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&cpu2_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&cpu2_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpu3-silver-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 4>;
-		tracks-low;
-		trips {
-			cpu3_trip: cpu3-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&cpu3_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&cpu3_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&cpu3_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&cpu3_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&cpu3_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&cpu3_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&cpu3_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&cpu3_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpuss-0-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 5>;
-		tracks-low;
-		trips {
-			l3_0_trip: l3-0-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&l3_0_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&l3_0_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&l3_0_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&l3_0_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&l3_0_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&l3_0_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&l3_0_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&l3_0_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpuss-1-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 6>;
-		tracks-low;
-		trips {
-			l3_1_trip: l3-1-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&l3_1_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&l3_1_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&l3_1_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&l3_1_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&l3_1_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&l3_1_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&l3_1_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&l3_1_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpu4-silver-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 7>;
-		tracks-low;
-		trips {
-			cpu4_trip: cpu4-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&cpu4_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&cpu4_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&cpu4_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&cpu4_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&cpu4_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&cpu4_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&cpu4_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&cpu4_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpu5-silver-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 8>;
-		tracks-low;
-		trips {
-			cpu5_trip: cpu5-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&cpu5_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&cpu5_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&cpu5_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&cpu5_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&cpu5_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&cpu5_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&cpu5_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&cpu5_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpu0-gold-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 9>;
-		tracks-low;
-		trips {
-			cpug0_trip: cpug0-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&cpug0_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&cpug0_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&cpug0_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&cpug0_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&cpug0_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&cpug0_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&cpug0_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&cpug0_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	cpu1-gold-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 10>;
-		tracks-low;
-		trips {
-			cpug1_trip: cpug1-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&cpug1_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&cpug1_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&cpug1_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&cpug1_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&cpug1_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&cpug1_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&cpug1_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&cpug1_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	gpu0-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 11>;
-		tracks-low;
-		trips {
-			gpu0_trip_l: gpu0-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&gpu0_trip_l>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&gpu0_trip_l>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&gpu0_trip_l>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&gpu0_trip_l>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&gpu0_trip_l>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&gpu0_trip_l>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&gpu0_trip_l>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&gpu0_trip_l>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	gpu1-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens0 12>;
-		tracks-low;
-		trips {
-			gpu1_trip_l: gpu1-trip_l {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&gpu1_trip_l>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&gpu1_trip_l>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&gpu1_trip_l>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&gpu1_trip_l>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&gpu1_trip_l>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&gpu1_trip_l>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&gpu1_trip_l>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&gpu1_trip_l>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
 	aoss1-lowf {
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
@@ -1121,7 +521,7 @@
 			};
 			gpu_vdd_cdev {
 				trip = <&aoss1_trip>;
-				cooling-device = <&msm_gpu 4 4>;
+				cooling-device = <&msm_gpu 0 0>;
 			};
 			cx_vdd_cdev {
 				trip = <&aoss1_trip>;
@@ -1146,356 +546,6 @@
 		};
 	};
 
-	mdm-dsp-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens1 1>;
-		tracks-low;
-		trips {
-			dsp_trip: dsp-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&dsp_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&dsp_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&dsp_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&dsp_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&dsp_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&dsp_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&dsp_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&dsp_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	ddr-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens1 2>;
-		tracks-low;
-		trips {
-			ddr_trip: ddr-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&ddr_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&ddr_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&ddr_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&ddr_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&ddr_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&ddr_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&ddr_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&ddr_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	wlan-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens1 3>;
-		tracks-low;
-		trips {
-			wlan_trip: wlan-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&wlan_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&wlan_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&wlan_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&wlan_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&wlan_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&wlan_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&wlan_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&wlan_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	compute-hvx-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens1 4>;
-		tracks-low;
-		trips {
-			hvx_trip: hvx-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&hvx_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&hvx_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&hvx_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&hvx_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&hvx_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&hvx_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&hvx_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&hvx_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	camera-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens1 5>;
-		tracks-low;
-		trips {
-			camera_trip: camera-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&camera_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&camera_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&camera_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&camera_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&camera_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&camera_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&camera_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&camera_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	mmss-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens1 6>;
-		tracks-low;
-		trips {
-			mmss_trip: mmss-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&mmss_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&mmss_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&mmss_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&mmss_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&mmss_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&mmss_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&mmss_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&mmss_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
-	mdm-core-lowf {
-		polling-delay-passive = <0>;
-		polling-delay = <0>;
-		thermal-governor = "low_limits_floor";
-		thermal-sensors = <&tsens1 7>;
-		tracks-low;
-		trips {
-			mdm_trip: mdm-trip {
-				temperature = <5000>;
-				hysteresis = <5000>;
-				type = "passive";
-			};
-		};
-		cooling-maps {
-			cpu0_vdd_cdev {
-				trip = <&mdm_trip>;
-				cooling-device = <&CPU0 2 2>;
-			};
-			cpu6_vdd_cdev {
-				trip = <&mdm_trip>;
-				cooling-device = <&CPU6 (THERMAL_MAX_LIMIT-8)
-							(THERMAL_MAX_LIMIT-8)>;
-			};
-			gpu_vdd_cdev {
-				trip = <&mdm_trip>;
-				cooling-device = <&msm_gpu 4 4>;
-			};
-			cx_vdd_cdev {
-				trip = <&mdm_trip>;
-				cooling-device = <&cx_cdev 0 0>;
-			};
-			mx_vdd_cdev {
-				trip = <&mdm_trip>;
-				cooling-device = <&mx_cdev 0 0>;
-			};
-			modem_vdd_cdev {
-				trip = <&mdm_trip>;
-				cooling-device = <&modem_vdd 0 0>;
-			};
-			adsp_vdd_cdev {
-				trip = <&mdm_trip>;
-				cooling-device = <&adsp_vdd 0 0>;
-			};
-			cdsp_vdd_cdev {
-				trip = <&mdm_trip>;
-				cooling-device = <&cdsp_vdd 0 0>;
-			};
-		};
-	};
-
 	lmh-dcvs-01 {
 		polling-delay-passive = <0>;
 		polling-delay = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
index a3a48af..d708a12 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
@@ -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
@@ -91,16 +91,26 @@
 		pinctrl-0 = <&camera_dvdd_en_default>;
 		vin-supply = <&pm8998_s3>;
 	};
+
+	camera_vana_ldo: gpio-regulator@4 {
+		compatible = "regulator-fixed";
+		reg = <0x04 0x00>;
+		regulator-name = "camera_vana_ldo";
+		regulator-min-microvolt = <2850000>;
+		regulator-max-microvolt = <2850000>;
+		regulator-enable-ramp-delay = <233>;
+		enable-active-high;
+		gpio = <&tlmm 8 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&cam_sensor_rear_vana>;
+		vin-supply = <&pmi8998_bob>;
+	};
 };
 
 &cam_cci {
 	qcom,cam-res-mgr {
 		compatible = "qcom,cam-res-mgr";
 		status = "ok";
-		shared-gpios = <8>;
-		pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend";
-		pinctrl-0 = <&cam_res_mgr_active>;
-		pinctrl-1 = <&cam_res_mgr_suspend>;
 	};
 
 	actuator_rear: qcom,actuator@0 {
@@ -339,13 +349,13 @@
 		eeprom-src = <&eeprom_rear_aux>;
 		cam_vdig-supply = <&camera_ldo>;
 		cam_vio-supply = <&pm8998_lvs1>;
-		cam_vana-supply = <&pmi8998_bob>;
+		cam_vana-supply = <&camera_vana_ldo>;
 		cam_clk-supply = <&titan_top_gdsc>;
 		regulator-names = "cam_vdig", "cam_vio", "cam_vana",
 			"cam_clk";
 		rgltr-cntrl-support;
-		rgltr-min-voltage = <1050000 0 3312000 0>;
-		rgltr-max-voltage = <1050000 0 3600000 0>;
+		rgltr-min-voltage = <1050000 0 2850000 0>;
+		rgltr-max-voltage = <1050000 0 2850000 0>;
 		rgltr-load-current = <105000 0 80000 0>;
 		gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
@@ -354,15 +364,12 @@
 		pinctrl-1 = <&cam_sensor_mclk2_suspend
 				&cam_sensor_rear2_suspend>;
 		gpios = <&tlmm 15 0>,
-			<&tlmm 9 0>,
-			<&tlmm 8 0>;
+			<&tlmm 9 0>;
 		gpio-reset = <1>;
-		gpio-vana = <2>;
-		gpio-req-tbl-num = <0 1 2>;
-		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
 		gpio-req-tbl-label = "CAMIF_MCLK1",
-					"CAM_RESET1",
-					"CAM_VANA1";
+					"CAM_RESET1";
 		sensor-mode = <0>;
 		cci-master = <1>;
 		status = "ok";
@@ -384,14 +391,14 @@
 		actuator-src = <&actuator_front>;
 		led-flash-src = <&led_flash_front>;
 		cam_vio-supply = <&pm8998_lvs1>;
-		cam_vana-supply = <&pmi8998_bob>;
+		cam_vana-supply = <&camera_vana_ldo>;
 		cam_vdig-supply = <&camera_ldo>;
 		cam_clk-supply = <&titan_top_gdsc>;
 		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
 			"cam_clk";
 		rgltr-cntrl-support;
-		rgltr-min-voltage = <0 3312000 1050000 0>;
-		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-min-voltage = <0 2850000 1050000 0>;
+		rgltr-max-voltage = <0 2850000 1050000 0>;
 		rgltr-load-current = <0 80000 105000 0>;
 		gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
@@ -400,15 +407,12 @@
 		pinctrl-1 = <&cam_sensor_mclk1_suspend
 				 &cam_sensor_front_suspend>;
 		gpios = <&tlmm 14 0>,
-			<&tlmm 28 0>,
-			<&tlmm 8 0>;
+			<&tlmm 28 0>;
 		gpio-reset = <1>;
-		gpio-vana = <2>;
-		gpio-req-tbl-num = <0 1 2>;
-		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
 		gpio-req-tbl-label = "CAMIF_MCLK2",
-					"CAM_RESET2",
-					"CAM_VANA1";
+					"CAM_RESET2";
 		sensor-mode = <0>;
 		cci-master = <1>;
 		status = "ok";
@@ -428,14 +432,14 @@
 		sensor-position-yaw = <0>;
 		led-flash-src = <&led_flash_iris>;
 		cam_vio-supply = <&pm8998_lvs1>;
-		cam_vana-supply = <&pmi8998_bob>;
+		cam_vana-supply = <&camera_vana_ldo>;
 		cam_vdig-supply = <&camera_ldo>;
 		cam_clk-supply = <&titan_top_gdsc>;
 		regulator-names = "cam_vio", "cam_vana", "cam_vdig",
 			"cam_clk";
 		rgltr-cntrl-support;
-		rgltr-min-voltage = <0 3312000 1050000 0>;
-		rgltr-max-voltage = <0 3600000 1050000 0>;
+		rgltr-min-voltage = <0 2850000 1050000 0>;
+		rgltr-max-voltage = <0 2850000 1050000 0>;
 		rgltr-load-current = <0 80000 105000 0>;
 		gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
@@ -444,15 +448,12 @@
 		pinctrl-1 = <&cam_sensor_mclk3_suspend
 				 &cam_sensor_iris_suspend>;
 		gpios = <&tlmm 16 0>,
-			<&tlmm 9 0>,
-			<&tlmm 8 0>;
+			<&tlmm 9 0>;
 		gpio-reset = <1>;
-		gpio-vana = <2>;
-		gpio-req-tbl-num = <0 1 2>;
-		gpio-req-tbl-flags = <1 0 0>;
+		gpio-req-tbl-num = <0 1>;
+		gpio-req-tbl-flags = <1 0>;
 		gpio-req-tbl-label = "CAMIF_MCLK3",
-					"CAM_RESET3",
-					"CAM_VANA1";
+					"CAM_RESET3";
 		sensor-mode = <0>;
 		cci-master = <1>;
 		status = "ok";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index a7cf880..90e1f24 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.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
@@ -166,6 +166,15 @@
 			};
 
 			port@1 {
+				reg = <6>;
+				funnel_swao_in_sensor_etm0: endpoint {
+					slave-mode;
+					remote-endpoint=
+						<&sensor_etm0_out_funnel_swao>;
+				};
+			};
+
+			port@2 {
 				reg = <7>;
 				funnel_swao_in_tpda_swao: endpoint {
 					slave-mode;
@@ -2049,6 +2058,20 @@
 		};
 	};
 
+	sensor_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+
+		coresight-name = "coresight-sensor-etm0";
+		qcom,inst-id = <8>;
+
+		port {
+			sensor_etm0_out_funnel_swao: endpoint {
+				remote-endpoint =
+					<&funnel_swao_in_sensor_etm0>;
+			};
+		};
+	};
+
 	modem_etm0 {
 		compatible = "qcom,coresight-remote-etm";
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index c16e1d8..1c7269a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.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
@@ -328,6 +328,13 @@
 		/delete-property/ pinctrl-0;
 	};
 
+	gpio-regulator@4 {
+		/delete-property/ gpio;
+		/delete-property/ vin-supply;
+		/delete-property/ pinctrl-names;
+		/delete-property/ pinctrl-0;
+	};
+
 	/delete-node/ qcom,spmi-debug@6b22000;
 
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 191e76d..11c48bd 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.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
@@ -3099,6 +3099,20 @@
 			};
 		};
 
+		cam_sensor_rear_vana: cam_sensor_rear_vana {
+			/*  AVDD LDO */
+			mux {
+				pins = "gpio8";
+				function = "gpio";
+			};
+
+			config {
+				pins = "gpio8";
+				bias-disable; /* No PULL */
+				drive-strength = <2>; /* 2 MA */
+			};
+		};
+
 		cam_res_mgr_active: cam_res_mgr_active {
 			/* AVDD_LDO*/
 			mux {
@@ -3200,6 +3214,77 @@
 				bias-pull-down;		/* pull down */
 			};
 		};
+
+		ap2mdm {
+			ap2mdm_active: ap2mdm_active {
+				mux {
+					/* ap2mdm-status
+					 * ap2mdm-errfatal
+					 * ap2mdm-vddmin
+					 */
+					pins = "gpio21", "gpio23";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio21", "gpio23";
+					drive-strength = <16>;
+					bias-disable;
+				};
+			};
+			ap2mdm_sleep: ap2mdm_sleep {
+				mux {
+					/* ap2mdm-status
+					 * ap2mdm-errfatal
+					 * ap2mdm-vddmin
+					 */
+					pins = "gpio21", "gpio23";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio21", "gpio23";
+					drive-strength = <8>;
+					bias-disable;
+				};
+
+			};
+		};
+
+		mdm2ap {
+			mdm2ap_active: mdm2ap_active {
+				mux {
+				/* mdm2ap-status
+				 * mdm2ap-errfatal
+				 * mdm2ap-vddmin
+				 */
+					pins = "gpio22", "gpio20";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio22", "gpio20";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+			mdm2ap_sleep: mdm2ap_sleep {
+				mux {
+					/* mdm2ap-status
+					 * mdm2ap-errfatal
+					 * mdm2ap-vddmin
+					 */
+					pins = "gpio22", "gpio20";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio22", "gpio20";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+		};
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index d2ee9eb..05d77d3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -156,6 +156,7 @@
 	qcom,cam_smmu {
 		compatible = "qcom,msm-cam-smmu";
 		status = "ok";
+		non-fatal-fault-disabled;
 
 		msm_cam_smmu_lrme {
 			compatible = "qcom,msm-cam-smmu-cb";
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 4a732e3..9b242a0 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -339,6 +339,7 @@
 CONFIG_REGULATOR_MEM_ACC=y
 CONFIG_REGULATOR_MSM_GFX_LDO=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_REGULATOR_RPM_SMD=y
 CONFIG_REGULATOR_SPM=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index ec7aad8..f6e49cd 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -349,6 +349,7 @@
 CONFIG_REGULATOR_MEM_ACC=y
 CONFIG_REGULATOR_MSM_GFX_LDO=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
 CONFIG_REGULATOR_QPNP=y
 CONFIG_REGULATOR_RPM_SMD=y
 CONFIG_REGULATOR_SPM=y
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h
index b64410c..96c11e7 100644
--- a/arch/arm64/include/asm/system_misc.h
+++ b/arch/arm64/include/asm/system_misc.h
@@ -46,6 +46,8 @@
 extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
 extern char* (*arch_read_hardware_id)(void);
 
+const char * __init arch_read_machine_name(void);
+
 #define show_unhandled_signals_ratelimited()				\
 ({									\
 	static DEFINE_RATELIMIT_STATE(_rs,				\
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index a58fb92..f58539f 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -65,6 +65,7 @@
 #include <asm/efi.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/mmu_context.h>
+#include <asm/system_misc.h>
 
 phys_addr_t __fdt_pointer __initdata;
 
@@ -186,6 +187,11 @@
 		pr_warn("Large number of MPIDR hash buckets detected\n");
 }
 
+const char * __init __weak arch_read_machine_name(void)
+{
+	return of_flat_dt_get_machine_name();
+}
+
 static void __init setup_machine_fdt(phys_addr_t dt_phys)
 {
 	void *dt_virt = fixmap_remap_fdt(dt_phys);
@@ -201,7 +207,7 @@
 			cpu_relax();
 	}
 
-	machine_name = of_flat_dt_get_machine_name();
+	machine_name = arch_read_machine_name();
 	if (machine_name) {
 		dump_stack_set_arch_desc("%s (DT)", machine_name);
 		pr_info("Machine: %s\n", machine_name);
diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c
index af8bf00..f3c587d 100644
--- a/drivers/char/diag/diagfwd_socket.c
+++ b/drivers/char/diag/diagfwd_socket.c
@@ -513,8 +513,10 @@
 		info->hdl->sk->sk_user_data = NULL;
 		info->hdl->sk->sk_data_ready = NULL;
 		write_unlock_bh(&info->hdl->sk->sk_callback_lock);
+		mutex_lock(&info->socket_info_mutex);
 		sock_release(info->hdl);
 		info->hdl = NULL;
+		mutex_unlock(&info->socket_info_mutex);
 		wake_up_interruptible(&info->read_wait_q);
 	}
 	DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", info->name);
@@ -820,6 +822,8 @@
 		break;
 	}
 
+	if (info->port_type == PORT_TYPE_CLIENT)
+		mutex_init(&info->socket_info_mutex);
 	info->svc_id = DIAG_SVC_ID;
 	info->ins_id = ins_base + ins_offset;
 	info->inited = 1;
@@ -1031,6 +1035,8 @@
 	diagfwd_deregister(info->peripheral, info->type, (void *)info);
 	info->fwd_ctxt = NULL;
 	info->hdl = NULL;
+	if (info->port_type == PORT_TYPE_CLIENT)
+		mutex_destroy(&info->socket_info_mutex);
 	if (info->wq)
 		destroy_workqueue(info->wq);
 
@@ -1119,13 +1125,28 @@
 		read_msg.msg_name = &src_addr;
 		read_msg.msg_namelen = sizeof(src_addr);
 
+		if (info->port_type != PORT_TYPE_SERVER) {
+			mutex_lock(&info->socket_info_mutex);
+			if (!info->hdl) {
+				DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+				"%s closing read thread\n",
+					info->name);
+				mutex_unlock(&info->socket_info_mutex);
+				goto fail;
+			}
+		}
 		pkt_len = kernel_recvmsg(info->hdl, &read_msg, &iov, 1, 0,
 					 MSG_PEEK);
-		if (pkt_len <= 0)
+		if (pkt_len <= 0) {
+			if (info->port_type != PORT_TYPE_SERVER)
+				mutex_unlock(&info->socket_info_mutex);
 			break;
+		}
 
 		if (pkt_len > bytes_remaining) {
 			buf_full = 1;
+			if (info->port_type != PORT_TYPE_SERVER)
+				mutex_unlock(&info->socket_info_mutex);
 			break;
 		}
 
@@ -1135,6 +1156,8 @@
 
 		read_len = kernel_recvmsg(info->hdl, &read_msg, &iov, 1,
 					  pkt_len, 0);
+		if (info->port_type != PORT_TYPE_SERVER)
+			mutex_unlock(&info->socket_info_mutex);
 		if (read_len <= 0)
 			goto fail;
 
@@ -1211,7 +1234,16 @@
 	write_msg.msg_name = &info->remote_addr;
 	write_msg.msg_namelen = sizeof(info->remote_addr);
 	write_msg.msg_flags |= MSG_DONTWAIT;
+	if (info->port_type != PORT_TYPE_SERVER) {
+		mutex_lock(&info->socket_info_mutex);
+		if (!info->hdl) {
+			mutex_unlock(&info->socket_info_mutex);
+			return -ENODEV;
+		}
+	}
 	write_len = kernel_sendmsg(info->hdl, &write_msg, &iov, 1, len);
+	if (info->port_type != PORT_TYPE_SERVER)
+		mutex_unlock(&info->socket_info_mutex);
 	if (write_len < 0) {
 		err = write_len;
 		/*
diff --git a/drivers/char/diag/diagfwd_socket.h b/drivers/char/diag/diagfwd_socket.h
index a9487b1..c42be06 100644
--- a/drivers/char/diag/diagfwd_socket.h
+++ b/drivers/char/diag/diagfwd_socket.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -65,6 +65,7 @@
 	struct work_struct read_work;
 	struct diagfwd_info *fwd_ctxt;
 	wait_queue_head_t read_wait_q;
+	struct mutex socket_info_mutex;
 };
 
 union cntl_port_msg {
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 0ea769c..19fe223 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2006-2007 Adam Belay <abelay@novell.com>
  * Copyright (C) 2009 Intel Corporation
  *
@@ -619,7 +619,7 @@
 
 	next_event_us = (uint32_t)(ktime_to_us(get_next_event_time(dev->cpu)));
 
-	if (is_cpu_biased(dev->cpu))
+	if (is_cpu_biased(dev->cpu) && (!cpu_isolated(dev->cpu)))
 		goto done_select;
 
 	for (i = 0; i < cpu->nlevels; i++) {
diff --git a/drivers/esoc/Kconfig b/drivers/esoc/Kconfig
index 3c65f69..4613150 100644
--- a/drivers/esoc/Kconfig
+++ b/drivers/esoc/Kconfig
@@ -38,7 +38,7 @@
 	  allow logging of different esoc driver traces.
 
 config ESOC_MDM_4x
-	bool "Add support for external mdm9x25/mdm9x35/mdm9x55"
+	bool "Add support for external modem"
 	help
 	  In some Qualcomm Technologies, Inc. boards, an external modem such as
 	  mdm9x25 or mdm9x35 is connected to a primary msm. The primary soc can
@@ -49,7 +49,7 @@
 	tristate "Command engine for 4x series external modems"
 	help
 	  Provides a command engine to control the behavior of an external modem
-	  such as mdm9x25/mdm9x35/mdm9x55/QSC. Allows the primary soc to put the
+	  such as mdm9x25/mdm9x35/mdm9x55/sdxpoorwills/QSC. Allows the primary soc to put the
 	  external modem in a specific mode. Also listens for events on the
 	  external modem.
 
diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c
index 677e21d..bbec9d3 100644
--- a/drivers/esoc/esoc-mdm-4x.c
+++ b/drivers/esoc/esoc-mdm-4x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -794,6 +794,28 @@
 	mdm->gpio_state_running = NULL;
 	return retval;
 }
+
+static void mdm_release_ipc_gpio(struct mdm_ctrl *mdm)
+{
+	int i;
+
+	if (!mdm)
+		return;
+
+	for (i = 0; i < NUM_GPIOS; ++i)
+		if (gpio_is_valid(MDM_GPIO(mdm, i)))
+			gpio_free(MDM_GPIO(mdm, i));
+}
+
+static void mdm_free_irq(struct mdm_ctrl *mdm)
+{
+	if (!mdm)
+		return;
+
+	free_irq(mdm->errfatal_irq, mdm);
+	free_irq(mdm->status_irq, mdm);
+}
+
 static int mdm9x25_setup_hw(struct mdm_ctrl *mdm,
 					const struct mdm_ops *ops,
 					struct platform_device *pdev)
@@ -1028,6 +1050,108 @@
 	return 0;
 }
 
+static int sdxpoorwills_setup_hw(struct mdm_ctrl *mdm,
+				const struct mdm_ops *ops,
+				struct platform_device *pdev)
+{
+	int ret;
+	struct device_node *node;
+	struct esoc_clink *esoc;
+	const struct esoc_clink_ops *clink_ops = ops->clink_ops;
+	const struct mdm_pon_ops *pon_ops = ops->pon_ops;
+
+	mdm->dev = &pdev->dev;
+	mdm->pon_ops = pon_ops;
+	node = pdev->dev.of_node;
+
+	esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
+	if (IS_ERR_OR_NULL(esoc)) {
+		dev_err(mdm->dev, "cannot allocate esoc device\n");
+		return PTR_ERR(esoc);
+	}
+
+	esoc->pdev = pdev;
+
+	mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
+	if (!mdm->mdm_queue) {
+		dev_err(mdm->dev, "could not create mdm_queue\n");
+		return -ENOMEM;
+	}
+
+	mdm->irq_mask = 0;
+	mdm->ready = false;
+
+	ret = mdm_dt_parse_gpios(mdm);
+	if (ret) {
+		dev_err(mdm->dev, "Failed to parse DT gpios\n");
+		goto err_destroy_wrkq;
+	}
+
+	ret = mdm_pon_dt_init(mdm);
+	if (ret) {
+		dev_err(mdm->dev, "Failed to parse PON DT gpio\n");
+		goto err_destroy_wrkq;
+	}
+
+	ret = mdm_pinctrl_init(mdm);
+	if (ret) {
+		dev_err(mdm->dev, "Failed to init pinctrl\n");
+		goto err_destroy_wrkq;
+	}
+
+	ret = mdm_pon_setup(mdm);
+	if (ret) {
+		dev_err(mdm->dev, "Failed to setup PON\n");
+		goto err_destroy_wrkq;
+	}
+
+	ret = mdm_configure_ipc(mdm, pdev);
+	if (ret) {
+		dev_err(mdm->dev, "Failed to configure the ipc\n");
+		goto err_release_ipc;
+	}
+
+	esoc->name = SDXPOORWILLS_LABEL;
+	esoc->link_name = SDXPOORWILLS_PCIE;
+
+	ret = of_property_read_string(node, "qcom,mdm-link-info",
+					&esoc->link_info);
+	if (ret)
+		dev_info(mdm->dev, "esoc link info missing\n");
+
+	esoc->clink_ops = clink_ops;
+	esoc->parent = mdm->dev;
+	esoc->owner = THIS_MODULE;
+	esoc->np = pdev->dev.of_node;
+	set_esoc_clink_data(esoc, mdm);
+
+	ret = esoc_clink_register(esoc);
+	if (ret) {
+		dev_err(mdm->dev, "esoc registration failed\n");
+		goto err_free_irq;
+	}
+	dev_dbg(mdm->dev, "esoc registration done\n");
+
+	init_completion(&mdm->debug_done);
+	INIT_WORK(&mdm->mdm_status_work, mdm_status_fn);
+	INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason);
+	INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check);
+	mdm->get_restart_reason = false;
+	mdm->debug_fail = false;
+	mdm->esoc = esoc;
+	mdm->init = 0;
+
+	return 0;
+
+err_free_irq:
+	mdm_free_irq(mdm);
+err_release_ipc:
+	mdm_release_ipc_gpio(mdm);
+err_destroy_wrkq:
+	destroy_workqueue(mdm->mdm_queue);
+	return ret;
+}
+
 static struct esoc_clink_ops mdm_cops = {
 	.cmd_exe = mdm_cmd_exe,
 	.get_status = mdm_get_status,
@@ -1053,6 +1177,12 @@
 	.pon_ops = &mdm9x55_pon_ops,
 };
 
+static struct mdm_ops sdxpoorwills_ops = {
+	.clink_ops = &mdm_cops,
+	.config_hw = sdxpoorwills_setup_hw,
+	.pon_ops = &sdxpoorwills_pon_ops,
+};
+
 static const struct of_device_id mdm_dt_match[] = {
 	{ .compatible = "qcom,ext-mdm9x25",
 		.data = &mdm9x25_ops, },
@@ -1060,6 +1190,8 @@
 		.data = &mdm9x35_ops, },
 	{ .compatible = "qcom,ext-mdm9x55",
 		.data = &mdm9x55_ops, },
+	{ .compatible = "qcom,ext-sdxpoorwills",
+		.data = &sdxpoorwills_ops, },
 	{},
 };
 MODULE_DEVICE_TABLE(of, mdm_dt_match);
diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c
index 77ae84b..4291bbc 100644
--- a/drivers/esoc/esoc-mdm-drv.c
+++ b/drivers/esoc/esoc-mdm-drv.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
@@ -309,6 +309,10 @@
 		.name = "MDM9x55",
 		.data = NULL,
 	},
+	{
+		.name = "SDXPOORWILLS",
+		.data = NULL,
+	},
 };
 
 static struct esoc_drv esoc_ssr_drv = {
diff --git a/drivers/esoc/esoc-mdm-pon.c b/drivers/esoc/esoc-mdm-pon.c
index 0e85776..9624275 100644
--- a/drivers/esoc/esoc-mdm-pon.c
+++ b/drivers/esoc/esoc-mdm-pon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -60,6 +60,24 @@
 	return 0;
 }
 
+/* This function can be called from atomic context. */
+static int sdxpoorwills_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
+{
+	int soft_reset_direction_assert = mdm->soft_reset_inverted;
+
+	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+			soft_reset_direction_assert);
+	/*
+	 * Allow PS hold assert to be detected
+	 */
+	if (!atomic)
+		usleep_range(80000, 180000);
+	else
+		mdelay(100);
+	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+			!soft_reset_direction_assert);
+	return 0;
+}
 
 static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
 {
@@ -99,6 +117,7 @@
 {
 	struct device *dev = mdm->dev;
 	int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
+
 	/* Assert the soft reset line whether mdm2ap_status went low or not */
 	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
 					soft_reset_direction);
@@ -135,6 +154,27 @@
 	return 0;
 }
 
+static int sdxpoorwills_power_down(struct mdm_ctrl *mdm)
+{
+	struct device *dev = mdm->dev;
+	int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
+
+	/* Assert the soft reset line whether mdm2ap_status went low or not */
+	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+					soft_reset_direction);
+	dev_info(dev, "Doing a hard reset\n");
+	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+						soft_reset_direction);
+	/*
+	 * Currently, there is a debounce timer on the charm PMIC. It is
+	 * necessary to hold the PMIC RESET low for 325ms
+	 * for the reset to fully take place. Sleep here to ensure the
+	 * reset has occurred before the function exits.
+	 */
+	mdelay(325);
+	return 0;
+}
+
 static void mdm4x_cold_reset(struct mdm_ctrl *mdm)
 {
 	if (!gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET)))
@@ -158,6 +198,16 @@
 			!mdm->soft_reset_inverted);
 }
 
+static void sdxpoorwills_cold_reset(struct mdm_ctrl *mdm)
+{
+	dev_info(mdm->dev, "Triggering mdm cold reset");
+	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+			!!mdm->soft_reset_inverted);
+	mdelay(600);
+	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
+			!mdm->soft_reset_inverted);
+}
+
 static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm)
 {
 	int val;
@@ -215,3 +265,12 @@
 	.dt_init = mdm4x_pon_dt_init,
 	.setup = mdm4x_pon_setup,
 };
+
+struct mdm_pon_ops sdxpoorwills_pon_ops = {
+	.pon = mdm4x_do_first_power_on,
+	.soft_reset = sdxpoorwills_toggle_soft_reset,
+	.poff_force = sdxpoorwills_power_down,
+	.cold_reset = sdxpoorwills_cold_reset,
+	.dt_init = mdm4x_pon_dt_init,
+	.setup = mdm4x_pon_setup,
+};
diff --git a/drivers/esoc/esoc-mdm.h b/drivers/esoc/esoc-mdm.h
index 621d913..baf4e0b 100644
--- a/drivers/esoc/esoc-mdm.h
+++ b/drivers/esoc/esoc-mdm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 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
@@ -35,6 +35,8 @@
 #define MDM9x35_HSIC			"HSIC"
 #define MDM9x55_LABEL			"MDM9x55"
 #define MDM9x55_PCIE			"PCIe"
+#define SDXPOORWILLS_LABEL		"SDXPOORWILLS"
+#define SDXPOORWILLS_PCIE		"PCIe"
 #define MDM2AP_STATUS_TIMEOUT_MS	120000L
 #define MDM_MODEM_TIMEOUT		3000
 #define DEF_RAMDUMP_TIMEOUT		120000
@@ -150,4 +152,5 @@
 extern struct mdm_pon_ops mdm9x25_pon_ops;
 extern struct mdm_pon_ops mdm9x35_pon_ops;
 extern struct mdm_pon_ops mdm9x55_pon_ops;
+extern struct mdm_pon_ops sdxpoorwills_pon_ops;
 #endif
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index 26c1c39..da37baf 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -335,8 +335,8 @@
 		.num_protected_regs = 0x20,
 		.busy_mask = 0xFFFFFFFE,
 		.gpmufw_name = "a630_gmu.bin",
-		.gpmu_major = 0x0,
-		.gpmu_minor = 0x005,
+		.gpmu_major = 0x1,
+		.gpmu_minor = 0x003,
 		.gpmu_tsens = 0x000C000D,
 		.max_power = 5448,
 	},
@@ -357,7 +357,7 @@
 		.busy_mask = 0xFFFFFFFE,
 		.gpmufw_name = "a630_gmu.bin",
 		.gpmu_major = 0x1,
-		.gpmu_minor = 0x001,
+		.gpmu_minor = 0x003,
 		.gpmu_tsens = 0x000C000D,
 		.max_power = 5448,
 	},
@@ -368,7 +368,7 @@
 		.minor = 5,
 		.patchid = ANY_ID,
 		.features = ADRENO_64BIT | ADRENO_RPMH |
-			ADRENO_GPMU | ADRENO_CONTENT_PROTECTION,
+			ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC,
 		.sqefw_name = "a630_sqe.fw",
 		.zap_name = "a615_zap",
 		.gpudev = &adreno_a6xx_gpudev,
@@ -377,6 +377,6 @@
 		.busy_mask = 0xFFFFFFFE,
 		.gpmufw_name = "a630_gmu.bin",
 		.gpmu_major = 0x1,
-		.gpmu_minor = 0x001,
+		.gpmu_minor = 0x003,
 	},
 };
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 7d11007..e0b725f 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1517,7 +1517,7 @@
 		adreno_writereg64(adreno_dev,
 			ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
 			ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
-			KGSL_IOMMU_SECURE_BASE);
+			KGSL_IOMMU_SECURE_BASE(&device->mmu));
 		adreno_writereg(adreno_dev,
 			ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE,
 			KGSL_IOMMU_SECURE_SIZE);
@@ -1848,11 +1848,6 @@
 
 error_mmu_off:
 	kgsl_mmu_stop(&device->mmu);
-	if (gpudev->oob_clear &&
-			ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
-		gpudev->oob_clear(adreno_dev,
-				OOB_BOOT_SLUMBER_CLEAR_MASK);
-	}
 
 error_pwr_off:
 	/* set the state back to original state */
@@ -2106,7 +2101,7 @@
 				 * anything to mmap().
 				 */
 				shadowprop.gpuaddr =
-					(unsigned int) device->memstore.gpuaddr;
+					(unsigned long)device->memstore.gpuaddr;
 				shadowprop.size = device->memstore.size;
 				/* GSL needs this to be set, even if it
 				 * appears to be meaningless
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index baf366e..a615dca 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -2424,8 +2424,8 @@
 	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL,
 		A5XX_CP_RB_CNTL_DEFAULT);
 
-	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
-			rb->buffer_desc.gpuaddr);
+	adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_BASE,
+			ADRENO_REG_CP_RB_BASE_HI, rb->buffer_desc.gpuaddr);
 
 	ret = a5xx_microcode_load(adreno_dev);
 	if (ret)
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 6275c19..c01640c 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -63,6 +63,9 @@
 	{ adreno_is_a615, a615_gbif },
 };
 
+
+static unsigned long a6xx_oob_state_bitmask;
+
 struct kgsl_hwcg_reg {
 	unsigned int off;
 	unsigned int val;
@@ -324,7 +327,6 @@
 static struct reg_list_pair a6xx_ifpc_pwrup_reglist[] = {
 	{ A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x0 },
 	{ A6XX_CP_CHICKEN_DBG, 0x0 },
-	{ A6XX_CP_ADDR_MODE_CNTL, 0x0 },
 	{ A6XX_CP_DBG_ECO_CNTL, 0x0 },
 	{ A6XX_CP_PROTECT_CNTL, 0x0 },
 	{ A6XX_CP_PROTECT_REG, 0x0 },
@@ -1083,8 +1085,8 @@
 	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL,
 					A6XX_CP_RB_CNTL_DEFAULT);
 
-	adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE,
-			rb->buffer_desc.gpuaddr);
+	adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_BASE,
+			ADRENO_REG_CP_RB_BASE_HI, rb->buffer_desc.gpuaddr);
 
 	ret = a6xx_microcode_load(adreno_dev);
 	if (ret)
@@ -1451,7 +1453,7 @@
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	int ret = 0;
 
-	if (!kgsl_gmu_isenabled(device))
+	if (!kgsl_gmu_isenabled(device) || !clear_mask)
 		return 0;
 
 	kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, set_mask);
@@ -1467,6 +1469,8 @@
 
 	kgsl_gmu_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, clear_mask);
 
+	set_bit((fls(clear_mask) - 1), &a6xx_oob_state_bitmask);
+
 	trace_kgsl_gmu_oob_set(set_mask);
 	return ret;
 }
@@ -1481,10 +1485,15 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 
-	if (!kgsl_gmu_isenabled(device))
+	if (!kgsl_gmu_isenabled(device) || !clear_mask)
 		return;
 
-	kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, clear_mask);
+	if (test_and_clear_bit(fls(clear_mask) - 1,
+				&a6xx_oob_state_bitmask))
+		kgsl_gmu_regwrite(device,
+			A6XX_GMU_HOST2GMU_INTR_SET,
+			clear_mask);
+
 	trace_kgsl_gmu_oob_clear(clear_mask);
 }
 
@@ -2308,6 +2317,9 @@
 		ret = a6xx_gmu_suspend(device);
 		break;
 	case GMU_FW_STOP:
+		if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
+			a6xx_oob_clear(adreno_dev,
+					OOB_BOOT_SLUMBER_CLEAR_MASK);
 		ret = a6xx_rpmh_power_off_gpu(device);
 		break;
 	case GMU_DCVS_NOHFI:
diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c
index 2d2c9e5..022aa9f 100644
--- a/drivers/gpu/msm/adreno_sysfs.c
+++ b/drivers/gpu/msm/adreno_sysfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -31,7 +31,7 @@
 
 #define _ADRENO_SYSFS_ATTR_RO(_name, __show) \
 struct adreno_sysfs_attribute adreno_attr_##_name = { \
-	.attr = __ATTR(_name, 0644, __show, NULL), \
+	.attr = __ATTR(_name, 0444, __show, NULL), \
 	.show = _ ## _name ## _show, \
 	.store = NULL, \
 }
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 0338c5fd..4b11bbe 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -35,12 +35,14 @@
 #include "kgsl_pwrctrl.h"
 
 #define CP_APERTURE_REG	0
+#define CP_SMMU_APERTURE_ID 0x1B
 
 #define _IOMMU_PRIV(_mmu) (&((_mmu)->priv.iommu))
 
-#define ADDR_IN_GLOBAL(_a) \
-	(((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE) && \
-	 ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE + KGSL_IOMMU_GLOBAL_MEM_SIZE)))
+#define ADDR_IN_GLOBAL(_mmu, _a) \
+	(((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu)) && \
+	 ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) + \
+	 KGSL_IOMMU_GLOBAL_MEM_SIZE)))
 
 /*
  * Flag to set SMMU memory attributes required to
@@ -184,7 +186,8 @@
 	if (entry != NULL) {
 		struct kgsl_pagetable *pagetable = device->mmu.securepagetable;
 		entry->pagetable = pagetable;
-		entry->gpuaddr = KGSL_IOMMU_SECURE_BASE + secure_global_size;
+		entry->gpuaddr = KGSL_IOMMU_SECURE_BASE(&device->mmu) +
+			secure_global_size;
 
 		ret = kgsl_mmu_map(pagetable, entry);
 		if (ret == 0)
@@ -223,7 +226,8 @@
 			KGSL_IOMMU_GLOBAL_MEM_SIZE))
 		return;
 
-	memdesc->gpuaddr = KGSL_IOMMU_GLOBAL_MEM_BASE + global_pt_alloc;
+	memdesc->gpuaddr = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu) + global_pt_alloc;
+
 	memdesc->priv |= KGSL_MEMDESC_GLOBAL;
 	global_pt_alloc += memdesc->size;
 
@@ -641,7 +645,7 @@
 	/* Set the maximum possible size as an initial value */
 	nextentry->gpuaddr = (uint64_t) -1;
 
-	if (ADDR_IN_GLOBAL(faultaddr)) {
+	if (ADDR_IN_GLOBAL(mmu, faultaddr)) {
 		_get_global_entries(faultaddr, preventry, nextentry);
 	} else if (context) {
 		private = context->proc_priv;
@@ -1030,13 +1034,13 @@
 		struct kgsl_iommu_pt *pt)
 {
 	if (mmu->secured && pagetable->name == KGSL_MMU_SECURE_PT) {
-		pt->compat_va_start = KGSL_IOMMU_SECURE_BASE;
-		pt->compat_va_end = KGSL_IOMMU_SECURE_END;
-		pt->va_start = KGSL_IOMMU_SECURE_BASE;
-		pt->va_end = KGSL_IOMMU_SECURE_END;
+		pt->compat_va_start = KGSL_IOMMU_SECURE_BASE(mmu);
+		pt->compat_va_end = KGSL_IOMMU_SECURE_END(mmu);
+		pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu);
+		pt->va_end = KGSL_IOMMU_SECURE_END(mmu);
 	} else {
 		pt->compat_va_start = KGSL_IOMMU_SVM_BASE32;
-		pt->compat_va_end = KGSL_IOMMU_SVM_END32;
+		pt->compat_va_end = KGSL_IOMMU_SECURE_BASE(mmu);
 		pt->va_start = KGSL_IOMMU_VA_BASE64;
 		pt->va_end = KGSL_IOMMU_VA_END64;
 	}
@@ -1045,7 +1049,7 @@
 		pagetable->name != KGSL_MMU_SECURE_PT) {
 		if ((BITS_PER_LONG == 32) || is_compat_task()) {
 			pt->svm_start = KGSL_IOMMU_SVM_BASE32;
-			pt->svm_end = KGSL_IOMMU_SVM_END32;
+			pt->svm_end = KGSL_IOMMU_SECURE_BASE(mmu);
 		} else {
 			pt->svm_start = KGSL_IOMMU_SVM_BASE64;
 			pt->svm_end = KGSL_IOMMU_SVM_END64;
@@ -1059,19 +1063,19 @@
 {
 	if (mmu->secured) {
 		if (pagetable->name == KGSL_MMU_SECURE_PT) {
-			pt->compat_va_start = KGSL_IOMMU_SECURE_BASE;
-			pt->compat_va_end = KGSL_IOMMU_SECURE_END;
-			pt->va_start = KGSL_IOMMU_SECURE_BASE;
-			pt->va_end = KGSL_IOMMU_SECURE_END;
+			pt->compat_va_start = KGSL_IOMMU_SECURE_BASE(mmu);
+			pt->compat_va_end = KGSL_IOMMU_SECURE_END(mmu);
+			pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu);
+			pt->va_end = KGSL_IOMMU_SECURE_END(mmu);
 		} else {
 			pt->va_start = KGSL_IOMMU_SVM_BASE32;
-			pt->va_end = KGSL_IOMMU_SECURE_BASE;
+			pt->va_end = KGSL_IOMMU_SECURE_BASE(mmu);
 			pt->compat_va_start = pt->va_start;
 			pt->compat_va_end = pt->va_end;
 		}
 	} else {
 		pt->va_start = KGSL_IOMMU_SVM_BASE32;
-		pt->va_end = KGSL_IOMMU_GLOBAL_MEM_BASE;
+		pt->va_end = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu);
 		pt->compat_va_start = pt->va_start;
 		pt->compat_va_end = pt->va_end;
 	}
@@ -1166,7 +1170,7 @@
 	desc.args[3] = 0xFFFFFFFF;
 	desc.arginfo = SCM_ARGS(4);
 
-	return scm_call2(SCM_SIP_FNID(SCM_SVC_MP, 0x1B), &desc);
+	return scm_call2(SCM_SIP_FNID(SCM_SVC_MP, CP_SMMU_APERTURE_ID), &desc);
 }
 
 static int _init_global_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt)
@@ -1209,7 +1213,8 @@
 		goto done;
 	}
 
-	if (!MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE)) {
+	if (!MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE) &&
+		scm_is_call_available(SCM_SVC_MP, CP_SMMU_APERTURE_ID)) {
 		ret = program_smmu_aperture(cb_num, CP_APERTURE_REG);
 		if (ret) {
 			pr_err("SMMU aperture programming call failed with error %d\n",
@@ -2381,7 +2386,8 @@
 	struct rb_node *node;
 
 	/* Make sure the requested address doesn't fall in the global range */
-	if (ADDR_IN_GLOBAL(gpuaddr) || ADDR_IN_GLOBAL(gpuaddr + size))
+	if (ADDR_IN_GLOBAL(pagetable->mmu, gpuaddr) ||
+			ADDR_IN_GLOBAL(pagetable->mmu, gpuaddr + size))
 		return -ENOMEM;
 
 	spin_lock(&pagetable->lock);
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index acf8ae4..462ff3b 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -24,12 +24,17 @@
  * are mapped into all pagetables.
  */
 #define KGSL_IOMMU_GLOBAL_MEM_SIZE	(20 * SZ_1M)
-#define KGSL_IOMMU_GLOBAL_MEM_BASE	0xf8000000
+#define KGSL_IOMMU_GLOBAL_MEM_BASE32	0xf8000000
+#define KGSL_IOMMU_GLOBAL_MEM_BASE64	TASK_SIZE_32
+
+#define KGSL_IOMMU_GLOBAL_MEM_BASE(__mmu)	\
+	(MMU_FEATURE(__mmu, KGSL_MMU_64BIT) ? \
+		KGSL_IOMMU_GLOBAL_MEM_BASE64 : KGSL_IOMMU_GLOBAL_MEM_BASE32)
 
 #define KGSL_IOMMU_SECURE_SIZE SZ_256M
-#define KGSL_IOMMU_SECURE_END KGSL_IOMMU_GLOBAL_MEM_BASE
-#define KGSL_IOMMU_SECURE_BASE	\
-	(KGSL_IOMMU_GLOBAL_MEM_BASE - KGSL_IOMMU_SECURE_SIZE)
+#define KGSL_IOMMU_SECURE_END(_mmu) KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu)
+#define KGSL_IOMMU_SECURE_BASE(_mmu)	\
+	(KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) - KGSL_IOMMU_SECURE_SIZE)
 
 #define KGSL_IOMMU_SVM_BASE32		0x300000
 #define KGSL_IOMMU_SVM_END32		(0xC0000000 - SZ_16M)
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 16a3e7d..f3e16b3 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -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
@@ -39,9 +39,22 @@
 #define PMI_CHG_SCALE_2		391750000000
 #define QPNP_VADC_HC_VREF_CODE		0x4000
 #define QPNP_VADC_HC_VDD_REFERENCE_MV	1875
+#define CHRG_SCALE_1 -250
+#define CHRG_SCALE_2 377500000
+#define DIE_SCALE_1 500
+#define DIE_SCALE_2 -273150000
+
 /* Clamp negative ADC code to 0 */
 #define QPNP_VADC_HC_MAX_CODE		0x7FFF
 
+/*Invalid current reading*/
+#define QPNP_IADC_INV		0x8000
+
+#define IADC_SCALE_1 0xffff
+#define IADC_SCALE_2 152593
+
+#define USBIN_I_SCALE 25
+
 /*
  * Units for temperature below (on x axis) is in 0.1DegC as
  * required by the battery driver. Note the resolution used
@@ -590,6 +603,80 @@
 	{30,	125}
 };
 
+/* Voltage to temperature */
+static const struct qpnp_vadc_map_pt adcmap_batt_therm[] = {
+	{1770,	-400},
+	{1757,	-380},
+	{1743,	-360},
+	{1727,	-340},
+	{1710,	-320},
+	{1691,	-300},
+	{1671,	-280},
+	{1650,	-260},
+	{1627,	-240},
+	{1602,	-220},
+	{1576,	-200},
+	{1548,	-180},
+	{1519,	-160},
+	{1488,	-140},
+	{1456,	-120},
+	{1423,	-100},
+	{1388,	-80},
+	{1353,	-60},
+	{1316,	-40},
+	{1278,	-20},
+	{1240,	0},
+	{1201,	20},
+	{1162,	40},
+	{1122,	60},
+	{1082,	80},
+	{1042,	100},
+	{1003,	120},
+	{964,	140},
+	{925,	160},
+	{887,	180},
+	{849,	200},
+	{812,	220},
+	{777,	240},
+	{742,	260},
+	{708,	280},
+	{675,	300},
+	{643,	320},
+	{613,	340},
+	{583,	360},
+	{555,	380},
+	{528,	400},
+	{502,	420},
+	{477,	440},
+	{453,	460},
+	{430,	480},
+	{409,	500},
+	{388,	520},
+	{369,	540},
+	{350,	560},
+	{333,	580},
+	{316,	600},
+	{300,	620},
+	{285,	640},
+	{271,	660},
+	{257,	680},
+	{245,	700},
+	{233,	720},
+	{221,	740},
+	{210,	760},
+	{200,	780},
+	{190,	800},
+	{181,	820},
+	{173,	840},
+	{164,	860},
+	{157,	880},
+	{149,	900},
+	{142,	920},
+	{136,	940},
+	{129,	960},
+	{124,	980}
+};
+
 /*
  * Voltage to temperature table for 100k pull up for NTCG104EF104 with
  * 1.875V reference.
@@ -899,6 +986,36 @@
 }
 EXPORT_SYMBOL(qpnp_adc_tdkntcg_therm);
 
+int32_t qpnp_adc_batt_therm(struct qpnp_vadc_chip *chip,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t batt_thm_voltage = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	if (adc_properties->adc_hc) {
+		/* (code * vref_vadc (1.875V) * 1000) / (scale_code * 1000) */
+		if (adc_code > QPNP_VADC_HC_MAX_CODE)
+			adc_code = 0;
+		batt_thm_voltage = (int64_t) adc_code;
+		batt_thm_voltage *= (adc_properties->adc_vdd_reference
+							* 1000);
+		batt_thm_voltage = div64_s64(batt_thm_voltage,
+				adc_properties->full_scale_code * 1000);
+		qpnp_adc_map_voltage_temp(adcmap_batt_therm,
+			ARRAY_SIZE(adcmap_batt_therm),
+			batt_thm_voltage, &adc_chan_result->physical);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_batt_therm);
+
 int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *chip,
 		int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -920,6 +1037,70 @@
 }
 EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
 
+int32_t qpnp_adc_scale_chrg_temp(struct qpnp_vadc_chip *vadc,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int rc = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	rc = qpnp_adc_scale_default(vadc, adc_code, adc_properties,
+			chan_properties, adc_chan_result);
+	if (rc < 0)
+		return rc;
+
+	pr_debug("raw_code:%x, v_adc:%lld\n", adc_code,
+						adc_chan_result->physical);
+	adc_chan_result->physical = (int64_t) ((CHRG_SCALE_1) *
+					(adc_chan_result->physical));
+	adc_chan_result->physical = (int64_t) (adc_chan_result->physical +
+							CHRG_SCALE_2);
+	adc_chan_result->physical = (int64_t) adc_chan_result->physical;
+	adc_chan_result->physical = div64_s64(adc_chan_result->physical,
+								1000000);
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_scale_chrg_temp);
+
+int32_t qpnp_adc_scale_die_temp(struct qpnp_vadc_chip *vadc,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int rc = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	rc = qpnp_adc_scale_default(vadc, adc_code, adc_properties,
+			chan_properties, adc_chan_result);
+	if (rc < 0)
+		return rc;
+
+	pr_debug("raw_code:%x, v_adc:%lld\n", adc_code,
+						adc_chan_result->physical);
+	adc_chan_result->physical = (int64_t) ((DIE_SCALE_1) *
+					(adc_chan_result->physical));
+	adc_chan_result->physical = (int64_t) (adc_chan_result->physical +
+							DIE_SCALE_2);
+	adc_chan_result->physical = (int64_t) adc_chan_result->physical;
+	adc_chan_result->physical = div64_s64(adc_chan_result->physical,
+								1000000);
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_scale_die_temp);
+
 int32_t qpnp_adc_scale_qrd_batt_therm(struct qpnp_vadc_chip *chip,
 		int32_t adc_code,
 		const struct qpnp_adc_properties *adc_properties,
@@ -1279,6 +1460,73 @@
 }
 EXPORT_SYMBOL(qpnp_adc_scale_default);
 
+int32_t qpnp_iadc_scale_default(struct qpnp_vadc_chip *vadc,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int64_t scale_current = 0;
+
+	if (!chan_properties || !chan_properties->offset_gain_numerator ||
+		!chan_properties->offset_gain_denominator || !adc_properties
+		|| !adc_chan_result)
+		return -EINVAL;
+
+	if (adc_properties->adc_hc) {
+
+		if (adc_code == QPNP_IADC_INV)
+			return -EINVAL;
+
+		scale_current = (int64_t) adc_code;
+
+		if (adc_code > QPNP_IADC_INV) {
+		scale_current = ((~scale_current) & IADC_SCALE_1);
+		scale_current++;
+		scale_current = -scale_current;
+		}
+	}
+
+	scale_current *= IADC_SCALE_2;
+	scale_current = div64_s64(scale_current,
+				1000);
+	scale_current *= chan_properties->offset_gain_denominator;
+	scale_current = div64_s64(scale_current,
+				chan_properties->offset_gain_numerator);
+	adc_chan_result->measurement = scale_current;
+	/*
+	 * Note: adc_chan_result->measurement is in uA.
+	 */
+	adc_chan_result->physical = adc_chan_result->measurement;
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_iadc_scale_default);
+
+int qpnp_adc_scale_usbin_curr(struct qpnp_vadc_chip *vadc,
+		int32_t adc_code,
+		const struct qpnp_adc_properties *adc_properties,
+		const struct qpnp_vadc_chan_properties *chan_properties,
+		struct qpnp_vadc_result *adc_chan_result)
+{
+	int rc = 0;
+
+	rc = qpnp_adc_scale_default(vadc, adc_code, adc_properties,
+			chan_properties, adc_chan_result);
+	if (rc < 0)
+		return rc;
+
+	pr_debug("raw_code:%x, v_adc:%lld\n", adc_code,
+						adc_chan_result->physical);
+	adc_chan_result->physical = (int64_t) ((USBIN_I_SCALE) *
+					adc_chan_result->physical);
+	adc_chan_result->physical = div64_s64(adc_chan_result->physical,
+								10);
+
+	return 0;
+}
+EXPORT_SYMBOL(qpnp_adc_scale_usbin_curr);
+
 int32_t qpnp_adc_usb_scaler(struct qpnp_vadc_chip *chip,
 		struct qpnp_adc_tm_btm_param *param,
 		uint32_t *low_threshold, uint32_t *high_threshold)
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 6fde46e..8b44c0f 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -219,6 +219,11 @@
 	[SCALE_NCP_03WF683_THERM] = {qpnp_adc_scale_therm_ncp03},
 	[SCALE_QRD_SKUT1_BATT_THERM] = {qpnp_adc_scale_qrd_skut1_batt_therm},
 	[SCALE_PMI_CHG_TEMP] = {qpnp_adc_scale_pmi_chg_temp},
+	[SCALE_BATT_THERM_TEMP] = {qpnp_adc_batt_therm},
+	[SCALE_CHRG_TEMP] = {qpnp_adc_scale_chrg_temp},
+	[SCALE_DIE_TEMP] = {qpnp_adc_scale_die_temp},
+	[SCALE_I_DEFAULT] = {qpnp_iadc_scale_default},
+	[SCALE_USBIN_I] = {qpnp_adc_scale_usbin_curr},
 };
 
 static struct qpnp_vadc_rscale_fn adc_vadc_rscale_fn[] = {
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 145af90..0bc9439 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -3600,6 +3600,11 @@
 		return -EPERM;
 
 	mutex_lock(&drvdata->lock);
+	if (!drvdata->enable) {
+		mutex_unlock(&drvdata->lock);
+		return -EPERM;
+	}
+
 	TPDM_UNLOCK(drvdata);
 	val = tpdm_readl(drvdata, TPDM_CMB_READVAL);
 	TPDM_LOCK(drvdata);
@@ -3622,6 +3627,11 @@
 		return -EPERM;
 
 	mutex_lock(&drvdata->lock);
+	if (!drvdata->enable) {
+		mutex_unlock(&drvdata->lock);
+		return -EPERM;
+	}
+
 	TPDM_UNLOCK(drvdata);
 	val = tpdm_readl(drvdata, TPDM_CMB_READCTL);
 	TPDM_LOCK(drvdata);
@@ -3650,6 +3660,11 @@
 		return -EPERM;
 
 	mutex_lock(&drvdata->lock);
+	if (!drvdata->enable) {
+		mutex_unlock(&drvdata->lock);
+		return -EPERM;
+	}
+
 	TPDM_UNLOCK(drvdata);
 	tpdm_writel(drvdata, val, TPDM_CMB_READCTL);
 	TPDM_LOCK(drvdata);
@@ -3748,6 +3763,11 @@
 		return -EPERM;
 
 	mutex_lock(&drvdata->lock);
+	if (!drvdata->enable) {
+		mutex_unlock(&drvdata->lock);
+		return -EPERM;
+	}
+
 	TPDM_UNLOCK(drvdata);
 	tpdm_writel(drvdata, val, TPDM_CMB_MARKR);
 	TPDM_LOCK(drvdata);
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
index 9ce3026..3d808fb 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c
@@ -4720,6 +4720,8 @@
 	struct synaptics_rmi4_exp_fhandler *exp_fhandler;
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
 	unsigned char device_ctrl;
+	const struct synaptics_dsx_board_data *bdata =
+			rmi4_data->hw_if->board_data;
 
 	if (rmi4_data->stay_awake)
 		return 0;
@@ -4762,9 +4764,10 @@
 		synaptics_rmi4_free_fingers(rmi4_data);
 	}
 
-	if (rmi4_data->ts_pinctrl)
-		pinctrl_select_state(rmi4_data->ts_pinctrl,
-					rmi4_data->pinctrl_state_suspend);
+	if (bdata->reset_gpio >= 0) {
+		gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
+		msleep(bdata->reset_active_ms);
+	}
 
 	synaptics_rmi4_enable_reg(rmi4_data, false);
 
@@ -4790,6 +4793,8 @@
 	struct synaptics_rmi4_exp_fhandler *exp_fhandler;
 	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
 
+	const struct synaptics_dsx_board_data *bdata =
+			rmi4_data->hw_if->board_data;
 	if (rmi4_data->stay_awake)
 		return 0;
 
@@ -4801,9 +4806,13 @@
 
 	synaptics_rmi4_enable_reg(rmi4_data, true);
 
-	if (rmi4_data->ts_pinctrl)
-		pinctrl_select_state(rmi4_data->ts_pinctrl,
-			rmi4_data->pinctrl_state_active);
+	if (bdata->reset_gpio >= 0) {
+		gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
+		msleep(bdata->reset_active_ms);
+		gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state);
+		msleep(bdata->reset_delay_ms);
+	}
+
 
 	rmi4_data->current_page = MASK_8BIT;
 
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index 29e09c9..d2e576d 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -210,6 +210,7 @@
 #define QPNP_WLED_SEC_ACCESS_REG(b)    (b + 0xD0)
 #define QPNP_WLED_SEC_UNLOCK           0xA5
 
+#define NUM_DDIC_CODES			256
 #define QPNP_WLED_MAX_STRINGS		4
 #define QPNP_PM660_WLED_MAX_STRINGS	3
 #define WLED_MAX_LEVEL_4095		4095
@@ -315,6 +316,7 @@
  *  @ cdev - led class device
  *  @ pdev - platform device
  *  @ work - worker for led operation
+ *  @ wq - workqueue for setting brightness level
  *  @ lock - mutex lock for exclusive access
  *  @ fdbk_op - output feedback mode
  *  @ dim_mode - dimming mode
@@ -340,6 +342,10 @@
  *  @ ramp_ms - delay between ramp steps in ms
  *  @ ramp_step - ramp step size
  *  @ cons_sync_write_delay_us - delay between two consecutive writes to SYNC
+ *  @ auto_calibration_ovp_count - OVP fault irq count to run auto calibration
+ *  @ max_strings - Number of strings supported in WLED peripheral
+ *  @ prev_level - Previous brightness level
+ *  @ brt_map_table - Brightness map table
  *  @ strings - supported list of strings
  *  @ num_strings - number of strings
  *  @ loop_auto_gm_thresh - the clamping level for auto gm
@@ -353,6 +359,13 @@
  *  @ en_cabc - enable or disable cabc
  *  @ disp_type_amoled - type of display: LCD/AMOLED
  *  @ en_ext_pfet_sc_pro - enable sc protection on external pfet
+ *  @ prev_state - previous state of WLED
+ *  @ stepper_en - Flag to enable stepper algorithm
+ *  @ ovp_irq_disabled - OVP interrupt disable status
+ *  @ auto_calib_enabled - Flag to enable auto calibration feature
+ *  @ auto_calib_done - Flag to indicate auto calibration is done
+ *  @ module_dis_perm - Flat to keep module permanently disabled
+ *  @ start_ovp_fault_time - Time when the OVP fault first occurred
  */
 struct qpnp_wled {
 	struct led_classdev	cdev;
@@ -360,6 +373,7 @@
 	struct regmap		*regmap;
 	struct pmic_revid_data	*pmic_rev_id;
 	struct work_struct	work;
+	struct workqueue_struct *wq;
 	struct mutex		lock;
 	struct mutex		bus_lock;
 	enum qpnp_wled_fdbk_op	fdbk_op;
@@ -388,6 +402,8 @@
 	u16			cons_sync_write_delay_us;
 	u16			auto_calibration_ovp_count;
 	u16			max_strings;
+	u16			prev_level;
+	u16			*brt_map_table;
 	u8			strings[QPNP_WLED_MAX_STRINGS];
 	u8			num_strings;
 	u8			loop_auto_gm_thresh;
@@ -402,6 +418,7 @@
 	bool			disp_type_amoled;
 	bool			en_ext_pfet_sc_pro;
 	bool			prev_state;
+	bool			stepper_en;
 	bool			ovp_irq_disabled;
 	bool			auto_calib_enabled;
 	bool			auto_calib_done;
@@ -409,6 +426,21 @@
 	ktime_t			start_ovp_fault_time;
 };
 
+static int qpnp_wled_step_delay_us = 52000;
+module_param_named(
+	total_step_delay_us, qpnp_wled_step_delay_us, int, 0600
+);
+
+static int qpnp_wled_step_size_threshold = 3;
+module_param_named(
+	step_size_threshold, qpnp_wled_step_size_threshold, int, 0600
+);
+
+static int qpnp_wled_step_delay_gain = 2;
+module_param_named(
+	step_delay_gain, qpnp_wled_step_delay_gain, int, 0600
+);
+
 /* helper to read a pmic register */
 static int qpnp_wled_read_reg(struct qpnp_wled *wled, u16 addr, u8 *data)
 {
@@ -570,6 +602,93 @@
 		return rc;
 	}
 
+	pr_debug("level:%d\n", level);
+	return 0;
+}
+
+static int qpnp_wled_set_map_level(struct qpnp_wled *wled, int level)
+{
+	int rc, i;
+
+	if (level < wled->prev_level) {
+		for (i = wled->prev_level; i >= level; i--) {
+			rc = qpnp_wled_set_level(wled, wled->brt_map_table[i]);
+			if (rc < 0) {
+				pr_err("set brightness level failed, rc:%d\n",
+					rc);
+				return rc;
+			}
+		}
+	} else if (level > wled->prev_level) {
+		for (i = wled->prev_level; i <= level; i++) {
+			rc = qpnp_wled_set_level(wled, wled->brt_map_table[i]);
+			if (rc < 0) {
+				pr_err("set brightness level failed, rc:%d\n",
+					rc);
+				return rc;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int qpnp_wled_set_step_level(struct qpnp_wled *wled, int new_level)
+{
+	int rc, i, num_steps, delay_us;
+	u16 level, start_level, end_level, step_size;
+	bool level_inc = false;
+
+	level = wled->prev_level;
+	start_level = wled->brt_map_table[level];
+	end_level = wled->brt_map_table[new_level];
+	level_inc = (new_level > level);
+
+	num_steps = abs(start_level - end_level);
+	if (!num_steps)
+		return 0;
+
+	delay_us = qpnp_wled_step_delay_us / num_steps;
+	pr_debug("level goes from [%d %d] num_steps: %d, delay: %d\n",
+		start_level, end_level, num_steps, delay_us);
+
+	if (delay_us < 500) {
+		step_size = 1000 / delay_us;
+		num_steps = num_steps / step_size;
+		delay_us = 1000;
+	} else {
+		if (num_steps < qpnp_wled_step_size_threshold)
+			delay_us *= qpnp_wled_step_delay_gain;
+
+		step_size = 1;
+	}
+
+	i = start_level;
+	while (num_steps--) {
+		if (level_inc)
+			i += step_size;
+		else
+			i -= step_size;
+
+		rc = qpnp_wled_set_level(wled, i);
+		if (rc < 0)
+			return rc;
+
+		if (delay_us > 0) {
+			if (delay_us < 20000)
+				usleep_range(delay_us, delay_us + 1);
+			else
+				msleep(delay_us / USEC_PER_MSEC);
+		}
+	}
+
+	if (i != end_level) {
+		i = end_level;
+		rc = qpnp_wled_set_level(wled, i);
+		if (rc < 0)
+			return rc;
+	}
+
 	return 0;
 }
 
@@ -942,15 +1061,33 @@
 static void qpnp_wled_work(struct work_struct *work)
 {
 	struct qpnp_wled *wled;
-	int level, rc;
+	int level, level_255, rc;
 
 	wled = container_of(work, struct qpnp_wled, work);
 
+	mutex_lock(&wled->lock);
 	level = wled->cdev.brightness;
 
-	mutex_lock(&wled->lock);
+	if (wled->brt_map_table) {
+		/*
+		 * Change the 12 bit level to 8 bit level and use the mapped
+		 * values for 12 bit level from brightness map table.
+		 */
+		level_255 = DIV_ROUND_CLOSEST(level, 16);
+		if (level_255 > 255)
+			level_255 = 255;
 
-	if (level) {
+		pr_debug("level: %d level_255: %d\n", level, level_255);
+		if (wled->stepper_en)
+			rc = qpnp_wled_set_step_level(wled, level_255);
+		else
+			rc = qpnp_wled_set_map_level(wled, level_255);
+		if (rc) {
+			dev_err(&wled->pdev->dev, "wled set level failed\n");
+			goto unlock_mutex;
+		}
+		wled->prev_level = level_255;
+	} else if (level) {
 		rc = qpnp_wled_set_level(wled, level);
 		if (rc) {
 			dev_err(&wled->pdev->dev, "wled set level failed\n");
@@ -1009,7 +1146,7 @@
 		level = wled->cdev.max_brightness;
 
 	wled->cdev.brightness = level;
-	schedule_work(&wled->work);
+	queue_work(wled->wq, &wled->work);
 }
 
 static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr)
@@ -2115,7 +2252,7 @@
 	struct property *prop;
 	const char *temp_str;
 	u32 temp_val;
-	int rc, i;
+	int rc, i, size;
 	u8 *strings;
 
 	wled->cdev.name = "wled";
@@ -2134,6 +2271,45 @@
 		return rc;
 	}
 
+	if (of_find_property(pdev->dev.of_node, "qcom,wled-brightness-map",
+			NULL)) {
+		size = of_property_count_elems_of_size(pdev->dev.of_node,
+				"qcom,wled-brightness-map", sizeof(u16));
+		if (size != NUM_DDIC_CODES) {
+			pr_err("Invalid WLED brightness map size:%d\n", size);
+			return rc;
+		}
+
+		wled->brt_map_table = devm_kcalloc(&pdev->dev, NUM_DDIC_CODES,
+						sizeof(u16), GFP_KERNEL);
+		if (!wled->brt_map_table)
+			return -ENOMEM;
+
+		rc = of_property_read_u16_array(pdev->dev.of_node,
+			"qcom,wled-brightness-map", wled->brt_map_table,
+			NUM_DDIC_CODES);
+		if (rc < 0) {
+			pr_err("Error in reading WLED brightness map, rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		for (i = 0; i < NUM_DDIC_CODES; i++) {
+			if (wled->brt_map_table[i] > WLED_MAX_LEVEL_4095) {
+				pr_err("WLED brightness map not in range\n");
+				return -EDOM;
+			}
+
+			if ((i > 1) && wled->brt_map_table[i]
+						< wled->brt_map_table[i - 1]) {
+				pr_err("WLED brightness map not in ascending order?\n");
+				return -EDOM;
+			}
+		}
+	}
+
+	wled->stepper_en = of_property_read_bool(pdev->dev.of_node,
+				"qcom,wled-stepper-en");
 	wled->disp_type_amoled = of_property_read_bool(pdev->dev.of_node,
 				"qcom,disp-type-amoled");
 	if (wled->disp_type_amoled) {
@@ -2470,6 +2646,7 @@
 	}
 
 	wled->pmic_rev_id = get_revid_data(revid_node);
+	of_node_put(revid_node);
 	if (IS_ERR_OR_NULL(wled->pmic_rev_id)) {
 		pr_err("Unable to get pmic_revid rc=%ld\n",
 			PTR_ERR(wled->pmic_rev_id));
@@ -2484,6 +2661,12 @@
 	pr_debug("PMIC subtype %d Digital major %d\n",
 		wled->pmic_rev_id->pmic_subtype, wled->pmic_rev_id->rev4);
 
+	wled->wq = alloc_ordered_workqueue("qpnp_wled_wq", WQ_HIGHPRI);
+	if (!wled->wq) {
+		pr_err("Unable to alloc workqueue for WLED\n");
+		return -ENOMEM;
+	}
+
 	prop = of_get_address_by_name(pdev->dev.of_node, QPNP_WLED_SINK_BASE,
 			NULL, NULL);
 	if (!prop) {
@@ -2549,6 +2732,7 @@
 	led_classdev_unregister(&wled->cdev);
 wled_register_fail:
 	cancel_work_sync(&wled->work);
+	destroy_workqueue(wled->wq);
 	mutex_destroy(&wled->lock);
 	return rc;
 }
@@ -2564,6 +2748,7 @@
 
 	led_classdev_unregister(&wled->cdev);
 	cancel_work_sync(&wled->work);
+	destroy_workqueue(wled->wq);
 	mutex_destroy(&wled->lock);
 
 	return 0;
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
index 00ead5d..3ebe7a1 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
@@ -662,9 +662,10 @@
 
 	opp = dev_pm_opp_find_freq_ceil(dev, &corner_freq);
 	if (IS_ERR(opp)) {
-		CAM_ERR(CAM_CPAS, "Error on OPP freq :%ld, %pK",
+		CAM_DBG(CAM_CPAS, "OPP Ceil not available for freq :%ld, %pK",
 			corner_freq, opp);
-		return -EINVAL;
+		*req_level = CAM_TURBO_VOTE;
+		return 0;
 	}
 
 	corner = dev_pm_opp_get_voltage(opp);
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
index 6909972..73663b3 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -74,6 +74,7 @@
 #define ICP_SHARED_MEM_IN_BYTES                 (1024 * 1024)
 #define ICP_UNCACHED_HEAP_SIZE_IN_BYTES         (2 * 1024 * 1024)
 #define ICP_HFI_MAX_PKT_SIZE_IN_WORDS           25600
+#define ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS      256
 
 #define ICP_HFI_QTBL_HOSTID1                    0x01000000
 #define ICP_HFI_QTBL_STATUS_ENABLED             0x00000001
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
index 837efec..0412b8a 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_session_defs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -197,6 +197,7 @@
 } __packed;
 
 #define MAX_NUM_OF_IMAGE_PLANES	2
+#define MAX_HFR_GROUP          16
 
 enum hfi_ipe_io_images {
 	IPE_INPUT_IMAGE_FULL,
@@ -220,6 +221,40 @@
 	IPE_IO_IMAGES_MAX
 };
 
+enum bps_io_images {
+	BPS_INPUT_IMAGE,
+	BPS_OUTPUT_IMAGE_FULL,
+	BPS_OUTPUT_IMAGE_DS4,
+	BPS_OUTPUT_IMAGE_DS16,
+	BPS_OUTPUT_IMAGE_DS64,
+	BPS_OUTPUT_IMAGE_STATS_BG,
+	BPS_OUTPUT_IMAGE_STATS_BHIST,
+	BPS_OUTPUT_IMAGE_REG1,
+	BPS_OUTPUT_IMAGE_REG2,
+	BPS_OUTPUT_IMAGE_FIRST = BPS_OUTPUT_IMAGE_FULL,
+	BPS_OUTPUT_IMAGE_LAST = BPS_OUTPUT_IMAGE_REG2,
+	BPS_IO_IMAGES_MAX
+};
+
+struct frame_buffer {
+	uint32_t buffer_ptr[MAX_NUM_OF_IMAGE_PLANES];
+	uint32_t meta_buffer_ptr[MAX_NUM_OF_IMAGE_PLANES];
+} __packed;
+
+struct bps_frame_process_data {
+	struct frame_buffer buffers[BPS_IO_IMAGES_MAX];
+	uint32_t max_num_cores;
+	uint32_t target_time;
+	uint32_t ubwc_stats_buffer_addr;
+	uint32_t ubwc_stats_buffer_size;
+	uint32_t cdm_buffer_addr;
+	uint32_t cdm_buffer_size;
+	uint32_t iq_settings_addr;
+	uint32_t strip_lib_out_addr;
+	uint32_t cdm_prog_addr;
+	uint32_t request_id;
+};
+
 enum hfi_ipe_image_format {
 	IMAGE_FORMAT_INVALID,
 	IMAGE_FORMAT_MIPI_8,
@@ -361,6 +396,49 @@
 	struct buffer_layout meta_buf_layout[MAX_NUM_OF_IMAGE_PLANES];
 } __packed;
 
+struct ica_stab_coeff {
+	uint32_t coeffs[8];
+} __packed;
+
+struct ica_stab_params {
+	uint32_t mode;
+	struct ica_stab_coeff transforms[3];
+} __packed;
+
+struct frame_set {
+	struct frame_buffer buffers[IPE_IO_IMAGES_MAX];
+	struct ica_stab_params ica_params;
+	uint32_t cdm_ica1_addr;
+	uint32_t cdm_ica2_addr;
+} __packed;
+
+struct ipe_frame_process_data {
+	uint32_t strip_lib_out_addr;
+	uint32_t iq_settings_addr;
+	uint32_t scratch_buffer_addr;
+	uint32_t scratch_buffer_size;
+	uint32_t ubwc_stats_buffer_addr;
+	uint32_t ubwc_stats_buffer_size;
+	uint32_t cdm_buffer_addr;
+	uint32_t cdm_buffer_size;
+	uint32_t max_num_cores;
+	uint32_t target_time;
+	uint32_t cdm_prog_base;
+	uint32_t cdm_pre_ltm;
+	uint32_t cdm_post_ltm;
+	uint32_t cdm_anr_full_pass;
+	uint32_t cdm_anr_ds4;
+	uint32_t cdm_anr_ds16;
+	uint32_t cdm_anr_ds64;
+	uint32_t cdm_tf_full_pass;
+	uint32_t cdm_tf_ds4;
+	uint32_t cdm_tf_ds16;
+	uint32_t cdm_tf_ds64;
+	uint32_t request_id;
+	uint32_t frames_in_batch;
+	struct frame_set framesets[MAX_HFR_GROUP];
+} __packed;
+
 /**
  * struct hfi_cmd_ipe_config
  * @images: images descreptions
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index eca16d6..77f33d0 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -138,6 +138,7 @@
 	struct hfi_q_hdr *q;
 	uint32_t new_read_idx, size_in_words, word_diff, temp;
 	uint32_t *read_q, *read_ptr, *write_ptr;
+	uint32_t size_upper_bound = 0;
 	int rc = 0;
 
 	if (!pmsg) {
@@ -175,10 +176,13 @@
 		goto err;
 	}
 
-	if (q_id == Q_MSG)
+	if (q_id == Q_MSG) {
 		read_q = (uint32_t *)g_hfi->map.msg_q.kva;
-	else
+		size_upper_bound = ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS;
+	} else {
 		read_q = (uint32_t *)g_hfi->map.dbg_q.kva;
+		size_upper_bound = ICP_HFI_MAX_PKT_SIZE_IN_WORDS;
+	}
 
 	read_ptr = (uint32_t *)(read_q + q->qhdr_read_idx);
 	write_ptr = (uint32_t *)(read_q + q->qhdr_write_idx);
@@ -196,7 +200,7 @@
 	}
 
 	if ((size_in_words == 0) ||
-		(size_in_words > ICP_HFI_MAX_PKT_SIZE_IN_WORDS)) {
+		(size_in_words > size_upper_bound)) {
 		CAM_ERR(CAM_HFI, "invalid HFI message packet size - 0x%08x",
 			size_in_words << BYTE_WORD_SHIFT);
 		q->qhdr_read_idx = q->qhdr_write_idx;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
index 25e1ce7..5bd7f1c 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
@@ -276,22 +276,29 @@
 		rc = cam_bps_handle_resume(bps_dev);
 		break;
 	case CAM_ICP_BPS_CMD_UPDATE_CLK: {
-		uint32_t clk_rate = *(uint32_t *)cmd_args;
+		struct cam_a5_clk_update_cmd *clk_upd_cmd =
+			(struct cam_a5_clk_update_cmd *)cmd_args;
+		uint32_t clk_rate = clk_upd_cmd->curr_clk_rate;
 
 		CAM_DBG(CAM_ICP, "bps_src_clk rate = %d", (int)clk_rate);
+
 		if (!core_info->clk_enable) {
-			cam_bps_handle_pc(bps_dev);
-			cam_cpas_reg_write(core_info->cpas_handle,
-				CAM_CPAS_REG_CPASTOP,
-				hw_info->pwr_ctrl, true, 0x0);
+			if (clk_upd_cmd->ipe_bps_pc_enable) {
+				cam_bps_handle_pc(bps_dev);
+				cam_cpas_reg_write(core_info->cpas_handle,
+					CAM_CPAS_REG_CPASTOP,
+					hw_info->pwr_ctrl, true, 0x0);
+			}
 			rc = cam_bps_toggle_clk(soc_info, true);
 			if (rc)
 				CAM_ERR(CAM_ICP, "Enable failed");
 			else
 				core_info->clk_enable = true;
-			rc = cam_bps_handle_resume(bps_dev);
-			if (rc)
-				CAM_ERR(CAM_ICP, "handle resume failed");
+			if (clk_upd_cmd->ipe_bps_pc_enable) {
+				rc = cam_bps_handle_resume(bps_dev);
+				if (rc)
+					CAM_ERR(CAM_ICP, "BPS resume failed");
+			}
 		}
 		CAM_DBG(CAM_ICP, "clock rate %d", clk_rate);
 		rc = cam_bps_update_clk_rate(soc_info, clk_rate);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index f44fcc0..0012b34 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -247,12 +247,12 @@
 		(struct cam_icp_clk_info *)task_data->data;
 	uint32_t id;
 	uint32_t i;
-	uint32_t curr_clk_rate;
 	struct cam_icp_hw_ctx_data *ctx_data;
 	struct cam_hw_intf *ipe0_dev_intf = NULL;
 	struct cam_hw_intf *ipe1_dev_intf = NULL;
 	struct cam_hw_intf *bps_dev_intf = NULL;
 	struct cam_hw_intf *dev_intf = NULL;
+	struct cam_a5_clk_update_cmd clk_upd_cmd;
 
 	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
 	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
@@ -290,14 +290,17 @@
 
 	CAM_DBG(CAM_ICP, "Disable %d", clk_info->hw_type);
 
+	clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag;
+
 	dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
-		&curr_clk_rate, sizeof(curr_clk_rate));
+		&clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd));
 
 	if (clk_info->hw_type != ICP_CLK_HW_BPS)
 		if (ipe1_dev_intf)
 			ipe1_dev_intf->hw_ops.process_cmd(
 				ipe1_dev_intf->hw_priv, id,
-				&curr_clk_rate, sizeof(curr_clk_rate));
+				&clk_upd_cmd,
+				sizeof(struct cam_a5_clk_update_cmd));
 
 	return 0;
 }
@@ -747,6 +750,7 @@
 	struct cam_hw_intf *ipe1_dev_intf = NULL;
 	struct cam_hw_intf *bps_dev_intf = NULL;
 	struct cam_hw_intf *dev_intf = NULL;
+	struct cam_a5_clk_update_cmd clk_upd_cmd;
 
 	ipe0_dev_intf = hw_mgr->ipe0_dev_intf;
 	ipe1_dev_intf = hw_mgr->ipe1_dev_intf;
@@ -768,14 +772,18 @@
 		id = CAM_ICP_IPE_CMD_UPDATE_CLK;
 	}
 
+	clk_upd_cmd.curr_clk_rate = curr_clk_rate;
+	clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag;
+
 	dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
-		&curr_clk_rate, sizeof(curr_clk_rate));
+		&clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd));
 
 	if (ctx_data->icp_dev_acquire_info->dev_type != CAM_ICP_RES_TYPE_BPS)
 		if (ipe1_dev_intf)
 			ipe1_dev_intf->hw_ops.process_cmd(
 				ipe1_dev_intf->hw_priv, id,
-				&curr_clk_rate, sizeof(curr_clk_rate));
+				&clk_upd_cmd,
+				sizeof(struct cam_a5_clk_update_cmd));
 
 	return 0;
 }
@@ -863,7 +871,7 @@
 		if (hw_mgr->bps_ctxt_cnt++)
 			goto end;
 		bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0);
-		if (icp_hw_mgr.icp_pc_flag) {
+		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			bps_dev_intf->hw_ops.process_cmd(
 				bps_dev_intf->hw_priv,
 				CAM_ICP_BPS_CMD_POWER_RESUME, NULL, 0);
@@ -874,7 +882,7 @@
 			goto end;
 
 		ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0);
-		if (icp_hw_mgr.icp_pc_flag) {
+		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			ipe0_dev_intf->hw_ops.process_cmd(
 				ipe0_dev_intf->hw_priv,
 				CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
@@ -884,21 +892,21 @@
 			ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv,
 				NULL, 0);
 
-			if (icp_hw_mgr.icp_pc_flag) {
+			if (icp_hw_mgr.ipe_bps_pc_flag) {
 				ipe1_dev_intf->hw_ops.process_cmd(
 					ipe1_dev_intf->hw_priv,
 					CAM_ICP_IPE_CMD_POWER_RESUME,
 					NULL, 0);
 			}
 		}
-		if (icp_hw_mgr.icp_pc_flag) {
+		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			hw_mgr->core_info = hw_mgr->core_info |
 				(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1);
 		}
 	}
 
 	CAM_DBG(CAM_ICP, "core_info %X",  hw_mgr->core_info);
-	if (icp_hw_mgr.icp_pc_flag)
+	if (icp_hw_mgr.ipe_bps_pc_flag)
 		rc = hfi_enable_ipe_bps_pc(true, hw_mgr->core_info);
 	else
 		rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info);
@@ -936,7 +944,7 @@
 		if (hw_mgr->bps_ctxt_cnt)
 			goto end;
 
-		if (icp_hw_mgr.icp_pc_flag) {
+		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			rc = bps_dev_intf->hw_ops.process_cmd(
 				bps_dev_intf->hw_priv,
 				CAM_ICP_BPS_CMD_POWER_COLLAPSE,
@@ -954,7 +962,7 @@
 		if (hw_mgr->ipe_ctxt_cnt)
 			goto end;
 
-		if (icp_hw_mgr.icp_pc_flag) {
+		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			rc = ipe0_dev_intf->hw_ops.process_cmd(
 				ipe0_dev_intf->hw_priv,
 				CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
@@ -963,7 +971,7 @@
 		ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
 
 		if (ipe1_dev_intf) {
-			if (icp_hw_mgr.icp_pc_flag) {
+			if (icp_hw_mgr.ipe_bps_pc_flag) {
 				rc = ipe1_dev_intf->hw_ops.process_cmd(
 					ipe1_dev_intf->hw_priv,
 					CAM_ICP_IPE_CMD_POWER_COLLAPSE,
@@ -973,7 +981,7 @@
 			ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
 				NULL, 0);
 		}
-		if (icp_hw_mgr.icp_pc_flag) {
+		if (icp_hw_mgr.ipe_bps_pc_flag) {
 			hw_mgr->core_info = hw_mgr->core_info &
 				(~(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1));
 		}
@@ -1031,7 +1039,18 @@
 		rc = -ENOMEM;
 		goto err;
 	}
-	icp_hw_mgr.icp_pc_flag = 1;
+	icp_hw_mgr.icp_pc_flag = false;
+
+	if (!debugfs_create_bool("ipe_bps_pc",
+		0644,
+		icp_hw_mgr.dentry,
+		&icp_hw_mgr.ipe_bps_pc_flag)) {
+		CAM_ERR(CAM_ICP, "failed to create ipe_bps_pc entry");
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	icp_hw_mgr.ipe_bps_pc_flag = false;
 
 	if (!debugfs_create_file("icp_debug_clk",
 		0644,
@@ -1159,11 +1178,9 @@
 
 	mutex_lock(&ctx_data->ctx_mutex);
 	if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) {
+		CAM_DBG(CAM_ICP, "ctx %u is in %d state",
+			ctx_data->ctx_id, ctx_data->state);
 		mutex_unlock(&ctx_data->ctx_mutex);
-		CAM_WARN(CAM_ICP,
-			"ctx with id: %u not in the right state : %x",
-			ctx_data->ctx_id,
-			ctx_data->state);
 		return 0;
 	}
 
@@ -1814,7 +1831,10 @@
 	}
 	a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
 
-	rc = cam_icp_mgr_send_pc_prep(hw_mgr);
+	if (!hw_mgr->icp_pc_flag)
+		rc = cam_icp_mgr_hw_close(hw_mgr, NULL);
+	else
+		rc = cam_icp_mgr_send_pc_prep(hw_mgr);
 
 	cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
 	a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
@@ -1871,33 +1891,6 @@
 		hw_mgr->a5_jtag_debug);
 }
 
-static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr)
-{
-	int rc = 0;
-	struct cam_hw_intf *a5_dev_intf = NULL;
-
-	CAM_DBG(CAM_ICP, "Enter");
-	a5_dev_intf = hw_mgr->a5_dev_intf;
-
-	if (!a5_dev_intf) {
-		CAM_ERR(CAM_ICP, "a5 dev intf is wrong");
-		return -EINVAL;
-	}
-
-	rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
-	if (rc)
-		return -EINVAL;
-
-	rc = cam_icp_mgr_hfi_resume(hw_mgr);
-	if (rc)
-		goto hfi_resume_failed;
-
-	CAM_DBG(CAM_ICP, "Exit");
-	return rc;
-hfi_resume_failed:
-	cam_icp_mgr_icp_power_collapse(hw_mgr);
-	return rc;
-}
 static int cam_icp_mgr_abort_handle(
 	struct cam_icp_hw_ctx_data *ctx_data)
 {
@@ -2021,7 +2014,10 @@
 			msecs_to_jiffies((timeout)));
 	if (!rem_jiffies) {
 		rc = -ETIMEDOUT;
-		CAM_ERR(CAM_ICP, "FW response timeout: %d", rc);
+		CAM_ERR(CAM_ICP, "FW response timeout: %d for %u",
+			rc, ctx_data->ctx_id);
+		if (icp_hw_mgr.a5_debug_q)
+			cam_icp_mgr_process_dbg_buf();
 	}
 
 	kfree(destroy_cmd);
@@ -2050,6 +2046,7 @@
 	cam_icp_mgr_ipe_bps_power_collapse(hw_mgr,
 		&hw_mgr->ctx_data[ctx_id], 0);
 	hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_RELEASE;
+	CAM_DBG(CAM_ICP, "E: ctx_id = %d", ctx_id);
 	cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]);
 	cam_icp_mgr_cleanup_ctx(&hw_mgr->ctx_data[ctx_id]);
 
@@ -2068,6 +2065,7 @@
 	hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_FREE;
 	mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
 
+	CAM_DBG(CAM_ICP, "X: ctx_id = %d", ctx_id);
 	return 0;
 }
 
@@ -2145,6 +2143,7 @@
 	hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
 
+	CAM_DBG(CAM_ICP, "Exit");
 	return rc;
 }
 
@@ -2321,11 +2320,50 @@
 	return rc;
 }
 
+static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr)
+{
+	int rc = 0;
+	struct cam_hw_intf *a5_dev_intf = NULL;
+	bool downloadFromResume = true;
+
+	CAM_DBG(CAM_ICP, "Enter");
+	a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+
+	if (!a5_dev_intf) {
+		CAM_ERR(CAM_ICP, "a5 dev intf is wrong");
+		return -EINVAL;
+	}
+
+	if (hw_mgr->fw_download  == false) {
+		CAM_DBG(CAM_ICP, "Downloading FW");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		cam_icp_mgr_hw_open(hw_mgr, &downloadFromResume);
+		mutex_lock(&hw_mgr->hw_mgr_mutex);
+		CAM_DBG(CAM_ICP, "FW Download Done Exit");
+		return 0;
+	}
+
+	rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
+	if (rc)
+		return -EINVAL;
+
+	rc = cam_icp_mgr_hfi_resume(hw_mgr);
+	if (rc)
+		goto hfi_resume_failed;
+
+	CAM_DBG(CAM_ICP, "Exit");
+	return rc;
+hfi_resume_failed:
+	cam_icp_mgr_icp_power_collapse(hw_mgr);
+	return rc;
+}
+
 static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args)
 {
 	struct cam_hw_intf *a5_dev_intf = NULL;
 	struct cam_hw_info *a5_dev = NULL;
 	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
+	bool icp_pc = false;
 	int rc = 0;
 
 	if (!hw_mgr) {
@@ -2378,17 +2416,23 @@
 	}
 
 	hw_mgr->ctxt_cnt = 0;
+	hw_mgr->fw_download = true;
 
 	if (icp_hw_mgr.a5_debug_q)
 		hfi_set_debug_level(icp_hw_mgr.a5_dbg_lvl);
 
 	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	CAM_INFO(CAM_ICP, "FW download done successfully");
 
 	rc = cam_ipe_bps_deint(hw_mgr);
+	if (download_fw_args)
+		icp_pc = *((bool *)download_fw_args);
+
+	if (download_fw_args && icp_pc == true)
+		return rc;
+
 	rc = cam_icp_mgr_icp_power_collapse(hw_mgr);
 
-	hw_mgr->fw_download = true;
-	CAM_DBG(CAM_ICP, "FW download done successfully");
 	return rc;
 
 fw_init_failed:
@@ -2489,6 +2533,8 @@
 	rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args);
 	if (rc)
 		goto config_err;
+	CAM_DBG(CAM_ICP, "req_id = %lld %u",
+		req_id, ctx_data->ctx_id);
 	mutex_unlock(&ctx_data->ctx_mutex);
 
 	return 0;
@@ -2539,14 +2585,17 @@
 }
 
 static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr,
-	struct cam_packet *packet,
+	struct cam_packet *packet, struct cam_icp_hw_ctx_data *ctx_data,
 	uint32_t *fw_cmd_buf_iova_addr)
 {
 	int rc = 0;
-	int i;
+	int i, j, k;
 	uint64_t addr;
 	size_t len;
 	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	uint64_t cpu_addr = 0;
+	struct ipe_frame_process_data *frame_process_data = NULL;
+	struct bps_frame_process_data *bps_frame_process_data = NULL;
 
 	cmd_desc = (struct cam_cmd_buf_desc *)
 		((uint32_t *) &packet->payload + packet->cmd_buf_offset/4);
@@ -2564,6 +2613,67 @@
 			*fw_cmd_buf_iova_addr = addr;
 			*fw_cmd_buf_iova_addr =
 				(*fw_cmd_buf_iova_addr + cmd_desc[i].offset);
+			rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle,
+				&cpu_addr, &len);
+			if (rc) {
+				CAM_ERR(CAM_ICP, "get cmd buf failed %x",
+					hw_mgr->iommu_hdl);
+				*fw_cmd_buf_iova_addr = 0;
+				return rc;
+			}
+			cpu_addr = cpu_addr + cmd_desc[i].offset;
+		}
+	}
+
+	if (!cpu_addr) {
+		CAM_ERR(CAM_ICP, "Invalid cpu addr");
+		return -EINVAL;
+	}
+
+	if (ctx_data->icp_dev_acquire_info->dev_type !=
+		CAM_ICP_RES_TYPE_BPS) {
+		CAM_DBG(CAM_ICP, "cpu addr = %llx", cpu_addr);
+		frame_process_data = (struct ipe_frame_process_data *)cpu_addr;
+		CAM_DBG(CAM_ICP, "%u %u %u", frame_process_data->max_num_cores,
+			frame_process_data->target_time,
+			frame_process_data->frames_in_batch);
+		frame_process_data->strip_lib_out_addr = 0;
+		frame_process_data->iq_settings_addr = 0;
+		frame_process_data->scratch_buffer_addr = 0;
+		frame_process_data->ubwc_stats_buffer_addr = 0;
+		frame_process_data->cdm_buffer_addr = 0;
+		frame_process_data->cdm_prog_base = 0;
+		for (i = 0; i < frame_process_data->frames_in_batch; i++) {
+			for (j = 0; j < IPE_IO_IMAGES_MAX; j++) {
+				for (k = 0; k < MAX_NUM_OF_IMAGE_PLANES; k++) {
+					frame_process_data->
+					framesets[i].buffers[j].
+					buffer_ptr[k] = 0;
+					frame_process_data->
+					framesets[i].buffers[j].
+					meta_buffer_ptr[k] = 0;
+				}
+			}
+		}
+	} else {
+		CAM_DBG(CAM_ICP, "cpu addr = %llx", cpu_addr);
+		bps_frame_process_data =
+			(struct bps_frame_process_data *)cpu_addr;
+		CAM_DBG(CAM_ICP, "%u %u",
+			bps_frame_process_data->max_num_cores,
+			bps_frame_process_data->target_time);
+		bps_frame_process_data->ubwc_stats_buffer_addr = 0;
+		bps_frame_process_data->cdm_buffer_addr = 0;
+		bps_frame_process_data->iq_settings_addr = 0;
+		bps_frame_process_data->strip_lib_out_addr = 0;
+		bps_frame_process_data->cdm_prog_addr = 0;
+		for (i = 0; i < BPS_IO_IMAGES_MAX; i++) {
+			for (j = 0; j < MAX_NUM_OF_IMAGE_PLANES; j++) {
+				bps_frame_process_data->
+				buffers[i].buffer_ptr[j] = 0;
+				bps_frame_process_data->
+				buffers[i].meta_buffer_ptr[j] = 0;
+			}
 		}
 	}
 
@@ -2766,12 +2876,13 @@
 	}
 
 	rc = cam_icp_mgr_process_cmd_desc(hw_mgr, packet,
-		&fw_cmd_buf_iova_addr);
+		ctx_data, &fw_cmd_buf_iova_addr);
 	if (rc) {
 		mutex_unlock(&ctx_data->ctx_mutex);
 		return rc;
 	}
 
+	CAM_DBG(CAM_ICP, "E: req id = %lld", packet->header.request_id);
 	/* Update Buffer Address from handles and patch information */
 	rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl,
 		hw_mgr->iommu_sec_hdl);
@@ -2809,6 +2920,8 @@
 	prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd;
 	prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx];
 
+	CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u",
+		packet->header.request_id, ctx_data->ctx_id);
 	mutex_unlock(&ctx_data->ctx_mutex);
 	return rc;
 }
@@ -3025,6 +3138,7 @@
 		return -EINVAL;
 	}
 
+	CAM_DBG(CAM_ICP, "Enter");
 	ctx_data = release_hw->ctxt_to_hw_map;
 	if (!ctx_data) {
 		CAM_ERR(CAM_ICP, "NULL ctx data");
@@ -3054,7 +3168,9 @@
 	rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
 	if (!hw_mgr->ctxt_cnt) {
 		CAM_DBG(CAM_ICP, "Last Release");
+		mutex_unlock(&hw_mgr->hw_mgr_mutex);
 		cam_icp_mgr_icp_power_collapse(hw_mgr);
+		mutex_lock(&hw_mgr->hw_mgr_mutex);
 		cam_icp_hw_mgr_reset_clk_info(hw_mgr);
 		hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
 	}
@@ -3063,6 +3179,7 @@
 	if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)
 		cam_icp_timer_stop(hw_mgr);
 
+	CAM_DBG(CAM_ICP, "Exit");
 	return rc;
 }
 
@@ -3302,6 +3419,7 @@
 		return -EINVAL;
 	}
 
+	CAM_DBG(CAM_ICP, "ENTER");
 	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	ctx_id = cam_icp_mgr_get_free_ctx(hw_mgr);
 	if (ctx_id >= CAM_ICP_CTX_MAX) {
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index 43d7a4a..85f5b550 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -258,6 +258,8 @@
  * @dentry: Debugfs entry
  * @a5_debug: A5 debug flag
  * @icp_pc_flag: Flag to enable/disable power collapse
+ * @ipe_bps_pc_flag: Flag to enable/disable
+ *                   power collapse for ipe & bps
  * @icp_debug_clk: Set clock based on debug value
  * @icp_default_clk: Set this clok if user doesn't supply
  * @clk_info: Clock info of hardware
@@ -295,6 +297,7 @@
 	struct dentry *dentry;
 	bool a5_debug;
 	bool icp_pc_flag;
+	bool ipe_bps_pc_flag;
 	uint64_t icp_debug_clk;
 	uint64_t icp_default_clk;
 	struct cam_icp_clk_info clk_info[ICP_CLK_HW_MAX];
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
index 6915ad5..9e05f2b 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
@@ -22,4 +22,15 @@
 	CAM_ICP_DEV_BPS,
 	CAM_ICP_DEV_MAX,
 };
+
+/**
+ * struct cam_a5_clk_update_cmd - Payload for hw manager command
+ *
+ * @curr_clk_rate:        clk rate to HW
+ * @ipe_bps_pc_enable     power collpase enable flag
+ */
+struct cam_a5_clk_update_cmd {
+	uint32_t  curr_clk_rate;
+	bool  ipe_bps_pc_enable;
+};
 #endif
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
index 5b4156a..87478af 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c
@@ -267,22 +267,28 @@
 		rc = cam_ipe_handle_resume(ipe_dev);
 		break;
 	case CAM_ICP_IPE_CMD_UPDATE_CLK: {
-		uint32_t clk_rate = *(uint32_t *)cmd_args;
+		struct cam_a5_clk_update_cmd *clk_upd_cmd =
+			(struct cam_a5_clk_update_cmd *)cmd_args;
+		uint32_t clk_rate = clk_upd_cmd->curr_clk_rate;
 
 		CAM_DBG(CAM_ICP, "ipe_src_clk rate = %d", (int)clk_rate);
 		if (!core_info->clk_enable) {
-			cam_ipe_handle_pc(ipe_dev);
-			cam_cpas_reg_write(core_info->cpas_handle,
-				CAM_CPAS_REG_CPASTOP,
-				hw_info->pwr_ctrl, true, 0x0);
+			if (clk_upd_cmd->ipe_bps_pc_enable) {
+				cam_ipe_handle_pc(ipe_dev);
+				cam_cpas_reg_write(core_info->cpas_handle,
+					CAM_CPAS_REG_CPASTOP,
+					hw_info->pwr_ctrl, true, 0x0);
+			}
 			rc = cam_ipe_toggle_clk(soc_info, true);
 			if (rc)
 				CAM_ERR(CAM_ICP, "Enable failed");
 			else
 				core_info->clk_enable = true;
-			rc = cam_ipe_handle_resume(ipe_dev);
-			if (rc)
-				CAM_ERR(CAM_ICP, "handle resume failed");
+			if (clk_upd_cmd->ipe_bps_pc_enable) {
+				rc = cam_ipe_handle_resume(ipe_dev);
+				if (rc)
+					CAM_ERR(CAM_ICP, "bps resume failed");
+			}
 		}
 		CAM_DBG(CAM_ICP, "clock rate %d", clk_rate);
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 01c0a02..d1153ba 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -456,6 +456,9 @@
 			}
 		}
 
+		if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_BUBBLE)
+			request_id = 0;
+
 		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
 	} else {
@@ -612,7 +615,10 @@
 		req_isp->bubble_report = 0;
 	}
 
-	request_id = req->request_id;
+	if (req->request_id > ctx_isp->reported_req_id) {
+		request_id = req->request_id;
+		ctx_isp->reported_req_id = request_id;
+	}
 	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
 		CAM_REQ_MGR_SOF_EVENT_ERROR);
 
@@ -738,9 +744,18 @@
 		req_isp->bubble_report = 0;
 	}
 
-	request_id = req->request_id;
-	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
-		CAM_REQ_MGR_SOF_EVENT_ERROR);
+	if (!req_isp->bubble_report) {
+		if (req->request_id > ctx_isp->reported_req_id) {
+			request_id = req->request_id;
+			ctx_isp->reported_req_id = request_id;
+			__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+			CAM_REQ_MGR_SOF_EVENT_ERROR);
+		} else
+			__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+				CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+	} else
+		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
 
 	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
 	CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated);
@@ -1310,6 +1325,17 @@
 	struct cam_isp_hw_sof_event_data      *sof_event_data = evt_data;
 	uint64_t  request_id = 0;
 
+	/*
+	 * Sof in bubble applied state means, reg update not received.
+	 * before increment frame id and override time stamp value, send
+	 * the previous sof time stamp that got captured in the
+	 * sof in applied state.
+	 */
+	CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
+		ctx_isp->frame_id, ctx_isp->sof_timestamp_val);
+	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+		CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+
 	ctx_isp->frame_id++;
 	ctx_isp->sof_timestamp_val = sof_event_data->timestamp;
 	CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
@@ -1359,9 +1385,18 @@
 		req_isp->bubble_report = 0;
 	}
 
-	request_id = req->request_id;
-	__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
-		CAM_REQ_MGR_SOF_EVENT_ERROR);
+	if (!req_isp->bubble_report) {
+		if (req->request_id > ctx_isp->reported_req_id) {
+			request_id = req->request_id;
+			ctx_isp->reported_req_id = request_id;
+			__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+			CAM_REQ_MGR_SOF_EVENT_ERROR);
+		} else
+			__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+				CAM_REQ_MGR_SOF_EVENT_SUCCESS);
+	} else
+		__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
+			CAM_REQ_MGR_SOF_EVENT_SUCCESS);
 
 	/* change the state to bubble, as reg update has not come */
 	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index ccab3a0..8d41ae7 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -3733,10 +3733,13 @@
 	struct cam_vfe_top_irq_evt_payload   *evt_payload;
 	int rc = -EINVAL;
 
-	if (!handler_priv)
+	if (!evt_payload_priv)
 		return rc;
 
 	evt_payload = evt_payload_priv;
+	if (!handler_priv)
+		goto put_payload;
+
 	ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)handler_priv;
 
 	CAM_DBG(CAM_ISP, "addr of evt_payload = %pK core_index:%d",
@@ -3764,7 +3767,7 @@
 	if (rc) {
 		CAM_ERR(CAM_ISP, "Encountered Error (%d), ignoring other irqs",
 			 rc);
-		return IRQ_HANDLED;
+		goto put_payload;
 	}
 
 	CAM_DBG(CAM_ISP, "Calling EOF");
@@ -3786,6 +3789,8 @@
 	cam_ife_hw_mgr_handle_epoch_for_camif_hw_res(ife_hwr_mgr_ctx,
 		evt_payload_priv);
 
+put_payload:
+	cam_vfe_put_evt_payload(evt_payload->core_info, &evt_payload);
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
index 031b7b2..b632e77 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
@@ -607,6 +607,33 @@
 	CAM_DBG(CAM_ISP, "Exit");
 }
 
+irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv)
+{
+	struct cam_irq_controller  *controller  = priv;
+	uint32_t i = 0;
+
+	if (!controller)
+		return IRQ_NONE;
+
+	for (i = 0; i < controller->num_registers; i++) {
+
+		cam_io_w_mb(0x0, controller->mem_base +
+			controller->irq_register_arr[i].clear_reg_offset);
+	}
+
+	if (controller->global_clear_offset)
+		cam_io_w_mb(controller->global_clear_bitmask,
+			controller->mem_base +
+			controller->global_clear_offset);
+
+	for (i = 0; i < controller->num_registers; i++) {
+		cam_io_w_mb(0x0, controller->mem_base +
+		controller->irq_register_arr[i].mask_reg_offset);
+	}
+
+	return IRQ_HANDLED;
+}
+
 irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv)
 {
 	struct cam_irq_controller  *controller  = priv;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
index 7e307b5..e3071ac 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
@@ -250,4 +250,18 @@
  */
 int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle);
 
+/*
+ * cam_irq_controller_clear_and_mask()
+ *
+ * @brief:              This function clears and masks all the irq bits
+ *
+ * @irq_num:            Number of IRQ line that was set that lead to this
+ *                      function being called
+ * @priv:               Private data registered with request_irq is passed back
+ *                      here. This private data should be the irq_controller
+ *                      structure.
+ *
+ * @return:             IRQ_HANDLED/IRQ_NONE
+ */
+irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv);
 #endif /* _CAM_IRQ_CONTROLLER_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 70c9c3b..bce0374 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -1884,21 +1884,23 @@
 
 	if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX ||
 		!csid_reg->rdi_reg[res->res_id]) {
-		CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d",
 			csid_hw->hw_intf->hw_idx, res->res_id);
 		return -EINVAL;
 	}
 
 	if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW ||
 		res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
-		CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d",
-			 csid_hw->hw_intf->hw_idx,
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"CSID:%d Res:%d already in stopped state:%d",
+			csid_hw->hw_intf->hw_idx,
 			res->res_id, res->res_state);
 		return rc;
 	}
 
 	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
-		CAM_DBG(CAM_ISP, "CSID:%d Res:%d Invalid res_state%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"CSID:%d Res:%d Invalid res_state%d",
 			csid_hw->hw_intf->hw_idx, res->res_id,
 			res->res_state);
 		return -EINVAL;
@@ -2006,21 +2008,23 @@
 	soc_info = &csid_hw->hw_info->soc_info;
 
 	if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) {
-		CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d",
 			csid_hw->hw_intf->hw_idx, res->res_id);
 		return -EINVAL;
 	}
 
 	if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW ||
 		res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) {
-		CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d",
-			 csid_hw->hw_intf->hw_idx,
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"CSID:%d Res:%d already in stopped state:%d",
+			csid_hw->hw_intf->hw_idx,
 			res->res_id, res->res_state);
 		return rc;
 	}
 
 	if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) {
-		CAM_DBG(CAM_ISP, "CSID:%d Res:%d Invalid state%d",
+		CAM_ERR_RATE_LIMIT(CAM_ISP,
+			"CSID:%d Res:%d Invalid state%d",
 			csid_hw->hw_intf->hw_idx, res->res_id,
 			res->res_state);
 		return -EINVAL;
@@ -2258,6 +2262,33 @@
 	return rc;
 }
 
+static int cam_ife_csid_reset_retain_sw_reg(
+	struct cam_ife_csid_hw *csid_hw)
+{
+	int rc = 0;
+	struct cam_ife_csid_reg_offset *csid_reg =
+		csid_hw->csid_info->csid_reg;
+
+	cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb,
+		csid_hw->hw_info->soc_info.reg_map[0].mem_base +
+		csid_reg->cmn_reg->csid_rst_strobes_addr);
+
+	CAM_DBG(CAM_ISP, " Waiting for SW reset complete from irq handler");
+	rc = wait_for_completion_timeout(&csid_hw->csid_top_complete,
+		msecs_to_jiffies(IFE_CSID_TIMEOUT));
+	if (rc <= 0) {
+		CAM_ERR(CAM_ISP, "CSID:%d reset completion in fail rc = %d",
+			csid_hw->hw_intf->hw_idx, rc);
+		if (rc == 0)
+			rc = -ETIMEDOUT;
+	} else {
+		rc = 0;
+	}
+
+	return rc;
+}
+
+
 static int cam_ife_csid_init_hw(void *hw_priv,
 	void *init_args, uint32_t arg_size)
 {
@@ -2290,7 +2321,6 @@
 		goto end;
 	}
 
-
 	if ((res->res_type == CAM_ISP_RESOURCE_PIX_PATH) &&
 		(res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED)) {
 		CAM_ERR(CAM_ISP,
@@ -2304,7 +2334,6 @@
 	CAM_DBG(CAM_ISP, "CSID:%d res type :%d res_id:%d",
 		csid_hw->hw_intf->hw_idx, res->res_type, res->res_id);
 
-
 	/* Initialize the csid hardware */
 	rc = cam_ife_csid_enable_hw(csid_hw);
 	if (rc)
@@ -2328,6 +2357,12 @@
 		break;
 	}
 
+	rc = cam_ife_csid_reset_retain_sw_reg(csid_hw);
+	if (rc < 0) {
+		CAM_ERR(CAM_ISP, "CSID: Failed in SW reset");
+		return rc;
+	}
+
 	if (rc)
 		cam_ife_csid_disable_hw(csid_hw);
 end:
@@ -2489,8 +2524,7 @@
 	/*wait for the path to halt */
 	for (i = 0; i < csid_stop->num_res; i++) {
 		res = csid_stop->node_res[i];
-		if (res->res_type == CAM_ISP_RESOURCE_PIX_PATH &&
-			csid_stop->stop_cmd == CAM_CSID_HALT_AT_FRAME_BOUNDARY)
+		if (csid_stop->stop_cmd == CAM_CSID_HALT_AT_FRAME_BOUNDARY)
 			rc = cam_ife_csid_res_wait_for_halt(csid_hw, res);
 		else
 			res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
@@ -2548,8 +2582,35 @@
 
 }
 
+static int cam_ife_csid_halt_device(
+	struct cam_ife_csid_hw *csid_hw)
+{
+	uint32_t  i;
+	int rc = 0;
+	struct cam_isp_resource_node *res_node;
+
+	res_node = &csid_hw->ipp_res;
+	if (res_node->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) {
+		rc = cam_ife_csid_disable_ipp_path(csid_hw,
+			res_node, CAM_CSID_HALT_IMMEDIATELY);
+		res_node->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
+	}
+
+	for (i = 0; i < CAM_IFE_CSID_RDI_MAX; i++) {
+		res_node = &csid_hw->rdi_res[i];
+		if (res_node->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) {
+			rc = cam_ife_csid_disable_rdi_path(csid_hw,
+				res_node, CAM_CSID_HALT_IMMEDIATELY);
+			res_node->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW;
+		}
+	}
+	return rc;
+}
+
+
 irqreturn_t cam_ife_csid_irq(int irq_num, void *data)
 {
+	int rc = 0;
 	struct cam_ife_csid_hw          *csid_hw;
 	struct cam_hw_soc_info          *soc_info;
 	struct cam_ife_csid_reg_offset  *csid_reg;
@@ -2623,22 +2684,52 @@
 	if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow",
 			 csid_hw->hw_intf->hw_idx);
+		rc = cam_ife_csid_halt_device(csid_hw);
+		if (rc) {
+			CAM_ERR_RATE_LIMIT(CAM_ISP,
+				"CSID:%d csid halt device fail rc = %d",
+				csid_hw->hw_intf->hw_idx, rc);
+		}
 	}
 	if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow",
 			 csid_hw->hw_intf->hw_idx);
+		rc = cam_ife_csid_halt_device(csid_hw);
+		if (rc) {
+			CAM_ERR_RATE_LIMIT(CAM_ISP,
+				"CSID:%d csid halt device fail rc = %d",
+				csid_hw->hw_intf->hw_idx, rc);
+		}
 	}
 	if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow",
 			 csid_hw->hw_intf->hw_idx);
+		rc = cam_ife_csid_halt_device(csid_hw);
+		if (rc) {
+			CAM_ERR_RATE_LIMIT(CAM_ISP,
+				"CSID:%d csid halt device fail rc = %d",
+				csid_hw->hw_intf->hw_idx, rc);
+		}
 	}
 	if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow",
 			 csid_hw->hw_intf->hw_idx);
+		rc = cam_ife_csid_halt_device(csid_hw);
+		if (rc) {
+			CAM_ERR_RATE_LIMIT(CAM_ISP,
+				"CSID:%d csid halt device fail rc = %d",
+				csid_hw->hw_intf->hw_idx, rc);
+		}
 	}
 	if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER  FLOW",
 			 csid_hw->hw_intf->hw_idx);
+		rc = cam_ife_csid_halt_device(csid_hw);
+		if (rc) {
+			CAM_ERR_RATE_LIMIT(CAM_ISP,
+				"CSID:%d csid halt device fail rc = %d",
+				csid_hw->hw_intf->hw_idx, rc);
+		}
 	}
 	if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_EOT_RECEPTION",
@@ -2664,7 +2755,7 @@
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT",
 			 csid_hw->hw_intf->hw_idx);
 	}
-		if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) {
+	if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) {
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_STREAM_UNDERFLOW",
 			 csid_hw->hw_intf->hw_idx);
 	}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
index 4a7a4f2..02fec28 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c
@@ -172,6 +172,8 @@
 			th_payload->evt_status_arr[1]);
 		cam_irq_controller_disable_irq(core_info->vfe_irq_controller,
 			core_info->irq_err_handle);
+		cam_irq_controller_clear_and_mask(evt_id,
+			core_info->vfe_irq_controller);
 	}
 
 	rc  = cam_vfe_get_evt_payload(handler_priv->core_info, &evt_payload);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index c166113..36ce652 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -60,7 +60,7 @@
 static uint32_t bus_error_irq_mask[3] = {
 	0x7800,
 	0x0000,
-	0x00C0,
+	0x0040,
 };
 
 enum cam_vfe_bus_packer_format {
@@ -106,6 +106,7 @@
 	struct cam_vfe_bus_irq_evt_payload          evt_payload[
 		CAM_VFE_BUS_VER2_PAYLOAD_MAX];
 	struct list_head                            free_payload_list;
+	spinlock_t                                  spin_lock;
 	struct mutex                                bus_mutex;
 	uint32_t                                    secure_mode;
 	uint32_t                                    num_sec_out;
@@ -214,16 +215,23 @@
 	struct cam_vfe_bus_ver2_common_data  *common_data,
 	struct cam_vfe_bus_irq_evt_payload  **evt_payload)
 {
+	int rc;
+
+	spin_lock(&common_data->spin_lock);
 	if (list_empty(&common_data->free_payload_list)) {
 		*evt_payload = NULL;
 		CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload");
-		return -ENODEV;
+		rc = -ENODEV;
+		goto done;
 	}
 
 	*evt_payload = list_first_entry(&common_data->free_payload_list,
 		struct cam_vfe_bus_irq_evt_payload, list);
 	list_del_init(&(*evt_payload)->list);
-	return 0;
+	rc = 0;
+done:
+	spin_unlock(&common_data->spin_lock);
+	return rc;
 }
 
 static enum cam_vfe_bus_comp_grp_id
@@ -254,6 +262,7 @@
 	struct cam_vfe_bus_ver2_common_data *common_data = NULL;
 	uint32_t  *ife_irq_regs = NULL;
 	uint32_t   status_reg0, status_reg1, status_reg2;
+	unsigned long flags;
 
 	if (!core_info) {
 		CAM_ERR(CAM_ISP, "Invalid param core_info NULL");
@@ -276,8 +285,12 @@
 	}
 
 	common_data = core_info;
+
+	spin_lock_irqsave(&common_data->spin_lock, flags);
 	list_add_tail(&(*evt_payload)->list,
 		&common_data->free_payload_list);
+	spin_unlock_irqrestore(&common_data->spin_lock, flags);
+
 	*evt_payload = NULL;
 
 	return 0;
@@ -2556,8 +2569,21 @@
 		CAM_DBG(CAM_ISP, "WM %d image address 0x%x",
 			wm_data->index, reg_val_pair[j-1]);
 
-		frame_inc = io_cfg->planes[i].plane_stride *
-			io_cfg->planes[i].slice_height;
+		if (wm_data->en_ubwc) {
+			frame_inc = ALIGNUP(io_cfg->planes[i].plane_stride *
+			    io_cfg->planes[i].slice_height, 4096);
+			frame_inc += io_cfg->planes[i].meta_size;
+			CAM_DBG(CAM_ISP,
+				"WM %d frm %d: ht: %d stride %d meta: %d",
+				wm_data->index, frame_inc,
+				io_cfg->planes[i].slice_height,
+				io_cfg->planes[i].plane_stride,
+				io_cfg->planes[i].meta_size);
+		} else {
+			frame_inc = io_cfg->planes[i].plane_stride *
+				io_cfg->planes[i].slice_height;
+		}
+
 		CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j,
 			wm_data->hw_regs->frame_inc, frame_inc);
 		CAM_DBG(CAM_ISP, "WM %d frame_inc %d",
@@ -2975,6 +3001,7 @@
 		}
 	}
 
+	spin_lock_init(&bus_priv->common_data.spin_lock);
 	INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list);
 	for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) {
 		INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
index 9848454..f427ab9 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c
@@ -355,7 +355,6 @@
 			CAM_DBG(CAM_ISP, "Received EPOCH");
 			ret = CAM_VFE_IRQ_STATUS_SUCCESS;
 		}
-		cam_vfe_put_evt_payload(payload->core_info, &payload);
 		break;
 	case CAM_ISP_HW_EVENT_REG_UPDATE:
 		if (irq_status0 & camif_priv->reg_data->reg_update_irq_mask) {
@@ -373,7 +372,6 @@
 		if (irq_status1 & camif_priv->reg_data->error_irq_mask1) {
 			CAM_DBG(CAM_ISP, "Received ERROR\n");
 			ret = CAM_ISP_HW_ERROR_OVERFLOW;
-			cam_vfe_put_evt_payload(payload->core_info, &payload);
 		} else {
 			ret = CAM_ISP_HW_ERROR_NONE;
 		}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
index 28e99f2..50dca827 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c
@@ -209,7 +209,6 @@
 			CAM_DBG(CAM_ISP, "Received REG UPDATE");
 			ret = CAM_VFE_IRQ_STATUS_SUCCESS;
 		}
-		cam_vfe_put_evt_payload(payload->core_info, &payload);
 		break;
 	default:
 		break;
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 65922dd..6e2e7e9 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -742,7 +742,7 @@
 	struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv;
 	uint32_t dev_type;
 	struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL;
-	struct cam_jpeg_hw_cfg_req *cfg_req, *req_temp;
+	struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL;
 
 	if (!hw_mgr || !ctx_data) {
 		CAM_ERR(CAM_JPEG, "Invalid args");
@@ -776,8 +776,8 @@
 
 	list_for_each_entry_safe(cfg_req, req_temp,
 		&hw_mgr->hw_config_req_list, list) {
-		if ((struct cam_jpeg_hw_ctx_data *)cfg_req->
-			hw_cfg_args.ctxt_to_hw_map != ctx_data)
+		if ((cfg_req) && ((struct cam_jpeg_hw_ctx_data *)cfg_req->
+			hw_cfg_args.ctxt_to_hw_map != ctx_data))
 			continue;
 
 		list_del_init(&cfg_req->list);
@@ -800,11 +800,14 @@
 		return -EINVAL;
 	}
 
-	request_id = *(int64_t *)flush_args->flush_req_pending[0];
+	if (flush_args->num_req_pending)
+		return 0;
+
+	request_id = *(int64_t *)flush_args->flush_req_active[0];
 	list_for_each_entry_safe(cfg_req, req_temp,
 		&hw_mgr->hw_config_req_list, list) {
-		if (cfg_req->hw_cfg_args.ctxt_to_hw_map
-			!= ctx_data)
+		if ((cfg_req) && (cfg_req->hw_cfg_args.ctxt_to_hw_map
+			!= ctx_data))
 			continue;
 
 		if (cfg_req->req_id != request_id)
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
index 3fc9032..bb952e6 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.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
@@ -60,8 +60,17 @@
 		hw_info->bus_rd_reg.bus_client_reg[index].core_cfg, 0x1);
 
 	/* 5. unpack_cfg */
-	cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
-		hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, 0x0);
+	if (io_buf->io_cfg->format == CAM_FORMAT_PD10)
+		cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+			hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0,
+			0x0);
+	else if (io_buf->io_cfg->format == CAM_FORMAT_Y_ONLY)
+		cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd,
+			hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0,
+			0x1);
+	else
+		CAM_ERR(CAM_LRME, "Unsupported format %d",
+			io_buf->io_cfg->format);
 }
 
 static void cam_lrme_hw_util_fill_we_reg(struct cam_lrme_hw_io_buffer *io_buf,
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index 784e90b..d7662f1 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -1138,9 +1138,8 @@
  * @brief    : Cleans up the mem allocated while linking
  * @link     : pointer to link, mem associated with this link is freed
  *
- * @return   : returns if unlink for any device was success or failure
  */
-static int __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
+static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link)
 {
 	int32_t                                 i = 0;
 	struct cam_req_mgr_connected_device    *dev;
@@ -1157,12 +1156,13 @@
 		dev = &link->l_dev[i];
 		if (dev != NULL) {
 			link_data.dev_hdl = dev->dev_hdl;
-			if (dev->ops && dev->ops->link_setup)
+			if (dev->ops && dev->ops->link_setup) {
 				rc = dev->ops->link_setup(&link_data);
 				if (rc)
 					CAM_ERR(CAM_CRM,
-						"Unlink failed dev_hdl %d",
-						dev->dev_hdl);
+						"Unlink failed dev_hdl 0x%x rc=%d",
+						dev->dev_hdl, rc);
+			}
 			dev->dev_hdl = 0;
 			dev->parent = NULL;
 			dev->ops = NULL;
@@ -1176,8 +1176,6 @@
 	link->pd_mask = 0;
 	link->num_devs = 0;
 	link->max_delay = 0;
-
-	return rc;
 }
 
 /**
@@ -1263,45 +1261,71 @@
 	return NULL;
 }
 
+/*
+ * __cam_req_mgr_free_link()
+ *
+ * @brief: Frees the link and its request queue
+ *
+ * @link: link identifier
+ *
+ */
+static void __cam_req_mgr_free_link(struct cam_req_mgr_core_link *link)
+{
+	kfree(link->req.in_q);
+	link->req.in_q = NULL;
+	kfree(link);
+}
+
 /**
  * __cam_req_mgr_unreserve_link()
  *
- * @brief  : Reserves one link data struct within session
+ * @brief  : Removes the link data struct from the session and frees it
  * @session: session identifier
  * @link   : link identifier
  *
  */
 static void __cam_req_mgr_unreserve_link(
 	struct cam_req_mgr_core_session *session,
-	struct cam_req_mgr_core_link **link)
+	struct cam_req_mgr_core_link *link)
 {
-	int32_t   i = 0;
+	int i;
 
-	if (!session || !*link) {
+	if (!session || !link) {
 		CAM_ERR(CAM_CRM, "NULL session/link ptr %pK %pK",
-			session, *link);
+			session, link);
 		return;
 	}
 
 	mutex_lock(&session->lock);
-	if (!session->num_links)
-		CAM_WARN(CAM_CRM, "No active link or invalid state %d",
-			session->num_links);
-	else {
-		for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
-			if (session->links[i] == *link)
-				session->links[i] = NULL;
-		}
-		session->num_links--;
-		CAM_DBG(CAM_CRM, "Active session links (%d)",
-			session->num_links);
+	if (!session->num_links) {
+		CAM_WARN(CAM_CRM, "No active link or invalid state: hdl %x",
+			link->link_hdl);
+		mutex_unlock(&session->lock);
+		return;
 	}
-	kfree((*link)->req.in_q);
-	(*link)->req.in_q = NULL;
-	kfree(*link);
-	*link = NULL;
-	mutex_unlock(&session->lock);
 
+	for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+		if (session->links[i] == link)
+			session->links[i] = NULL;
+	}
+
+	if ((session->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC) &&
+		(link->sync_link)) {
+		/*
+		 * make sure to unlink sync setup under the assumption
+		 * of only having 2 links in a given session
+		 */
+		session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC;
+		for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+			if (session->links[i])
+				session->links[i]->sync_link = NULL;
+		}
+	}
+
+	session->num_links--;
+	CAM_DBG(CAM_CRM, "Active session links (%d)", session->num_links);
+	mutex_unlock(&session->lock);
+	__cam_req_mgr_free_link(link);
 }
 
 /* Workqueue context processing section */
@@ -2145,11 +2169,58 @@
 	return rc;
 }
 
+/**
+ * __cam_req_mgr_unlink()
+ *
+ * @brief : Unlink devices on a link structure from the session
+ * @link  : Pointer to the link structure
+ *
+ * @return: 0 for success, negative for failure
+ *
+ */
+static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link)
+{
+	int rc;
+
+	mutex_lock(&link->lock);
+	spin_lock_bh(&link->link_state_spin_lock);
+	link->state = CAM_CRM_LINK_STATE_IDLE;
+	spin_unlock_bh(&link->link_state_spin_lock);
+	__cam_req_mgr_print_req_tbl(&link->req);
+
+	/* Destroy workq payload data */
+	kfree(link->workq->task.pool[0].payload);
+	link->workq->task.pool[0].payload = NULL;
+
+	/* Destroy workq and timer of link */
+	crm_timer_exit(&link->watchdog);
+
+	cam_req_mgr_workq_destroy(&link->workq);
+
+	/* Cleanup request tables and unlink devices */
+	__cam_req_mgr_destroy_link_info(link);
+
+	/* Free memory holding data of linked devs */
+	__cam_req_mgr_destroy_subdev(link->l_dev);
+
+	/* Destroy the link handle */
+	rc = cam_destroy_device_hdl(link->link_hdl);
+	if (rc < 0) {
+		CAM_ERR(CAM_CRM, "error while destroying dev handle %d %x",
+			rc, link->link_hdl);
+	}
+
+	mutex_unlock(&link->lock);
+	return rc;
+}
+
 int cam_req_mgr_destroy_session(
 		struct cam_req_mgr_session_info *ses_info)
 {
 	int rc;
+	int i;
 	struct cam_req_mgr_core_session *cam_session = NULL;
+	struct cam_req_mgr_core_link *link;
 
 	if (!ses_info) {
 		CAM_DBG(CAM_CRM, "NULL session info pointer");
@@ -2167,10 +2238,20 @@
 	}
 	mutex_lock(&cam_session->lock);
 	if (cam_session->num_links) {
-		CAM_ERR(CAM_CRM, "destroy session %x num_active_links %d",
+		CAM_DBG(CAM_CRM, "destroy session %x num_active_links %d",
 			ses_info->session_hdl,
 			cam_session->num_links);
-		/* @TODO : Go through active links and destroy ? */
+
+		for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
+			link = cam_session->links[i];
+
+			if (!link)
+				continue;
+
+			/* Ignore return value since session is going away */
+			__cam_req_mgr_unlink(link);
+			__cam_req_mgr_free_link(link);
+		}
 	}
 	list_del(&cam_session->entry);
 	mutex_unlock(&cam_session->lock);
@@ -2286,7 +2367,7 @@
 	link_info->link_hdl = 0;
 link_hdl_fail:
 	mutex_unlock(&link->lock);
-	__cam_req_mgr_unreserve_link(cam_session, &link);
+	__cam_req_mgr_unreserve_link(cam_session, link);
 	mutex_unlock(&g_crm_core_dev->crm_lock);
 	return rc;
 }
@@ -2296,7 +2377,6 @@
 	int                              rc = 0;
 	struct cam_req_mgr_core_session *cam_session;
 	struct cam_req_mgr_core_link    *link;
-	int                              i;
 
 	if (!unlink_info) {
 		CAM_ERR(CAM_CRM, "NULL pointer");
@@ -2319,60 +2399,18 @@
 	link = cam_get_device_priv(unlink_info->link_hdl);
 	if (!link) {
 		CAM_ERR(CAM_CRM, "NULL pointer");
-		mutex_unlock(&g_crm_core_dev->crm_lock);
-		return -EINVAL;
+		rc = -EINVAL;
+		goto done;
 	}
 
-	mutex_lock(&link->lock);
-	spin_lock_bh(&link->link_state_spin_lock);
-	link->state = CAM_CRM_LINK_STATE_IDLE;
-	spin_unlock_bh(&link->link_state_spin_lock);
-	__cam_req_mgr_print_req_tbl(&link->req);
-
-	if ((cam_session->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC) &&
-		(link->sync_link)) {
-		/*
-		 * make sure to unlink sync setup under the assumption
-		 * of only having 2 links in a given session
-		 */
-		cam_session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC;
-		for (i = 0; i < MAX_LINKS_PER_SESSION; i++) {
-			if (cam_session->links[i])
-				cam_session->links[i]->sync_link = NULL;
-		}
-	}
-
-	/* Destroy workq payload data */
-	kfree(link->workq->task.pool[0].payload);
-	link->workq->task.pool[0].payload = NULL;
-
-	/* Destroy workq and timer of link */
-	crm_timer_exit(&link->watchdog);
-
-	cam_req_mgr_workq_destroy(&link->workq);
-
-	/* Cleanup request tables and unlink devices */
-	rc = __cam_req_mgr_destroy_link_info(link);
-	if (rc) {
-		CAM_ERR(CAM_CORE, "Unlink failed. Cannot proceed");
-		return rc;
-	}
-
-	/* Free memory holding data of linked devs */
-	__cam_req_mgr_destroy_subdev(link->l_dev);
-
-	/* Destroy the link handle */
-	rc = cam_destroy_device_hdl(unlink_info->link_hdl);
-	if (rc < 0) {
-		CAM_ERR(CAM_CRM, "error while destroying dev handle %d %x",
-			rc, link->link_hdl);
-	}
+	rc = __cam_req_mgr_unlink(link);
 
 	/* Free curent link and put back into session's free pool of links */
-	mutex_unlock(&link->lock);
-	__cam_req_mgr_unreserve_link(cam_session, &link);
-	mutex_unlock(&g_crm_core_dev->crm_lock);
+	if (!rc)
+		__cam_req_mgr_unreserve_link(cam_session, link);
 
+done:
+	mutex_unlock(&g_crm_core_dev->crm_lock);
 	return rc;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
index e0d4502..23d25a4 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -612,37 +612,36 @@
 		case CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE: {
 			CAM_DBG(CAM_FLASH,
 				"CAMERA_FLASH_CMD_TYPE_OPS case called");
-			if ((fctrl->flash_state == CAM_FLASH_STATE_START) ||
+			if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) ||
 				(fctrl->flash_state ==
-					CAM_FLASH_STATE_CONFIG)) {
-				flash_operation_info =
-					(struct cam_flash_set_on_off *) cmd_buf;
-				if (!flash_operation_info) {
-					CAM_ERR(CAM_FLASH,
-						"flash_operation_info Null");
-					return -EINVAL;
-				}
-
-				fctrl->per_frame[frame_offset].opcode =
-					flash_operation_info->opcode;
-				fctrl->per_frame[frame_offset].cmn_attr.count =
-					flash_operation_info->count;
-				for (i = 0;
-					i < flash_operation_info->count; i++)
-					fctrl->per_frame[frame_offset].
-						led_current_ma[i]
-						= flash_operation_info->
-						led_current_ma[i];
-
-			} else {
-				CAM_ERR(CAM_FLASH,
-					"Rxed Update packets without linking");
+					CAM_FLASH_STATE_ACQUIRE)) {
+				CAM_WARN(CAM_FLASH,
+					"Rxed Flash fire ops without linking");
 				fctrl->per_frame[frame_offset].
 					cmn_attr.is_settings_valid = false;
+				return 0;
+			}
+
+			flash_operation_info =
+				(struct cam_flash_set_on_off *) cmd_buf;
+			if (!flash_operation_info) {
+				CAM_ERR(CAM_FLASH,
+					"flash_operation_info Null");
 				return -EINVAL;
 			}
+
+			fctrl->per_frame[frame_offset].opcode =
+				flash_operation_info->opcode;
+			fctrl->per_frame[frame_offset].cmn_attr.count =
+				flash_operation_info->count;
+			for (i = 0;
+				i < flash_operation_info->count; i++)
+				fctrl->per_frame[frame_offset].
+					led_current_ma[i]
+					= flash_operation_info->
+					led_current_ma[i];
+			}
 			break;
-		}
 		default:
 			CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d",
 				cmn_hdr->cmd_type);
@@ -741,18 +740,18 @@
 		break;
 	}
 	case CAM_PKT_NOP_OPCODE: {
-		if ((fctrl->flash_state == CAM_FLASH_STATE_START) ||
-			(fctrl->flash_state == CAM_FLASH_STATE_CONFIG)) {
-			CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u",
-				csl_packet->header.request_id);
-			goto update_req_mgr;
-		} else {
-			CAM_ERR(CAM_FLASH,
-				"Rxed Update packets without linking");
+		if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) ||
+			(fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) {
+			CAM_WARN(CAM_FLASH,
+				"Rxed NOP packets without linking");
 			fctrl->per_frame[frame_offset].
 				cmn_attr.is_settings_valid = false;
-			return -EINVAL;
+			return 0;
 		}
+
+		CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u",
+			csl_packet->header.request_id);
+		goto update_req_mgr;
 	}
 	default:
 		CAM_ERR(CAM_FLASH, "Wrong Opcode : %d",
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
index eddbf97..085bcf6 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
@@ -82,7 +82,8 @@
 	}
 	case CAM_RELEASE_DEV: {
 		CAM_DBG(CAM_FLASH, "CAM_RELEASE_DEV");
-		if (fctrl->flash_state != CAM_FLASH_STATE_ACQUIRE) {
+		if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) ||
+			(fctrl->flash_state == CAM_FLASH_STATE_START)) {
 			CAM_WARN(CAM_FLASH,
 				"Cannot apply Release dev: Prev state:%d",
 				fctrl->flash_state);
@@ -131,7 +132,8 @@
 	}
 	case CAM_START_DEV: {
 		CAM_DBG(CAM_FLASH, "CAM_START_DEV");
-		if (fctrl->flash_state != CAM_FLASH_STATE_CONFIG) {
+		if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) ||
+			(fctrl->flash_state == CAM_FLASH_STATE_START)) {
 			CAM_WARN(CAM_FLASH,
 				"Cannot apply Start Dev: Prev state: %d",
 				fctrl->flash_state);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
index 76f5b46..db80584 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -469,7 +469,7 @@
 				CAM_ERR(CAM_OIS, "invalid cmd buf");
 				return -EINVAL;
 			}
-			cmd_buf += cmd_desc->offset / sizeof(uint32_t);
+			cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
 			cmm_hdr = (struct common_header *)cmd_buf;
 
 			switch (cmm_hdr->cmd_type) {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 9ce7a21..9894ca3 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -38,6 +38,31 @@
 			add_req.req_id);
 }
 
+static void cam_sensor_release_stream_rsc(
+	struct cam_sensor_ctrl_t *s_ctrl)
+{
+	struct i2c_settings_array *i2c_set = NULL;
+	int rc;
+
+	i2c_set = &(s_ctrl->i2c_data.streamoff_settings);
+	if (i2c_set->is_settings_valid == 1) {
+		i2c_set->is_settings_valid = -1;
+		rc = delete_request(i2c_set);
+		if (rc < 0)
+			CAM_ERR(CAM_SENSOR,
+				"failed while deleting Streamoff settings");
+	}
+
+	i2c_set = &(s_ctrl->i2c_data.streamon_settings);
+	if (i2c_set->is_settings_valid == 1) {
+		i2c_set->is_settings_valid = -1;
+		rc = delete_request(i2c_set);
+		if (rc < 0)
+			CAM_ERR(CAM_SENSOR,
+				"failed while deleting Streamon settings");
+	}
+}
+
 static void cam_sensor_release_resource(
 	struct cam_sensor_ctrl_t *s_ctrl)
 {
@@ -61,26 +86,10 @@
 			CAM_ERR(CAM_SENSOR,
 				"failed while deleting Res settings");
 	}
-	i2c_set = &(s_ctrl->i2c_data.streamoff_settings);
-	if (i2c_set->is_settings_valid == 1) {
-		i2c_set->is_settings_valid = -1;
-		rc = delete_request(i2c_set);
-		if (rc < 0)
-			CAM_ERR(CAM_SENSOR,
-				"failed while deleting Streamoff settings");
-	}
-	i2c_set = &(s_ctrl->i2c_data.streamon_settings);
-	if (i2c_set->is_settings_valid == 1) {
-		i2c_set->is_settings_valid = -1;
-		rc = delete_request(i2c_set);
-		if (rc < 0)
-			CAM_ERR(CAM_SENSOR,
-				"failed while deleting Streamoff settings");
-	}
+
 	if (s_ctrl->i2c_data.per_frame != NULL) {
 		for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
 			i2c_set = &(s_ctrl->i2c_data.per_frame[i]);
-
 			if (i2c_set->is_settings_valid == 1) {
 				i2c_set->is_settings_valid = -1;
 				rc = delete_request(i2c_set);
@@ -165,42 +174,42 @@
 	}
 
 	case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: {
-		if ((s_ctrl->sensor_state == CAM_SENSOR_CONFIG) ||
-			(s_ctrl->sensor_state == CAM_SENSOR_START)) {
-			i2c_reg_settings =
-				&i2c_data->
-				per_frame[csl_packet->header.request_id %
-				MAX_PER_FRAME_ARRAY];
-			CAM_DBG(CAM_SENSOR, "Received Packet: %lld",
-			csl_packet->header.request_id % MAX_PER_FRAME_ARRAY);
-			if (i2c_reg_settings->is_settings_valid == 1) {
-				CAM_ERR(CAM_SENSOR,
-					"Already some pkt in offset req : %lld",
-					csl_packet->header.request_id);
-				rc = delete_request(i2c_reg_settings);
-				if (rc < 0) {
-					CAM_ERR(CAM_SENSOR,
-					"Failed in Deleting the err: %d", rc);
-					return rc;
-				}
-			}
-		} else {
-			CAM_ERR(CAM_SENSOR,
+		if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
+			(s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) {
+			CAM_WARN(CAM_SENSOR,
 				"Rxed Update packets without linking");
-			return -EINVAL;
+			return 0;
+		}
+
+		i2c_reg_settings =
+			&i2c_data->
+			per_frame[csl_packet->header.request_id %
+			MAX_PER_FRAME_ARRAY];
+		CAM_DBG(CAM_SENSOR, "Received Packet: %lld",
+		csl_packet->header.request_id % MAX_PER_FRAME_ARRAY);
+		if (i2c_reg_settings->is_settings_valid == 1) {
+			CAM_ERR(CAM_SENSOR,
+				"Already some pkt in offset req : %lld",
+				csl_packet->header.request_id);
+			rc = delete_request(i2c_reg_settings);
+			if (rc < 0) {
+				CAM_ERR(CAM_SENSOR,
+				"Failed in Deleting the err: %d", rc);
+				return rc;
+			}
 		}
 	break;
 	}
 	case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: {
-		if ((s_ctrl->sensor_state == CAM_SENSOR_CONFIG) ||
-			(s_ctrl->sensor_state == CAM_SENSOR_START)) {
-			cam_sensor_update_req_mgr(s_ctrl, csl_packet);
-		} else {
-			CAM_ERR(CAM_SENSOR,
-				"Rxed Update packets without linking");
-			rc = -EINVAL;
+		if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
+			(s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) {
+			CAM_WARN(CAM_SENSOR,
+				"Rxed NOP packets without linking");
+			return 0;
 		}
-		return rc;
+
+		cam_sensor_update_req_mgr(s_ctrl, csl_packet);
+		return 0;
 	}
 	default:
 		CAM_ERR(CAM_SENSOR, "Invalid Packet Header");
@@ -489,7 +498,7 @@
 		return;
 
 	cam_sensor_release_resource(s_ctrl);
-
+	cam_sensor_release_stream_rsc(s_ctrl);
 	if (s_ctrl->sensor_state >= CAM_SENSOR_ACQUIRE)
 		cam_sensor_power_down(s_ctrl);
 
@@ -706,8 +715,8 @@
 	}
 		break;
 	case CAM_RELEASE_DEV: {
-		if ((s_ctrl->sensor_state < CAM_SENSOR_ACQUIRE) ||
-			(s_ctrl->sensor_state > CAM_SENSOR_CONFIG)) {
+		if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
+			(s_ctrl->sensor_state == CAM_SENSOR_START)) {
 			rc = -EINVAL;
 			CAM_WARN(CAM_SENSOR,
 			"Not in right state to release : %d",
@@ -722,6 +731,7 @@
 		}
 
 		cam_sensor_release_resource(s_ctrl);
+		cam_sensor_release_stream_rsc(s_ctrl);
 		if (s_ctrl->bridge_intf.device_hdl == -1) {
 			CAM_ERR(CAM_SENSOR,
 				"Invalid Handles: link hdl: %d device hdl: %d",
@@ -754,7 +764,8 @@
 		break;
 	}
 	case CAM_START_DEV: {
-		if (s_ctrl->sensor_state != CAM_SENSOR_CONFIG) {
+		if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) ||
+			(s_ctrl->sensor_state == CAM_SENSOR_START)) {
 			rc = -EINVAL;
 			CAM_WARN(CAM_SENSOR,
 			"Not in right state to start : %d",
@@ -793,6 +804,8 @@
 				"cannot apply streamoff settings");
 			}
 		}
+
+		cam_sensor_release_resource(s_ctrl);
 		s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE;
 	}
 		break;
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
index 7824102..c757315 100644
--- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -434,7 +434,7 @@
 		CAM_ERR(CAM_SMMU, "Error: domain = %pK, device = %pK",
 			domain, dev);
 		CAM_ERR(CAM_SMMU, "iova = %lX, flags = %d", iova, flags);
-		return 0;
+		return -EINVAL;
 	}
 
 	cb_name = (char *)token;
@@ -448,12 +448,12 @@
 		CAM_ERR(CAM_SMMU,
 			"Error: index is not valid, index = %d, token = %s",
 			idx, cb_name);
-		return 0;
+		return -EINVAL;
 	}
 
 	payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC);
 	if (!payload)
-		return 0;
+		return -EINVAL;
 
 	payload->domain = domain;
 	payload->dev = dev;
@@ -468,7 +468,7 @@
 
 	schedule_work(&iommu_cb_set.smmu_work);
 
-	return 0;
+	return -EINVAL;
 }
 
 static int cam_smmu_translate_dir_to_iommu_dir(
@@ -3140,12 +3140,10 @@
 		CAM_ERR(CAM_SMMU, "Error: failed to setup cb : %s", cb->name);
 		goto cb_init_fail;
 	}
-
 	if (cb->io_support && cb->mapping)
 		iommu_set_fault_handler(cb->mapping->domain,
 			cam_smmu_iommu_fault_handler,
 			(void *)cb->name);
-
 	/* increment count to next bank */
 	iommu_cb_set.cb_init_count++;
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index bdc4e2a..ff4f84f 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -3004,12 +3004,6 @@
 	struct mmc_card *card = host->card;
 	int ret;
 
-	/*
-	 * In the case of recovery, we can't expect flushing the cache to work
-	 * always, but we have a go and ignore errors.
-	 */
-	mmc_flush_cache(host->card);
-
 	if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset &&
 	     mmc_can_reset(card)) {
 		mmc_host_clk_hold(host);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index e2e9603..75faeb1 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -121,6 +121,7 @@
 	 Select Y to compile the driver in order to have WLAN functionality
 	 support.
 
+source "drivers/net/wireless/cnss2/Kconfig"
 source "drivers/net/wireless/cnss_utils/Kconfig"
 source "drivers/net/wireless/cnss_genl/Kconfig"
 
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 7a75193..4ffbd10 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -26,6 +26,8 @@
 
 obj-$(CONFIG_MAC80211_HWSIM)	+= mac80211_hwsim.o
 
+obj-$(CONFIG_CNSS2)	+= cnss2/
+
 obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
 
 obj-$(CONFIG_CNSS_UTILS) += cnss_utils/
diff --git a/drivers/net/wireless/cnss2/Kconfig b/drivers/net/wireless/cnss2/Kconfig
new file mode 100644
index 0000000..daa343e
--- /dev/null
+++ b/drivers/net/wireless/cnss2/Kconfig
@@ -0,0 +1,40 @@
+config CNSS2
+	tristate "CNSS2 Platform Driver for Wi-Fi Module"
+	depends on !CNSS && PCI_MSM
+	---help---
+	  This module adds the support for Connectivity Subsystem (CNSS) used
+	  for PCIe based Wi-Fi devices with QCA6174/QCA6290 chipsets.
+	  This driver also adds support to integrate WLAN module to subsystem
+	  restart framework.
+
+config CNSS2_DEBUG
+	bool "CNSS2 Platform Driver Debug Support"
+	depends on CNSS2
+	---help---
+	  This option is to enable CNSS2 platform driver debug support which
+	  primarily includes providing additional verbose logs for certain
+	  features, enabling kernel panic for certain cases to aid the
+	  debugging, and enabling any other debug mechanisms.
+
+config CNSS_ASYNC
+	bool "Enable/disable CNSS platform driver asynchronous probe"
+	depends on CNSS2
+	---help---
+	  If enabled, CNSS platform driver would do asynchronous probe.
+	  Using asynchronous probe will allow CNSS platform driver to
+	  probe in parallel with other device drivers and will help to
+	  reduce kernel boot time.
+
+config BUS_AUTO_SUSPEND
+	bool "Enable/Disable Runtime PM support for PCIe based WLAN Drivers"
+	depends on CNSS2
+	depends on PCI
+	---help---
+	  Runtime Power Management is supported for PCIe based WLAN Drivers.
+	  The features enable cld wlan driver to suspend pcie bus when APPS
+	  is awake based on the driver inactivity with the Firmware.
+	  The Feature uses runtime power management framework from kernel to
+	  track bus access clients and to synchronize the driver activity
+	  during system pm.
+	  This config flag controls the feature per target based. The feature
+	  requires CNSS driver support.
diff --git a/drivers/net/wireless/cnss2/Makefile b/drivers/net/wireless/cnss2/Makefile
new file mode 100644
index 0000000..b49d089
--- /dev/null
+++ b/drivers/net/wireless/cnss2/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_CNSS2) += cnss2.o
+
+cnss2-y := main.o
+cnss2-y += debug.o
+cnss2-y += pci.o
+cnss2-y += power.o
+cnss2-y += qmi.o
+cnss2-y += wlan_firmware_service_v01.o
diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c
new file mode 100644
index 0000000..5e2d44c
--- /dev/null
+++ b/drivers/net/wireless/cnss2/debug.c
@@ -0,0 +1,495 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include "main.h"
+#include "debug.h"
+#include "pci.h"
+
+#define CNSS_IPC_LOG_PAGES		32
+
+void *cnss_ipc_log_context;
+
+static int cnss_pin_connect_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *cnss_priv = s->private;
+
+	seq_puts(s, "Pin connect results\n");
+	seq_printf(s, "FW power pin result: %04x\n",
+		   cnss_priv->pin_result.fw_pwr_pin_result);
+	seq_printf(s, "FW PHY IO pin result: %04x\n",
+		   cnss_priv->pin_result.fw_phy_io_pin_result);
+	seq_printf(s, "FW RF pin result: %04x\n",
+		   cnss_priv->pin_result.fw_rf_pin_result);
+	seq_printf(s, "Host pin result: %04x\n",
+		   cnss_priv->pin_result.host_pin_result);
+	seq_puts(s, "\n");
+
+	return 0;
+}
+
+static int cnss_pin_connect_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_pin_connect_show, inode->i_private);
+}
+
+static const struct file_operations cnss_pin_connect_fops = {
+	.read		= seq_read,
+	.release	= single_release,
+	.open		= cnss_pin_connect_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static int cnss_stats_show_state(struct seq_file *s,
+				 struct cnss_plat_data *plat_priv)
+{
+	enum cnss_driver_state i;
+	int skip = 0;
+	unsigned long state;
+
+	seq_printf(s, "\nState: 0x%lx(", plat_priv->driver_state);
+	for (i = 0, state = plat_priv->driver_state; state != 0;
+	     state >>= 1, i++) {
+		if (!(state & 0x1))
+			continue;
+
+		if (skip++)
+			seq_puts(s, " | ");
+
+		switch (i) {
+		case CNSS_QMI_WLFW_CONNECTED:
+			seq_puts(s, "QMI_WLFW_CONNECTED");
+			continue;
+		case CNSS_FW_MEM_READY:
+			seq_puts(s, "FW_MEM_READY");
+			continue;
+		case CNSS_FW_READY:
+			seq_puts(s, "FW_READY");
+			continue;
+		case CNSS_COLD_BOOT_CAL:
+			seq_puts(s, "COLD_BOOT_CAL");
+			continue;
+		case CNSS_DRIVER_LOADING:
+			seq_puts(s, "DRIVER_LOADING");
+			continue;
+		case CNSS_DRIVER_UNLOADING:
+			seq_puts(s, "DRIVER_UNLOADING");
+			continue;
+		case CNSS_DRIVER_PROBED:
+			seq_puts(s, "DRIVER_PROBED");
+			continue;
+		case CNSS_DRIVER_RECOVERY:
+			seq_puts(s, "DRIVER_RECOVERY");
+			continue;
+		case CNSS_FW_BOOT_RECOVERY:
+			seq_puts(s, "FW_BOOT_RECOVERY");
+			continue;
+		case CNSS_DEV_ERR_NOTIFY:
+			seq_puts(s, "DEV_ERR");
+			continue;
+		case CNSS_DRIVER_DEBUG:
+			seq_puts(s, "DRIVER_DEBUG");
+			continue;
+		}
+
+		seq_printf(s, "UNKNOWN-%d", i);
+	}
+	seq_puts(s, ")\n");
+
+	return 0;
+}
+
+static int cnss_stats_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *plat_priv = s->private;
+
+	cnss_stats_show_state(s, plat_priv);
+
+	return 0;
+}
+
+static int cnss_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_stats_show, inode->i_private);
+}
+
+static const struct file_operations cnss_stats_fops = {
+	.read		= seq_read,
+	.release	= single_release,
+	.open		= cnss_stats_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static ssize_t cnss_dev_boot_debug_write(struct file *fp,
+					 const char __user *user_buf,
+					 size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	char buf[64];
+	char *cmd;
+	unsigned int len = 0;
+	int ret = 0;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	cmd = buf;
+
+	if (sysfs_streq(cmd, "on")) {
+		ret = cnss_power_on_device(plat_priv);
+	} else if (sysfs_streq(cmd, "off")) {
+		cnss_power_off_device(plat_priv);
+	} else if (sysfs_streq(cmd, "enumerate")) {
+		ret = cnss_pci_init(plat_priv);
+	} else if (sysfs_streq(cmd, "download")) {
+		set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+		ret = cnss_pci_start_mhi(plat_priv->bus_priv);
+	} else if (sysfs_streq(cmd, "linkup")) {
+		ret = cnss_resume_pci_link(plat_priv->bus_priv);
+	} else if (sysfs_streq(cmd, "linkdown")) {
+		ret = cnss_suspend_pci_link(plat_priv->bus_priv);
+	} else if (sysfs_streq(cmd, "powerup")) {
+		set_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+		ret = cnss_driver_event_post(plat_priv,
+					     CNSS_DRIVER_EVENT_POWER_UP,
+					     CNSS_EVENT_SYNC, NULL);
+	} else if (sysfs_streq(cmd, "shutdown")) {
+		ret = cnss_driver_event_post(plat_priv,
+					     CNSS_DRIVER_EVENT_POWER_DOWN,
+					     CNSS_EVENT_SYNC, NULL);
+		clear_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state);
+	} else {
+		cnss_pr_err("Device boot debugfs command is invalid\n");
+		ret = -EINVAL;
+	}
+
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static int cnss_dev_boot_debug_show(struct seq_file *s, void *data)
+{
+	seq_puts(s, "\nUsage: echo <action> > <debugfs_path>/cnss/dev_boot\n");
+	seq_puts(s, "<action> can be one of below:\n");
+	seq_puts(s, "on: turn on device power, assert WLAN_EN\n");
+	seq_puts(s, "off: de-assert WLAN_EN, turn off device power\n");
+	seq_puts(s, "enumerate: de-assert PERST, enumerate PCIe\n");
+	seq_puts(s, "download: download FW and do QMI handshake with FW\n");
+	seq_puts(s, "linkup: bring up PCIe link\n");
+	seq_puts(s, "linkdown: bring down PCIe link\n");
+	seq_puts(s, "powerup: full power on sequence to boot device, download FW and do QMI handshake with FW\n");
+	seq_puts(s, "shutdown: full power off sequence to shutdown device\n");
+
+	return 0;
+}
+
+static int cnss_dev_boot_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_dev_boot_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_dev_boot_debug_fops = {
+	.read		= seq_read,
+	.write		= cnss_dev_boot_debug_write,
+	.release	= single_release,
+	.open		= cnss_dev_boot_debug_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static int cnss_reg_read_debug_show(struct seq_file *s, void *data)
+{
+	struct cnss_plat_data *plat_priv = s->private;
+
+	mutex_lock(&plat_priv->dev_lock);
+	if (!plat_priv->diag_reg_read_buf) {
+		seq_puts(s, "\nUsage: echo <mem_type> <offset> <data_len> > <debugfs_path>/cnss/reg_read\n");
+		mutex_unlock(&plat_priv->dev_lock);
+		return 0;
+	}
+
+	seq_printf(s, "\nRegister read, address: 0x%x memory type: 0x%x length: 0x%x\n\n",
+		   plat_priv->diag_reg_read_addr,
+		   plat_priv->diag_reg_read_mem_type,
+		   plat_priv->diag_reg_read_len);
+
+	seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 32, 4,
+		     plat_priv->diag_reg_read_buf,
+		     plat_priv->diag_reg_read_len, false);
+
+	plat_priv->diag_reg_read_len = 0;
+	kfree(plat_priv->diag_reg_read_buf);
+	plat_priv->diag_reg_read_buf = NULL;
+	mutex_unlock(&plat_priv->dev_lock);
+
+	return 0;
+}
+
+static ssize_t cnss_reg_read_debug_write(struct file *fp,
+					 const char __user *user_buf,
+					 size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	char buf[64];
+	char *sptr, *token;
+	unsigned int len = 0;
+	u32 reg_offset, mem_type;
+	u32 data_len = 0;
+	u8 *reg_buf = NULL;
+	const char *delim = " ";
+	int ret = 0;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Firmware is not ready yet\n");
+		return -EINVAL;
+	}
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	sptr = buf;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (!sptr)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &mem_type))
+		return -EINVAL;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (!sptr)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &reg_offset))
+		return -EINVAL;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &data_len))
+		return -EINVAL;
+
+	if (data_len == 0 ||
+	    data_len > QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01)
+		return -EINVAL;
+
+	mutex_lock(&plat_priv->dev_lock);
+	kfree(plat_priv->diag_reg_read_buf);
+	plat_priv->diag_reg_read_buf = NULL;
+
+	reg_buf = kzalloc(data_len, GFP_KERNEL);
+	if (!reg_buf) {
+		mutex_unlock(&plat_priv->dev_lock);
+		return -ENOMEM;
+	}
+
+	ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, reg_offset,
+					       mem_type, data_len,
+					       reg_buf);
+	if (ret) {
+		kfree(reg_buf);
+		mutex_unlock(&plat_priv->dev_lock);
+		return ret;
+	}
+
+	plat_priv->diag_reg_read_addr = reg_offset;
+	plat_priv->diag_reg_read_mem_type = mem_type;
+	plat_priv->diag_reg_read_len = data_len;
+	plat_priv->diag_reg_read_buf = reg_buf;
+	mutex_unlock(&plat_priv->dev_lock);
+
+	return count;
+}
+
+static int cnss_reg_read_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_reg_read_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_reg_read_debug_fops = {
+	.read		= seq_read,
+	.write		= cnss_reg_read_debug_write,
+	.open		= cnss_reg_read_debug_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static int cnss_reg_write_debug_show(struct seq_file *s, void *data)
+{
+	seq_puts(s, "\nUsage: echo <mem_type> <offset> <reg_val> > <debugfs_path>/cnss/reg_write\n");
+
+	return 0;
+}
+
+static ssize_t cnss_reg_write_debug_write(struct file *fp,
+					  const char __user *user_buf,
+					  size_t count, loff_t *off)
+{
+	struct cnss_plat_data *plat_priv =
+		((struct seq_file *)fp->private_data)->private;
+	char buf[64];
+	char *sptr, *token;
+	unsigned int len = 0;
+	u32 reg_offset, mem_type, reg_val;
+	const char *delim = " ";
+	int ret = 0;
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Firmware is not ready yet\n");
+		return -EINVAL;
+	}
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	buf[len] = '\0';
+	sptr = buf;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (!sptr)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &mem_type))
+		return -EINVAL;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (!sptr)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &reg_offset))
+		return -EINVAL;
+
+	token = strsep(&sptr, delim);
+	if (!token)
+		return -EINVAL;
+
+	if (kstrtou32(token, 0, &reg_val))
+		return -EINVAL;
+
+	ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, reg_offset, mem_type,
+						sizeof(u32),
+						(u8 *)&reg_val);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static int cnss_reg_write_debug_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_reg_write_debug_show, inode->i_private);
+}
+
+static const struct file_operations cnss_reg_write_debug_fops = {
+	.read		= seq_read,
+	.write		= cnss_reg_write_debug_write,
+	.open		= cnss_reg_write_debug_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+#ifdef CONFIG_CNSS2_DEBUG
+static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
+{
+	struct dentry *root_dentry = plat_priv->root_dentry;
+
+	debugfs_create_file("dev_boot", 0600, root_dentry, plat_priv,
+			    &cnss_dev_boot_debug_fops);
+	debugfs_create_file("reg_read", 0600, root_dentry, plat_priv,
+			    &cnss_reg_read_debug_fops);
+	debugfs_create_file("reg_write", 0600, root_dentry, plat_priv,
+			    &cnss_reg_write_debug_fops);
+
+	return 0;
+}
+#else
+static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv)
+{
+	return 0;
+}
+#endif
+
+int cnss_debugfs_create(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct dentry *root_dentry;
+
+	root_dentry = debugfs_create_dir("cnss", 0);
+	if (IS_ERR(root_dentry)) {
+		ret = PTR_ERR(root_dentry);
+		cnss_pr_err("Unable to create debugfs %d\n", ret);
+		goto out;
+	}
+
+	plat_priv->root_dentry = root_dentry;
+
+	debugfs_create_file("pin_connect_result", 0644, root_dentry, plat_priv,
+			    &cnss_pin_connect_fops);
+	debugfs_create_file("stats", 0644, root_dentry, plat_priv,
+			    &cnss_stats_fops);
+
+	cnss_create_debug_only_node(plat_priv);
+
+out:
+	return ret;
+}
+
+void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv)
+{
+	debugfs_remove_recursive(plat_priv->root_dentry);
+}
+
+int cnss_debug_init(void)
+{
+	cnss_ipc_log_context = ipc_log_context_create(CNSS_IPC_LOG_PAGES,
+						      "cnss", 0);
+	if (!cnss_ipc_log_context) {
+		cnss_pr_err("Unable to create IPC log context!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void cnss_debug_deinit(void)
+{
+	if (cnss_ipc_log_context) {
+		ipc_log_context_destroy(cnss_ipc_log_context);
+		cnss_ipc_log_context = NULL;
+	}
+}
diff --git a/drivers/net/wireless/cnss2/debug.h b/drivers/net/wireless/cnss2/debug.h
new file mode 100644
index 0000000..decc84a
--- /dev/null
+++ b/drivers/net/wireless/cnss2/debug.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CNSS_DEBUG_H
+#define _CNSS_DEBUG_H
+
+#include <linux/ipc_logging.h>
+#include <linux/printk.h>
+
+extern void *cnss_ipc_log_context;
+
+#define cnss_ipc_log_string(_x...) do {					\
+		if (cnss_ipc_log_context)				\
+			ipc_log_string(cnss_ipc_log_context, _x);	\
+	} while (0)
+
+#define cnss_pr_err(_fmt, ...) do {					\
+		pr_err("cnss: " _fmt, ##__VA_ARGS__);			\
+		cnss_ipc_log_string("ERR: " _fmt, ##__VA_ARGS__);	\
+	} while (0)
+
+#define cnss_pr_warn(_fmt, ...) do {					\
+		pr_warn("cnss: " _fmt, ##__VA_ARGS__);			\
+		cnss_ipc_log_string("WRN: " _fmt, ##__VA_ARGS__);	\
+	} while (0)
+
+#define cnss_pr_info(_fmt, ...) do {					\
+		pr_info("cnss: " _fmt, ##__VA_ARGS__);			\
+		cnss_ipc_log_string("INF: " _fmt, ##__VA_ARGS__);	\
+	} while (0)
+
+#define cnss_pr_dbg(_fmt, ...) do {					\
+		pr_debug("cnss: " _fmt, ##__VA_ARGS__);			\
+		cnss_ipc_log_string("DBG: " _fmt, ##__VA_ARGS__);	\
+	} while (0)
+
+#ifdef CONFIG_CNSS2_DEBUG
+#define CNSS_ASSERT(_condition) do {					\
+		if (!(_condition)) {					\
+			cnss_pr_err("ASSERT at line %d\n",		\
+				    __LINE__);				\
+			BUG_ON(1);					\
+		}							\
+	} while (0)
+#else
+#define CNSS_ASSERT(_condition) do {					\
+		if (!(_condition)) {					\
+			cnss_pr_err("ASSERT at line %d\n",		\
+				    __LINE__);				\
+			WARN_ON(1);					\
+		}							\
+	} while (0)
+#endif
+
+int cnss_debug_init(void);
+void cnss_debug_deinit(void);
+int cnss_debugfs_create(struct cnss_plat_data *plat_priv);
+void cnss_debugfs_destroy(struct cnss_plat_data *plat_priv);
+
+#endif /* _CNSS_DEBUG_H */
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
new file mode 100644
index 0000000..bcea74a
--- /dev/null
+++ b/drivers/net/wireless/cnss2/main.c
@@ -0,0 +1,2368 @@
+/* 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
+ * 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/delay.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/rwsem.h>
+#include <linux/suspend.h>
+#include <linux/timer.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/subsystem_notif.h>
+
+#include "main.h"
+#include "debug.h"
+#include "pci.h"
+
+#define CNSS_DUMP_FORMAT_VER		0x11
+#define CNSS_DUMP_FORMAT_VER_V2		0x22
+#define CNSS_DUMP_MAGIC_VER_V2		0x42445953
+#define CNSS_DUMP_NAME			"CNSS_WLAN"
+#define CNSS_DUMP_DESC_SIZE		0x1000
+#define CNSS_DUMP_SEG_VER		0x1
+#define WLAN_RECOVERY_DELAY		1000
+#define FILE_SYSTEM_READY		1
+#define FW_READY_TIMEOUT		20000
+#define FW_ASSERT_TIMEOUT		5000
+#define CNSS_EVENT_PENDING		2989
+#define WAKE_MSI_NAME			"WAKE"
+
+static struct cnss_plat_data *plat_env;
+
+static DECLARE_RWSEM(cnss_pm_sem);
+
+static bool qmi_bypass;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(qmi_bypass, bool, 0600);
+MODULE_PARM_DESC(qmi_bypass, "Bypass QMI from platform driver");
+#endif
+
+static bool enable_waltest;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(enable_waltest, bool, 0600);
+MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest");
+#endif
+
+enum cnss_debug_quirks {
+	LINK_DOWN_SELF_RECOVERY,
+	SKIP_DEVICE_BOOT,
+	USE_CORE_ONLY_FW,
+	SKIP_RECOVERY,
+};
+
+unsigned long quirks;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(quirks, ulong, 0600);
+MODULE_PARM_DESC(quirks, "Debug quirks for the driver");
+#endif
+
+static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = {
+	"qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin",
+	"utfbd30.bin", "epping30.bin", "evicted30.bin"
+};
+
+static struct cnss_fw_files FW_FILES_DEFAULT = {
+	"qwlan.bin", "bdwlan.bin", "otp.bin", "utf.bin",
+	"utfbd.bin", "epping.bin", "evicted.bin"
+};
+
+struct cnss_driver_event {
+	struct list_head list;
+	enum cnss_driver_event_type type;
+	bool sync;
+	struct completion complete;
+	int ret;
+	void *data;
+};
+
+static enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev)
+{
+	if (!dev)
+		return CNSS_BUS_NONE;
+
+	if (!dev->bus)
+		return CNSS_BUS_NONE;
+
+	if (memcmp(dev->bus->name, "pci", 3) == 0)
+		return CNSS_BUS_PCI;
+	else
+		return CNSS_BUS_NONE;
+}
+
+static void cnss_set_plat_priv(struct platform_device *plat_dev,
+			       struct cnss_plat_data *plat_priv)
+{
+	plat_env = plat_priv;
+}
+
+static struct cnss_plat_data *cnss_get_plat_priv(struct platform_device
+						 *plat_dev)
+{
+	return plat_env;
+}
+
+void *cnss_bus_dev_to_bus_priv(struct device *dev)
+{
+	if (!dev)
+		return NULL;
+
+	switch (cnss_get_dev_bus_type(dev)) {
+	case CNSS_BUS_PCI:
+		return cnss_get_pci_priv(to_pci_dev(dev));
+	default:
+		return NULL;
+	}
+}
+
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev)
+{
+	void *bus_priv;
+
+	if (!dev)
+		return cnss_get_plat_priv(NULL);
+
+	bus_priv = cnss_bus_dev_to_bus_priv(dev);
+	if (!bus_priv)
+		return NULL;
+
+	switch (cnss_get_dev_bus_type(dev)) {
+	case CNSS_BUS_PCI:
+		return cnss_pci_priv_to_plat_priv(bus_priv);
+	default:
+		return NULL;
+	}
+}
+
+static int cnss_pm_notify(struct notifier_block *b,
+			  unsigned long event, void *p)
+{
+	switch (event) {
+	case PM_SUSPEND_PREPARE:
+		down_write(&cnss_pm_sem);
+		break;
+	case PM_POST_SUSPEND:
+		up_write(&cnss_pm_sem);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block cnss_pm_notifier = {
+	.notifier_call = cnss_pm_notify,
+};
+
+static void cnss_pm_stay_awake(struct cnss_plat_data *plat_priv)
+{
+	if (atomic_inc_return(&plat_priv->pm_count) != 1)
+		return;
+
+	cnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n",
+		    plat_priv->driver_state,
+		    atomic_read(&plat_priv->pm_count));
+	pm_stay_awake(&plat_priv->plat_dev->dev);
+}
+
+static void cnss_pm_relax(struct cnss_plat_data *plat_priv)
+{
+	int r = atomic_dec_return(&plat_priv->pm_count);
+
+	WARN_ON(r < 0);
+
+	if (r != 0)
+		return;
+
+	cnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n",
+		    plat_priv->driver_state,
+		    atomic_read(&plat_priv->pm_count));
+	pm_relax(&plat_priv->plat_dev->dev);
+}
+
+void cnss_lock_pm_sem(struct device *dev)
+{
+	down_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_lock_pm_sem);
+
+void cnss_release_pm_sem(struct device *dev)
+{
+	up_read(&cnss_pm_sem);
+}
+EXPORT_SYMBOL(cnss_release_pm_sem);
+
+int cnss_get_fw_files_for_target(struct device *dev,
+				 struct cnss_fw_files *pfw_files,
+				 u32 target_type, u32 target_version)
+{
+	if (!pfw_files)
+		return -ENODEV;
+
+	switch (target_version) {
+	case QCA6174_REV3_VERSION:
+	case QCA6174_REV3_2_VERSION:
+		memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
+		break;
+	default:
+		memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
+		cnss_pr_err("Unknown target version, type: 0x%X, version: 0x%X",
+			    target_type, target_version);
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_fw_files_for_target);
+
+int cnss_request_bus_bandwidth(struct device *dev, int bandwidth)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_bus_bw_info *bus_bw_info;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	bus_bw_info = &plat_priv->bus_bw_info;
+	if (!bus_bw_info->bus_client)
+		return -EINVAL;
+
+	switch (bandwidth) {
+	case CNSS_BUS_WIDTH_NONE:
+	case CNSS_BUS_WIDTH_LOW:
+	case CNSS_BUS_WIDTH_MEDIUM:
+	case CNSS_BUS_WIDTH_HIGH:
+		ret = msm_bus_scale_client_update_request(
+			bus_bw_info->bus_client, bandwidth);
+		if (!ret)
+			bus_bw_info->current_bw_vote = bandwidth;
+		else
+			cnss_pr_err("Could not set bus bandwidth: %d, err = %d\n",
+				    bandwidth, ret);
+		break;
+	default:
+		cnss_pr_err("Invalid bus bandwidth: %d", bandwidth);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(cnss_request_bus_bandwidth);
+
+int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (cap)
+		*cap = plat_priv->cap;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_platform_cap);
+
+int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	void *bus_priv = cnss_bus_dev_to_bus_priv(dev);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	ret = cnss_pci_get_bar_info(bus_priv, &info->va, &info->pa);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_soc_info);
+
+void cnss_request_pm_qos(struct device *dev, u32 qos_val)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return;
+
+	pm_qos_add_request(&plat_priv->qos_request, PM_QOS_CPU_DMA_LATENCY,
+			   qos_val);
+}
+EXPORT_SYMBOL(cnss_request_pm_qos);
+
+void cnss_remove_pm_qos(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv)
+		return;
+
+	pm_qos_remove_request(&plat_priv->qos_request);
+}
+EXPORT_SYMBOL(cnss_remove_pm_qos);
+
+int cnss_wlan_enable(struct device *dev,
+		     struct cnss_wlan_enable_cfg *config,
+		     enum cnss_driver_mode mode,
+		     const char *host_version)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct wlfw_wlan_cfg_req_msg_v01 req;
+	u32 i;
+	int ret = 0;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (qmi_bypass)
+		return 0;
+
+	if (!config || !host_version) {
+		cnss_pr_err("Invalid config or host_version pointer\n");
+		return -EINVAL;
+	}
+
+	cnss_pr_dbg("Mode: %d, config: %pK, host_version: %s\n",
+		    mode, config, host_version);
+
+	if (mode == CNSS_WALTEST || mode == CNSS_CCPM)
+		goto skip_cfg;
+
+	memset(&req, 0, sizeof(req));
+
+	req.host_version_valid = 1;
+	strlcpy(req.host_version, host_version,
+		QMI_WLFW_MAX_STR_LEN_V01 + 1);
+
+	req.tgt_cfg_valid = 1;
+	if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01)
+		req.tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
+	else
+		req.tgt_cfg_len = config->num_ce_tgt_cfg;
+	for (i = 0; i < req.tgt_cfg_len; i++) {
+		req.tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
+		req.tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
+		req.tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
+		req.tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
+		req.tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
+	}
+
+	req.svc_cfg_valid = 1;
+	if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01)
+		req.svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01;
+	else
+		req.svc_cfg_len = config->num_ce_svc_pipe_cfg;
+	for (i = 0; i < req.svc_cfg_len; i++) {
+		req.svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
+		req.svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
+		req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
+	}
+
+	req.shadow_reg_v2_valid = 1;
+	if (config->num_shadow_reg_v2_cfg >
+	    QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
+		req.shadow_reg_v2_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01;
+	else
+		req.shadow_reg_v2_len = config->num_shadow_reg_v2_cfg;
+
+	memcpy(req.shadow_reg_v2, config->shadow_reg_v2_cfg,
+	       sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01)
+	       * req.shadow_reg_v2_len);
+
+	ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, &req);
+	if (ret)
+		goto out;
+
+skip_cfg:
+	ret = cnss_wlfw_wlan_mode_send_sync(plat_priv, mode);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_enable);
+
+int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (qmi_bypass)
+		return 0;
+
+	return cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
+}
+EXPORT_SYMBOL(cnss_wlan_disable);
+
+#ifdef CONFIG_CNSS2_DEBUG
+int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
+		      u32 data_len, u8 *output)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	int ret = 0;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (!output || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
+		cnss_pr_err("Invalid parameters for athdiag read: output %p, data_len %u\n",
+			    output, data_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Invalid state for athdiag read: 0x%lx\n",
+			    plat_priv->driver_state);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, offset, mem_type,
+					       data_len, output);
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_athdiag_read);
+
+int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
+		       u32 data_len, u8 *input)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	int ret = 0;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (!input || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
+		cnss_pr_err("Invalid parameters for athdiag write: input %p, data_len %u\n",
+			    input, data_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+		cnss_pr_err("Invalid state for athdiag write: 0x%lx\n",
+			    plat_priv->driver_state);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, offset, mem_type,
+						data_len, input);
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_athdiag_write);
+#else
+int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
+		      u32 data_len, u8 *output)
+{
+	return -EPERM;
+}
+EXPORT_SYMBOL(cnss_athdiag_read);
+
+int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
+		       u32 data_len, u8 *input)
+{
+	return -EPERM;
+}
+EXPORT_SYMBOL(cnss_athdiag_write);
+#endif
+
+int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	return cnss_wlfw_ini_send_sync(plat_priv, fw_log_mode);
+}
+EXPORT_SYMBOL(cnss_set_fw_log_mode);
+
+u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+	int ret, num_vectors;
+	u32 user_base_data, base_vector;
+
+	ret = cnss_get_user_msi_assignment(&pci_priv->pci_dev->dev,
+					   WAKE_MSI_NAME, &num_vectors,
+					   &user_base_data, &base_vector);
+
+	if (ret) {
+		cnss_pr_err("WAKE MSI is not valid\n");
+		return 0;
+	}
+
+	return user_base_data;
+}
+
+static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	set_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+
+	ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
+	if (ret)
+		goto out;
+
+	ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
+	if (ret)
+		goto out;
+
+	ret = cnss_pci_load_m3(plat_priv->bus_priv);
+	if (ret)
+		goto out;
+
+	ret = cnss_wlfw_m3_dnld_send_sync(plat_priv);
+	if (ret)
+		goto out;
+
+	return 0;
+out:
+	return ret;
+}
+
+static int cnss_driver_call_probe(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	if (test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+		cnss_pr_dbg("Skip driver probe\n");
+		goto out;
+	}
+
+	if (!plat_priv->driver_ops) {
+		cnss_pr_err("driver_ops is NULL\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		ret = plat_priv->driver_ops->reinit(pci_priv->pci_dev,
+						    pci_priv->pci_device_id);
+		if (ret) {
+			cnss_pr_err("Failed to reinit host driver, err = %d\n",
+				    ret);
+			goto out;
+		}
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+	} else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
+		ret = plat_priv->driver_ops->probe(pci_priv->pci_dev,
+						   pci_priv->pci_device_id);
+		if (ret) {
+			cnss_pr_err("Failed to probe host driver, err = %d\n",
+				    ret);
+			goto out;
+		}
+		clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+		set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+	}
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static int cnss_driver_call_remove(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
+	    test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Skip driver remove\n");
+		return 0;
+	}
+
+	if (!plat_priv->driver_ops) {
+		cnss_pr_err("driver_ops is NULL\n");
+		return -EINVAL;
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		plat_priv->driver_ops->shutdown(pci_priv->pci_dev);
+	} else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+		plat_priv->driver_ops->remove(pci_priv->pci_dev);
+		clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state);
+	}
+
+	return 0;
+}
+
+static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	del_timer(&plat_priv->fw_boot_timer);
+	set_bit(CNSS_FW_READY, &plat_priv->driver_state);
+
+	if (test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state)) {
+		clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+	}
+
+	if (enable_waltest) {
+		ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
+						    QMI_WLFW_WALTEST_V01);
+	} else if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) {
+		ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
+						    QMI_WLFW_CALIBRATION_V01);
+	} else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+		   test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		ret = cnss_driver_call_probe(plat_priv);
+	} else {
+		complete(&plat_priv->power_up_complete);
+	}
+
+	if (ret)
+		goto shutdown;
+
+	return 0;
+
+shutdown:
+	cnss_pci_stop_mhi(plat_priv->bus_priv);
+	cnss_suspend_pci_link(plat_priv->bus_priv);
+	cnss_power_off_device(plat_priv);
+
+	return ret;
+}
+
+static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
+{
+	switch (type) {
+	case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
+		return "SERVER_ARRIVE";
+	case CNSS_DRIVER_EVENT_SERVER_EXIT:
+		return "SERVER_EXIT";
+	case CNSS_DRIVER_EVENT_REQUEST_MEM:
+		return "REQUEST_MEM";
+	case CNSS_DRIVER_EVENT_FW_MEM_READY:
+		return "FW_MEM_READY";
+	case CNSS_DRIVER_EVENT_FW_READY:
+		return "FW_READY";
+	case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
+		return "COLD_BOOT_CAL_START";
+	case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
+		return "COLD_BOOT_CAL_DONE";
+	case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
+		return "REGISTER_DRIVER";
+	case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
+		return "UNREGISTER_DRIVER";
+	case CNSS_DRIVER_EVENT_RECOVERY:
+		return "RECOVERY";
+	case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
+		return "FORCE_FW_ASSERT";
+	case CNSS_DRIVER_EVENT_POWER_UP:
+		return "POWER_UP";
+	case CNSS_DRIVER_EVENT_POWER_DOWN:
+		return "POWER_DOWN";
+	case CNSS_DRIVER_EVENT_MAX:
+		return "EVENT_MAX";
+	}
+
+	return "UNKNOWN";
+};
+
+int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
+			   enum cnss_driver_event_type type,
+			   u32 flags, void *data)
+{
+	struct cnss_driver_event *event;
+	unsigned long irq_flags;
+	int gfp = GFP_KERNEL;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Posting event: %s(%d)%s, state: 0x%lx flags: 0x%0x\n",
+		    cnss_driver_event_to_str(type), type,
+		    flags ? "-sync" : "", plat_priv->driver_state, flags);
+
+	if (type >= CNSS_DRIVER_EVENT_MAX) {
+		cnss_pr_err("Invalid Event type: %d, can't post", type);
+		return -EINVAL;
+	}
+
+	if (in_interrupt() || irqs_disabled())
+		gfp = GFP_ATOMIC;
+
+	event = kzalloc(sizeof(*event), gfp);
+	if (!event)
+		return -ENOMEM;
+
+	cnss_pm_stay_awake(plat_priv);
+
+	event->type = type;
+	event->data = data;
+	init_completion(&event->complete);
+	event->ret = CNSS_EVENT_PENDING;
+	event->sync = !!(flags & CNSS_EVENT_SYNC);
+
+	spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
+	list_add_tail(&event->list, &plat_priv->event_list);
+	spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+
+	queue_work(plat_priv->event_wq, &plat_priv->event_work);
+
+	if (!(flags & CNSS_EVENT_SYNC))
+		goto out;
+
+	if (flags & CNSS_EVENT_UNINTERRUPTIBLE)
+		wait_for_completion(&event->complete);
+	else
+		ret = wait_for_completion_interruptible(&event->complete);
+
+	cnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n",
+		    cnss_driver_event_to_str(type), type,
+		    plat_priv->driver_state, ret, event->ret);
+	spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
+	if (ret == -ERESTARTSYS && event->ret == CNSS_EVENT_PENDING) {
+		event->sync = false;
+		spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+		ret = -EINTR;
+		goto out;
+	}
+	spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
+
+	ret = event->ret;
+	kfree(event);
+
+out:
+	cnss_pm_relax(plat_priv);
+	return ret;
+}
+
+int cnss_power_up(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	unsigned int timeout;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	cnss_pr_dbg("Powering up device\n");
+
+	ret = cnss_driver_event_post(plat_priv,
+				     CNSS_DRIVER_EVENT_POWER_UP,
+				     CNSS_EVENT_SYNC, NULL);
+	if (ret)
+		goto out;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		goto out;
+
+	timeout = cnss_get_qmi_timeout();
+
+	reinit_completion(&plat_priv->power_up_complete);
+	ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
+					  msecs_to_jiffies(timeout) << 2);
+	if (!ret) {
+		cnss_pr_err("Timeout waiting for power up to complete\n");
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	return 0;
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_power_up);
+
+int cnss_power_down(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	cnss_pr_dbg("Powering down device\n");
+
+	return cnss_driver_event_post(plat_priv,
+				      CNSS_DRIVER_EVENT_POWER_DOWN,
+				      CNSS_EVENT_SYNC, NULL);
+}
+EXPORT_SYMBOL(cnss_power_down);
+
+int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return -ENODEV;
+	}
+
+	if (plat_priv->driver_ops) {
+		cnss_pr_err("Driver has already registered!\n");
+		return -EEXIST;
+	}
+
+	ret = cnss_driver_event_post(plat_priv,
+				     CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+				     CNSS_EVENT_SYNC_UNINTERRUPTIBLE,
+				     driver_ops);
+	return ret;
+}
+EXPORT_SYMBOL(cnss_wlan_register_driver);
+
+void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver_ops)
+{
+	struct cnss_plat_data *plat_priv = cnss_get_plat_priv(NULL);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return;
+	}
+
+	cnss_driver_event_post(plat_priv,
+			       CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+			       CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(cnss_wlan_unregister_driver);
+
+static int cnss_get_resources(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	ret = cnss_get_vreg(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to get vreg, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = cnss_get_pinctrl(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to get pinctrl, err = %d\n", ret);
+		goto out;
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+static void cnss_put_resources(struct cnss_plat_data *plat_priv)
+{
+}
+
+static int cnss_modem_notifier_nb(struct notifier_block *nb,
+				  unsigned long code,
+				  void *ss_handle)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(nb, struct cnss_plat_data, modem_nb);
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+	struct cnss_esoc_info *esoc_info;
+	struct cnss_wlan_driver *driver_ops;
+
+	cnss_pr_dbg("Modem notifier: event %lu\n", code);
+
+	if (!pci_priv)
+		return NOTIFY_DONE;
+
+	esoc_info = &plat_priv->esoc_info;
+
+	if (code == SUBSYS_AFTER_POWERUP)
+		esoc_info->modem_current_status = 1;
+	else if (code == SUBSYS_BEFORE_SHUTDOWN)
+		esoc_info->modem_current_status = 0;
+	else
+		return NOTIFY_DONE;
+
+	driver_ops = plat_priv->driver_ops;
+	if (!driver_ops || !driver_ops->modem_status)
+		return NOTIFY_DONE;
+
+	driver_ops->modem_status(pci_priv->pci_dev,
+				 esoc_info->modem_current_status);
+
+	return NOTIFY_OK;
+}
+
+static int cnss_register_esoc(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct device *dev;
+	struct cnss_esoc_info *esoc_info;
+	struct esoc_desc *esoc_desc;
+	const char *client_desc;
+
+	dev = &plat_priv->plat_dev->dev;
+	esoc_info = &plat_priv->esoc_info;
+
+	esoc_info->notify_modem_status =
+		of_property_read_bool(dev->of_node,
+				      "qcom,notify-modem-status");
+
+	if (esoc_info->notify_modem_status)
+		goto out;
+
+	ret = of_property_read_string_index(dev->of_node, "esoc-names", 0,
+					    &client_desc);
+	if (ret) {
+		cnss_pr_dbg("esoc-names is not defined in DT, skip!\n");
+	} else {
+		esoc_desc = devm_register_esoc_client(dev, client_desc);
+		if (IS_ERR_OR_NULL(esoc_desc)) {
+			ret = PTR_RET(esoc_desc);
+			cnss_pr_err("Failed to register esoc_desc, err = %d\n",
+				    ret);
+			goto out;
+		}
+		esoc_info->esoc_desc = esoc_desc;
+	}
+
+	plat_priv->modem_nb.notifier_call = cnss_modem_notifier_nb;
+	esoc_info->modem_current_status = 0;
+	esoc_info->modem_notify_handler =
+		subsys_notif_register_notifier(esoc_info->esoc_desc ?
+					       esoc_info->esoc_desc->name :
+					       "modem", &plat_priv->modem_nb);
+	if (IS_ERR(esoc_info->modem_notify_handler)) {
+		ret = PTR_ERR(esoc_info->modem_notify_handler);
+		cnss_pr_err("Failed to register esoc notifier, err = %d\n",
+			    ret);
+		goto unreg_esoc;
+	}
+
+	return 0;
+unreg_esoc:
+	if (esoc_info->esoc_desc)
+		devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
+out:
+	return ret;
+}
+
+static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev;
+	struct cnss_esoc_info *esoc_info;
+
+	dev = &plat_priv->plat_dev->dev;
+	esoc_info = &plat_priv->esoc_info;
+
+	if (esoc_info->notify_modem_status)
+		subsys_notif_unregister_notifier(esoc_info->
+						 modem_notify_handler,
+						 &plat_priv->modem_nb);
+	if (esoc_info->esoc_desc)
+		devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
+}
+
+static int cnss_qca6174_powerup(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL!\n");
+		return -ENODEV;
+	}
+
+	ret = cnss_power_on_device(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to power on device, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = cnss_resume_pci_link(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+		goto power_off;
+	}
+
+	ret = cnss_driver_call_probe(plat_priv);
+	if (ret)
+		goto suspend_link;
+
+	return 0;
+suspend_link:
+	cnss_suspend_pci_link(pci_priv);
+power_off:
+	cnss_power_off_device(plat_priv);
+out:
+	return ret;
+}
+
+static int cnss_qca6174_shutdown(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	cnss_pm_request_resume(pci_priv);
+
+	cnss_driver_call_remove(plat_priv);
+
+	cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+				   CNSS_BUS_WIDTH_NONE);
+	cnss_pci_set_monitor_wake_intr(pci_priv, false);
+	cnss_pci_set_auto_suspended(pci_priv, 0);
+
+	ret = cnss_suspend_pci_link(pci_priv);
+	if (ret)
+		cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+
+	cnss_power_off_device(plat_priv);
+
+	clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+	return ret;
+}
+
+static void cnss_qca6174_crash_shutdown(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	if (!plat_priv->driver_ops)
+		return;
+
+	plat_priv->driver_ops->crash_shutdown(pci_priv->pci_dev);
+}
+
+static int cnss_qca6290_powerup(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+	unsigned int timeout;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL!\n");
+		return -ENODEV;
+	}
+
+	if (plat_priv->ramdump_info_v2.dump_data_valid ||
+	    test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+		cnss_pci_clear_dump_info(pci_priv);
+	}
+
+	ret = cnss_power_on_device(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to power on device, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = cnss_resume_pci_link(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
+		goto power_off;
+	}
+
+	timeout = cnss_get_qmi_timeout();
+
+	ret = cnss_pci_start_mhi(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to start MHI, err = %d\n", ret);
+		if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state) &&
+		    !pci_priv->pci_link_down_ind && timeout)
+			mod_timer(&plat_priv->fw_boot_timer,
+				  jiffies + msecs_to_jiffies(timeout >> 1));
+		return 0;
+	}
+
+	if (test_bit(USE_CORE_ONLY_FW, &quirks)) {
+		clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
+		clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+		return 0;
+	}
+
+	cnss_set_pin_connect_status(plat_priv);
+
+	if (qmi_bypass) {
+		ret = cnss_driver_call_probe(plat_priv);
+		if (ret)
+			goto stop_mhi;
+	} else if (timeout) {
+		mod_timer(&plat_priv->fw_boot_timer,
+			  jiffies + msecs_to_jiffies(timeout << 1));
+	}
+
+	return 0;
+
+stop_mhi:
+	cnss_pci_stop_mhi(pci_priv);
+	cnss_suspend_pci_link(pci_priv);
+power_off:
+	cnss_power_off_device(plat_priv);
+out:
+	return ret;
+}
+
+static int cnss_qca6290_shutdown(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	cnss_pm_request_resume(pci_priv);
+
+	cnss_driver_call_remove(plat_priv);
+
+	cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev,
+				   CNSS_BUS_WIDTH_NONE);
+	cnss_pci_set_monitor_wake_intr(pci_priv, false);
+	cnss_pci_set_auto_suspended(pci_priv, 0);
+
+	cnss_pci_stop_mhi(pci_priv);
+
+	ret = cnss_suspend_pci_link(pci_priv);
+	if (ret)
+		cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
+
+	cnss_power_off_device(plat_priv);
+
+	clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
+	clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
+	clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+
+	return ret;
+}
+
+static void cnss_qca6290_crash_shutdown(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+	int ret = 0;
+
+	cnss_pr_dbg("Crash shutdown with driver_state 0x%lx\n",
+		    plat_priv->driver_state);
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
+	    test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state))
+		return;
+
+	ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM_KERNEL_PANIC);
+	if (ret) {
+		cnss_pr_err("Fail to complete RDDM, err = %d\n", ret);
+		return;
+	}
+
+	cnss_pci_collect_dump_info(pci_priv);
+}
+
+static int cnss_powerup(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		ret = cnss_qca6174_powerup(plat_priv);
+		break;
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		ret = cnss_qca6290_powerup(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device_id found: 0x%lx\n",
+			    plat_priv->device_id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int cnss_shutdown(struct cnss_plat_data *plat_priv)
+{
+	int ret;
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		ret = cnss_qca6174_shutdown(plat_priv);
+		break;
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		ret = cnss_qca6290_shutdown(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device_id found: 0x%lx\n",
+			    plat_priv->device_id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!subsys_desc->dev) {
+		cnss_pr_err("dev from subsys_desc is NULL\n");
+		return -ENODEV;
+	}
+
+	plat_priv = dev_get_drvdata(subsys_desc->dev);
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (!plat_priv->driver_state) {
+		cnss_pr_dbg("Powerup is ignored\n");
+		return 0;
+	}
+
+	return cnss_powerup(plat_priv);
+}
+
+static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
+				bool force_stop)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!subsys_desc->dev) {
+		cnss_pr_err("dev from subsys_desc is NULL\n");
+		return -ENODEV;
+	}
+
+	plat_priv = dev_get_drvdata(subsys_desc->dev);
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (!plat_priv->driver_state) {
+		cnss_pr_dbg("shutdown is ignored\n");
+		return 0;
+	}
+
+	return cnss_shutdown(plat_priv);
+}
+
+static int cnss_qca6290_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info_v2 *info_v2 = &plat_priv->ramdump_info_v2;
+	struct cnss_dump_data *dump_data = &info_v2->dump_data;
+	struct cnss_dump_seg *dump_seg = info_v2->dump_data_vaddr;
+	struct ramdump_segment *ramdump_segs, *s;
+	int i, ret = 0;
+
+	if (!info_v2->dump_data_valid ||
+	    dump_data->nentries == 0)
+		return 0;
+
+	ramdump_segs = kcalloc(dump_data->nentries,
+			       sizeof(*ramdump_segs),
+			       GFP_KERNEL);
+	if (!ramdump_segs)
+		return -ENOMEM;
+
+	s = ramdump_segs;
+	for (i = 0; i < dump_data->nentries; i++) {
+		s->address = dump_seg->address;
+		s->v_address = dump_seg->v_address;
+		s->size = dump_seg->size;
+		s++;
+		dump_seg++;
+	}
+
+	ret = do_elf_ramdump(info_v2->ramdump_dev, ramdump_segs,
+			     dump_data->nentries);
+	kfree(ramdump_segs);
+
+	cnss_pci_set_mhi_state(plat_priv->bus_priv, CNSS_MHI_DEINIT);
+	cnss_pci_clear_dump_info(plat_priv->bus_priv);
+
+	return ret;
+}
+
+static int cnss_qca6174_ramdump(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_ramdump_info *ramdump_info;
+	struct ramdump_segment segment;
+
+	ramdump_info = &plat_priv->ramdump_info;
+	if (!ramdump_info->ramdump_size)
+		return -EINVAL;
+
+	memset(&segment, 0, sizeof(segment));
+	segment.v_address = ramdump_info->ramdump_va;
+	segment.size = ramdump_info->ramdump_size;
+	ret = do_ramdump(ramdump_info->ramdump_dev, &segment, 1);
+
+	return ret;
+}
+
+static int cnss_subsys_ramdump(int enable,
+			       const struct subsys_desc *subsys_desc)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return -ENODEV;
+	}
+
+	if (!enable)
+		return 0;
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		ret = cnss_qca6174_ramdump(plat_priv);
+		break;
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		ret = cnss_qca6290_ramdump(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device_id found: 0x%lx\n",
+			    plat_priv->device_id);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_ramdump_info *ramdump_info;
+
+	if (!plat_priv)
+		return NULL;
+
+	ramdump_info = &plat_priv->ramdump_info;
+	*size = ramdump_info->ramdump_size;
+
+	return ramdump_info->ramdump_va;
+}
+EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
+
+void cnss_device_crashed(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_subsys_info *subsys_info;
+
+	if (!plat_priv)
+		return;
+
+	subsys_info = &plat_priv->subsys_info;
+	if (subsys_info->subsys_device) {
+		set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+		subsys_set_crash_status(subsys_info->subsys_device, true);
+		subsystem_restart_dev(subsys_info->subsys_device);
+	}
+}
+EXPORT_SYMBOL(cnss_device_crashed);
+
+static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc)
+{
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return;
+	}
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		cnss_qca6174_crash_shutdown(plat_priv);
+		break;
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		cnss_qca6290_crash_shutdown(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device_id found: 0x%lx\n",
+			    plat_priv->device_id);
+	}
+}
+
+static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
+{
+	switch (reason) {
+	case CNSS_REASON_DEFAULT:
+		return "DEFAULT";
+	case CNSS_REASON_LINK_DOWN:
+		return "LINK_DOWN";
+	case CNSS_REASON_RDDM:
+		return "RDDM";
+	case CNSS_REASON_TIMEOUT:
+		return "TIMEOUT";
+	}
+
+	return "UNKNOWN";
+};
+
+static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
+			    enum cnss_recovery_reason reason)
+{
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+	struct cnss_subsys_info *subsys_info =
+		&plat_priv->subsys_info;
+	int ret = 0;
+
+	plat_priv->recovery_count++;
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID)
+		goto self_recovery;
+
+	if (plat_priv->driver_ops &&
+	    test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state))
+		plat_priv->driver_ops->update_status(pci_priv->pci_dev,
+						     CNSS_RECOVERY);
+
+	if (test_bit(SKIP_RECOVERY, &quirks)) {
+		cnss_pr_dbg("Skip device recovery\n");
+		return 0;
+	}
+
+	switch (reason) {
+	case CNSS_REASON_LINK_DOWN:
+		if (test_bit(LINK_DOWN_SELF_RECOVERY, &quirks))
+			goto self_recovery;
+		break;
+	case CNSS_REASON_RDDM:
+		clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+		ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RDDM);
+		if (ret) {
+			cnss_pr_err("Failed to complete RDDM, err = %d\n", ret);
+			break;
+		}
+		cnss_pci_collect_dump_info(pci_priv);
+		break;
+	case CNSS_REASON_DEFAULT:
+	case CNSS_REASON_TIMEOUT:
+		break;
+	default:
+		cnss_pr_err("Unsupported recovery reason: %s(%d)\n",
+			    cnss_recovery_reason_to_str(reason), reason);
+		break;
+	}
+
+	if (!subsys_info->subsys_device)
+		return 0;
+
+	subsys_set_crash_status(subsys_info->subsys_device, true);
+	subsystem_restart_dev(subsys_info->subsys_device);
+
+	return 0;
+
+self_recovery:
+	cnss_shutdown(plat_priv);
+	cnss_powerup(plat_priv);
+
+	return 0;
+}
+
+static int cnss_driver_recovery_hdlr(struct cnss_plat_data *plat_priv,
+				     void *data)
+{
+	struct cnss_recovery_data *recovery_data = data;
+	int ret = 0;
+
+	cnss_pr_dbg("Driver recovery is triggered with reason: %s(%d)\n",
+		    cnss_recovery_reason_to_str(recovery_data->reason),
+		    recovery_data->reason);
+
+	if (!plat_priv->driver_state) {
+		cnss_pr_err("Improper driver state, ignore recovery\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		cnss_pr_err("Recovery is already in progress\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
+		cnss_pr_err("Driver unload is in progress, ignore recovery\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
+			cnss_pr_err("Driver load is in progress, ignore recovery\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		break;
+	default:
+		if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
+			set_bit(CNSS_FW_BOOT_RECOVERY,
+				&plat_priv->driver_state);
+		} else if (test_bit(CNSS_DRIVER_LOADING,
+			   &plat_priv->driver_state)) {
+			cnss_pr_err("Driver probe is in progress, ignore recovery\n");
+			ret = -EINVAL;
+			goto out;
+		}
+		break;
+	}
+
+	set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
+	ret = cnss_do_recovery(plat_priv, recovery_data->reason);
+
+out:
+	kfree(data);
+	return ret;
+}
+
+int cnss_self_recovery(struct device *dev,
+		       enum cnss_recovery_reason reason)
+{
+	cnss_schedule_recovery(dev, reason);
+	return 0;
+}
+EXPORT_SYMBOL(cnss_self_recovery);
+
+void cnss_schedule_recovery(struct device *dev,
+			    enum cnss_recovery_reason reason)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_recovery_data *data;
+	int gfp = GFP_KERNEL;
+
+	if (in_interrupt() || irqs_disabled())
+		gfp = GFP_ATOMIC;
+
+	data = kzalloc(sizeof(*data), gfp);
+	if (!data)
+		return;
+
+	data->reason = reason;
+	cnss_driver_event_post(plat_priv,
+			       CNSS_DRIVER_EVENT_RECOVERY,
+			       0, data);
+}
+EXPORT_SYMBOL(cnss_schedule_recovery);
+
+static int cnss_force_fw_assert_hdlr(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+	int ret;
+
+	ret = cnss_pci_set_mhi_state(plat_priv->bus_priv,
+				     CNSS_MHI_TRIGGER_RDDM);
+	if (ret) {
+		cnss_pr_err("Failed to trigger RDDM, err = %d\n", ret);
+		cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+				       CNSS_REASON_DEFAULT);
+		return 0;
+	}
+
+	if (!test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) {
+		mod_timer(&plat_priv->fw_boot_timer,
+			  jiffies + msecs_to_jiffies(FW_ASSERT_TIMEOUT));
+	}
+
+	return 0;
+}
+
+int cnss_force_fw_assert(struct device *dev)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL\n");
+		return -ENODEV;
+	}
+
+	if (plat_priv->device_id == QCA6174_DEVICE_ID) {
+		cnss_pr_info("Forced FW assert is not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		cnss_pr_info("Recovery is already in progress, ignore forced FW assert\n");
+		return 0;
+	}
+
+	cnss_driver_event_post(plat_priv,
+			       CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
+			       0, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_force_fw_assert);
+
+void fw_boot_timeout(unsigned long data)
+{
+	struct cnss_plat_data *plat_priv = (struct cnss_plat_data *)data;
+	struct cnss_pci_data *pci_priv = plat_priv->bus_priv;
+
+	cnss_pr_err("Timeout waiting for FW ready indication!\n");
+
+	cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+			       CNSS_REASON_TIMEOUT);
+}
+
+static int cnss_register_driver_hdlr(struct cnss_plat_data *plat_priv,
+				     void *data)
+{
+	int ret = 0;
+
+	set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+	plat_priv->driver_ops = data;
+
+	ret = cnss_powerup(plat_priv);
+	if (ret) {
+		clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state);
+		plat_priv->driver_ops = NULL;
+	}
+
+	return ret;
+}
+
+static int cnss_unregister_driver_hdlr(struct cnss_plat_data *plat_priv)
+{
+	set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state);
+	cnss_shutdown(plat_priv);
+	plat_priv->driver_ops = NULL;
+
+	return 0;
+}
+
+static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
+	ret = cnss_powerup(plat_priv);
+	if (ret)
+		clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
+
+	return ret;
+}
+
+static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
+{
+	cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
+	cnss_shutdown(plat_priv);
+	clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
+
+	return 0;
+}
+
+static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
+{
+	return cnss_powerup(plat_priv);
+}
+
+static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
+{
+	cnss_shutdown(plat_priv);
+
+	return 0;
+}
+
+static void cnss_driver_event_work(struct work_struct *work)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(work, struct cnss_plat_data, event_work);
+	struct cnss_driver_event *event;
+	unsigned long flags;
+	int ret = 0;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return;
+	}
+
+	cnss_pm_stay_awake(plat_priv);
+
+	spin_lock_irqsave(&plat_priv->event_lock, flags);
+
+	while (!list_empty(&plat_priv->event_list)) {
+		event = list_first_entry(&plat_priv->event_list,
+					 struct cnss_driver_event, list);
+		list_del(&event->list);
+		spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+		cnss_pr_dbg("Processing driver event: %s%s(%d), state: 0x%lx\n",
+			    cnss_driver_event_to_str(event->type),
+			    event->sync ? "-sync" : "", event->type,
+			    plat_priv->driver_state);
+
+		switch (event->type) {
+		case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
+			ret = cnss_wlfw_server_arrive(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_SERVER_EXIT:
+			ret = cnss_wlfw_server_exit(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_REQUEST_MEM:
+			ret = cnss_pci_alloc_fw_mem(plat_priv->bus_priv);
+			if (ret)
+				break;
+			ret = cnss_wlfw_respond_mem_send_sync(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_FW_MEM_READY:
+			ret = cnss_fw_mem_ready_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_FW_READY:
+			ret = cnss_fw_ready_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
+			ret = cnss_cold_boot_cal_start_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
+			ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
+			ret = cnss_register_driver_hdlr(plat_priv,
+							event->data);
+			break;
+		case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
+			ret = cnss_unregister_driver_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_RECOVERY:
+			ret = cnss_driver_recovery_hdlr(plat_priv,
+							event->data);
+			break;
+		case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
+			ret = cnss_force_fw_assert_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_POWER_UP:
+			ret = cnss_power_up_hdlr(plat_priv);
+			break;
+		case CNSS_DRIVER_EVENT_POWER_DOWN:
+			ret = cnss_power_down_hdlr(plat_priv);
+			break;
+		default:
+			cnss_pr_err("Invalid driver event type: %d",
+				    event->type);
+			kfree(event);
+			spin_lock_irqsave(&plat_priv->event_lock, flags);
+			continue;
+		}
+
+		spin_lock_irqsave(&plat_priv->event_lock, flags);
+		if (event->sync) {
+			event->ret = ret;
+			complete(&event->complete);
+			continue;
+		}
+		spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+		kfree(event);
+
+		spin_lock_irqsave(&plat_priv->event_lock, flags);
+	}
+	spin_unlock_irqrestore(&plat_priv->event_lock, flags);
+
+	cnss_pm_relax(plat_priv);
+}
+
+int cnss_register_subsys(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_subsys_info *subsys_info;
+
+	subsys_info = &plat_priv->subsys_info;
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		subsys_info->subsys_desc.name = "AR6320";
+		break;
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		subsys_info->subsys_desc.name = "QCA6290";
+		break;
+	default:
+		cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
+		ret = -ENODEV;
+		goto out;
+	}
+
+	subsys_info->subsys_desc.owner = THIS_MODULE;
+	subsys_info->subsys_desc.powerup = cnss_subsys_powerup;
+	subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown;
+	subsys_info->subsys_desc.ramdump = cnss_subsys_ramdump;
+	subsys_info->subsys_desc.crash_shutdown = cnss_subsys_crash_shutdown;
+	subsys_info->subsys_desc.dev = &plat_priv->plat_dev->dev;
+
+	subsys_info->subsys_device = subsys_register(&subsys_info->subsys_desc);
+	if (IS_ERR(subsys_info->subsys_device)) {
+		ret = PTR_ERR(subsys_info->subsys_device);
+		cnss_pr_err("Failed to register subsys, err = %d\n", ret);
+		goto out;
+	}
+
+	subsys_info->subsys_handle =
+		subsystem_get(subsys_info->subsys_desc.name);
+	if (!subsys_info->subsys_handle) {
+		cnss_pr_err("Failed to get subsys_handle!\n");
+		ret = -EINVAL;
+		goto unregister_subsys;
+	} else if (IS_ERR(subsys_info->subsys_handle)) {
+		ret = PTR_ERR(subsys_info->subsys_handle);
+		cnss_pr_err("Failed to do subsystem_get, err = %d\n", ret);
+		goto unregister_subsys;
+	}
+
+	return 0;
+
+unregister_subsys:
+	subsys_unregister(subsys_info->subsys_device);
+out:
+	return ret;
+}
+
+void cnss_unregister_subsys(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_subsys_info *subsys_info;
+
+	subsys_info = &plat_priv->subsys_info;
+	subsystem_put(subsys_info->subsys_handle);
+	subsys_unregister(subsys_info->subsys_device);
+}
+
+static int cnss_init_dump_entry(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info *ramdump_info;
+	struct msm_dump_entry dump_entry;
+
+	ramdump_info = &plat_priv->ramdump_info;
+	ramdump_info->dump_data.addr = ramdump_info->ramdump_pa;
+	ramdump_info->dump_data.len = ramdump_info->ramdump_size;
+	ramdump_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
+	ramdump_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
+	strlcpy(ramdump_info->dump_data.name, CNSS_DUMP_NAME,
+		sizeof(ramdump_info->dump_data.name));
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(&ramdump_info->dump_data);
+
+	return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+}
+
+static int cnss_qca6174_register_ramdump(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct device *dev;
+	struct cnss_subsys_info *subsys_info;
+	struct cnss_ramdump_info *ramdump_info;
+	u32 ramdump_size = 0;
+
+	dev = &plat_priv->plat_dev->dev;
+	subsys_info = &plat_priv->subsys_info;
+	ramdump_info = &plat_priv->ramdump_info;
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0) {
+		ramdump_info->ramdump_va = dma_alloc_coherent(dev, ramdump_size,
+			&ramdump_info->ramdump_pa, GFP_KERNEL);
+
+		if (ramdump_info->ramdump_va)
+			ramdump_info->ramdump_size = ramdump_size;
+	}
+
+	cnss_pr_dbg("ramdump va: %pK, pa: %pa\n",
+		    ramdump_info->ramdump_va, &ramdump_info->ramdump_pa);
+
+	if (ramdump_info->ramdump_size == 0) {
+		cnss_pr_info("Ramdump will not be collected");
+		goto out;
+	}
+
+	ret = cnss_init_dump_entry(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
+		goto free_ramdump;
+	}
+
+	ramdump_info->ramdump_dev = create_ramdump_device(
+		subsys_info->subsys_desc.name, subsys_info->subsys_desc.dev);
+	if (!ramdump_info->ramdump_dev) {
+		cnss_pr_err("Failed to create ramdump device!");
+		ret = -ENOMEM;
+		goto free_ramdump;
+	}
+
+	return 0;
+free_ramdump:
+	dma_free_coherent(dev, ramdump_info->ramdump_size,
+			  ramdump_info->ramdump_va, ramdump_info->ramdump_pa);
+out:
+	return ret;
+}
+
+static void cnss_qca6174_unregister_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct device *dev;
+	struct cnss_ramdump_info *ramdump_info;
+
+	dev = &plat_priv->plat_dev->dev;
+	ramdump_info = &plat_priv->ramdump_info;
+
+	if (ramdump_info->ramdump_dev)
+		destroy_ramdump_device(ramdump_info->ramdump_dev);
+
+	if (ramdump_info->ramdump_va)
+		dma_free_coherent(dev, ramdump_info->ramdump_size,
+				  ramdump_info->ramdump_va,
+				  ramdump_info->ramdump_pa);
+}
+
+static int cnss_qca6290_register_ramdump(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_subsys_info *subsys_info;
+	struct cnss_ramdump_info_v2 *info_v2;
+	struct cnss_dump_data *dump_data;
+	struct msm_dump_entry dump_entry;
+	struct device *dev = &plat_priv->plat_dev->dev;
+	u32 ramdump_size = 0;
+
+	subsys_info = &plat_priv->subsys_info;
+	info_v2 = &plat_priv->ramdump_info_v2;
+	dump_data = &info_v2->dump_data;
+
+	if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
+				 &ramdump_size) == 0)
+		info_v2->ramdump_size = ramdump_size;
+
+	cnss_pr_dbg("Ramdump size 0x%lx\n", info_v2->ramdump_size);
+
+	info_v2->dump_data_vaddr = kzalloc(CNSS_DUMP_DESC_SIZE, GFP_KERNEL);
+	if (!info_v2->dump_data_vaddr)
+		return -ENOMEM;
+
+	dump_data->paddr = virt_to_phys(info_v2->dump_data_vaddr);
+	dump_data->version = CNSS_DUMP_FORMAT_VER_V2;
+	dump_data->magic = CNSS_DUMP_MAGIC_VER_V2;
+	dump_data->seg_version = CNSS_DUMP_SEG_VER;
+	strlcpy(dump_data->name, CNSS_DUMP_NAME,
+		sizeof(dump_data->name));
+	dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
+	dump_entry.addr = virt_to_phys(dump_data);
+
+	ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
+	if (ret) {
+		cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
+		goto free_ramdump;
+	}
+
+	info_v2->ramdump_dev =
+		create_ramdump_device(subsys_info->subsys_desc.name,
+				      subsys_info->subsys_desc.dev);
+	if (!info_v2->ramdump_dev) {
+		cnss_pr_err("Failed to create ramdump device!\n");
+		ret = -ENOMEM;
+		goto free_ramdump;
+	}
+
+	return 0;
+
+free_ramdump:
+	kfree(info_v2->dump_data_vaddr);
+	info_v2->dump_data_vaddr = NULL;
+	return ret;
+}
+
+static void cnss_qca6290_unregister_ramdump(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_ramdump_info_v2 *info_v2;
+
+	info_v2 = &plat_priv->ramdump_info_v2;
+
+	if (info_v2->ramdump_dev)
+		destroy_ramdump_device(info_v2->ramdump_dev);
+
+	kfree(info_v2->dump_data_vaddr);
+	info_v2->dump_data_vaddr = NULL;
+	info_v2->dump_data_valid = false;
+}
+
+int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		ret = cnss_qca6174_register_ramdump(plat_priv);
+		break;
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		ret = cnss_qca6290_register_ramdump(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
+		ret = -ENODEV;
+		break;
+	}
+	return ret;
+}
+
+void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
+{
+	switch (plat_priv->device_id) {
+	case QCA6174_DEVICE_ID:
+		cnss_qca6174_unregister_ramdump(plat_priv);
+		break;
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		cnss_qca6290_unregister_ramdump(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
+		break;
+	}
+}
+
+static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_bus_bw_info *bus_bw_info;
+
+	bus_bw_info = &plat_priv->bus_bw_info;
+
+	bus_bw_info->bus_scale_table =
+		msm_bus_cl_get_pdata(plat_priv->plat_dev);
+	if (bus_bw_info->bus_scale_table)  {
+		bus_bw_info->bus_client =
+			msm_bus_scale_register_client(
+				bus_bw_info->bus_scale_table);
+		if (!bus_bw_info->bus_client) {
+			cnss_pr_err("Failed to register bus scale client!\n");
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv)
+{
+	struct cnss_bus_bw_info *bus_bw_info;
+
+	bus_bw_info = &plat_priv->bus_bw_info;
+
+	if (bus_bw_info->bus_client)
+		msm_bus_scale_unregister_client(bus_bw_info->bus_client);
+}
+
+static ssize_t cnss_fs_ready_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf,
+				   size_t count)
+{
+	int fs_ready = 0;
+	struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
+
+	if (sscanf(buf, "%du", &fs_ready) != 1)
+		return -EINVAL;
+
+	cnss_pr_dbg("File system is ready, fs_ready is %d, count is %zu\n",
+		    fs_ready, count);
+
+	if (qmi_bypass) {
+		cnss_pr_dbg("QMI is bypassed.\n");
+		return count;
+	}
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return count;
+	}
+
+	switch (plat_priv->device_id) {
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		break;
+	default:
+		cnss_pr_err("Not supported for device ID 0x%lx\n",
+			    plat_priv->device_id);
+		return count;
+	}
+
+	if (fs_ready == FILE_SYSTEM_READY) {
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
+				       CNSS_EVENT_SYNC, NULL);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(fs_ready, 0220, NULL, cnss_fs_ready_store);
+
+static int cnss_create_sysfs(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	ret = device_create_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
+	if (ret) {
+		cnss_pr_err("Failed to create device file, err = %d\n", ret);
+		goto out;
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv)
+{
+	device_remove_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
+}
+
+static int cnss_event_work_init(struct cnss_plat_data *plat_priv)
+{
+	spin_lock_init(&plat_priv->event_lock);
+	plat_priv->event_wq = alloc_workqueue("cnss_driver_event",
+					      WQ_UNBOUND, 1);
+	if (!plat_priv->event_wq) {
+		cnss_pr_err("Failed to create event workqueue!\n");
+		return -EFAULT;
+	}
+
+	INIT_WORK(&plat_priv->event_work, cnss_driver_event_work);
+	INIT_LIST_HEAD(&plat_priv->event_list);
+
+	return 0;
+}
+
+static void cnss_event_work_deinit(struct cnss_plat_data *plat_priv)
+{
+	destroy_workqueue(plat_priv->event_wq);
+}
+
+static const struct platform_device_id cnss_platform_id_table[] = {
+	{ .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
+	{ .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
+};
+
+static const struct of_device_id cnss_of_match_table[] = {
+	{
+		.compatible = "qcom,cnss",
+		.data = (void *)&cnss_platform_id_table[0]},
+	{
+		.compatible = "qcom,cnss-qca6290",
+		.data = (void *)&cnss_platform_id_table[1]},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, cnss_of_match_table);
+
+static int cnss_probe(struct platform_device *plat_dev)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv;
+	const struct of_device_id *of_id;
+	const struct platform_device_id *device_id;
+
+	if (cnss_get_plat_priv(plat_dev)) {
+		cnss_pr_err("Driver is already initialized!\n");
+		ret = -EEXIST;
+		goto out;
+	}
+
+	of_id = of_match_device(cnss_of_match_table, &plat_dev->dev);
+	if (!of_id || !of_id->data) {
+		cnss_pr_err("Failed to find of match device!\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	device_id = of_id->data;
+
+	plat_priv = devm_kzalloc(&plat_dev->dev, sizeof(*plat_priv),
+				 GFP_KERNEL);
+	if (!plat_priv) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	plat_priv->plat_dev = plat_dev;
+	plat_priv->device_id = device_id->driver_data;
+	cnss_set_plat_priv(plat_dev, plat_priv);
+	platform_set_drvdata(plat_dev, plat_priv);
+
+	ret = cnss_get_resources(plat_priv);
+	if (ret)
+		goto reset_ctx;
+
+	if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) {
+		ret = cnss_power_on_device(plat_priv);
+		if (ret)
+			goto free_res;
+
+		ret = cnss_pci_init(plat_priv);
+		if (ret)
+			goto power_off;
+	}
+
+	ret = cnss_register_esoc(plat_priv);
+	if (ret)
+		goto deinit_pci;
+
+	ret = cnss_register_bus_scale(plat_priv);
+	if (ret)
+		goto unreg_esoc;
+
+	ret = cnss_create_sysfs(plat_priv);
+	if (ret)
+		goto unreg_bus_scale;
+
+	ret = cnss_event_work_init(plat_priv);
+	if (ret)
+		goto remove_sysfs;
+
+	ret = cnss_qmi_init(plat_priv);
+	if (ret)
+		goto deinit_event_work;
+
+	ret = cnss_debugfs_create(plat_priv);
+	if (ret)
+		goto deinit_qmi;
+
+	setup_timer(&plat_priv->fw_boot_timer,
+		    fw_boot_timeout, (unsigned long)plat_priv);
+
+	register_pm_notifier(&cnss_pm_notifier);
+
+	ret = device_init_wakeup(&plat_dev->dev, true);
+	if (ret)
+		cnss_pr_err("Failed to init platform device wakeup source, err = %d\n",
+			    ret);
+
+	init_completion(&plat_priv->power_up_complete);
+	mutex_init(&plat_priv->dev_lock);
+
+	cnss_pr_info("Platform driver probed successfully.\n");
+
+	return 0;
+
+deinit_qmi:
+	cnss_qmi_deinit(plat_priv);
+deinit_event_work:
+	cnss_event_work_deinit(plat_priv);
+remove_sysfs:
+	cnss_remove_sysfs(plat_priv);
+unreg_bus_scale:
+	cnss_unregister_bus_scale(plat_priv);
+unreg_esoc:
+	cnss_unregister_esoc(plat_priv);
+deinit_pci:
+	if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
+		cnss_pci_deinit(plat_priv);
+power_off:
+	if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
+		cnss_power_off_device(plat_priv);
+free_res:
+	cnss_put_resources(plat_priv);
+reset_ctx:
+	platform_set_drvdata(plat_dev, NULL);
+	cnss_set_plat_priv(plat_dev, NULL);
+out:
+	return ret;
+}
+
+static int cnss_remove(struct platform_device *plat_dev)
+{
+	struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev);
+
+	complete_all(&plat_priv->power_up_complete);
+	device_init_wakeup(&plat_dev->dev, false);
+	unregister_pm_notifier(&cnss_pm_notifier);
+	del_timer(&plat_priv->fw_boot_timer);
+	cnss_debugfs_destroy(plat_priv);
+	cnss_qmi_deinit(plat_priv);
+	cnss_event_work_deinit(plat_priv);
+	cnss_remove_sysfs(plat_priv);
+	cnss_unregister_bus_scale(plat_priv);
+	cnss_unregister_esoc(plat_priv);
+	cnss_pci_deinit(plat_priv);
+	cnss_put_resources(plat_priv);
+	platform_set_drvdata(plat_dev, NULL);
+	plat_env = NULL;
+
+	return 0;
+}
+
+static struct platform_driver cnss_platform_driver = {
+	.probe  = cnss_probe,
+	.remove = cnss_remove,
+	.driver = {
+		.name = "cnss2",
+		.owner = THIS_MODULE,
+		.of_match_table = cnss_of_match_table,
+#ifdef CONFIG_CNSS_ASYNC
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+#endif
+	},
+};
+
+static int __init cnss_initialize(void)
+{
+	int ret = 0;
+
+	cnss_debug_init();
+	ret = platform_driver_register(&cnss_platform_driver);
+	if (ret)
+		cnss_debug_deinit();
+
+	return ret;
+}
+
+static void __exit cnss_exit(void)
+{
+	platform_driver_unregister(&cnss_platform_driver);
+	cnss_debug_deinit();
+}
+
+module_init(cnss_initialize);
+module_exit(cnss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS2 Platform Driver");
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
new file mode 100644
index 0000000..81b5de8
--- /dev/null
+++ b/drivers/net/wireless/cnss2/main.h
@@ -0,0 +1,225 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CNSS_MAIN_H
+#define _CNSS_MAIN_H
+
+#include <linux/esoc_client.h>
+#include <linux/etherdevice.h>
+#include <linux/msm-bus.h>
+#include <linux/pm_qos.h>
+#include <net/cnss2.h>
+#include <soc/qcom/memory_dump.h>
+#include <soc/qcom/subsystem_restart.h>
+
+#include "qmi.h"
+
+#define MAX_NO_OF_MAC_ADDR		4
+
+#define CNSS_EVENT_SYNC   BIT(0)
+#define CNSS_EVENT_UNINTERRUPTIBLE BIT(1)
+#define CNSS_EVENT_SYNC_UNINTERRUPTIBLE (CNSS_EVENT_SYNC | \
+				CNSS_EVENT_UNINTERRUPTIBLE)
+
+enum cnss_dev_bus_type {
+	CNSS_BUS_NONE = -1,
+	CNSS_BUS_PCI,
+};
+
+struct cnss_vreg_info {
+	struct regulator *reg;
+	const char *name;
+	u32 min_uv;
+	u32 max_uv;
+	u32 load_ua;
+	u32 delay_us;
+};
+
+struct cnss_pinctrl_info {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *bootstrap_active;
+	struct pinctrl_state *wlan_en_active;
+	struct pinctrl_state *wlan_en_sleep;
+};
+
+struct cnss_subsys_info {
+	struct subsys_device *subsys_device;
+	struct subsys_desc subsys_desc;
+	void *subsys_handle;
+};
+
+struct cnss_ramdump_info {
+	struct ramdump_device *ramdump_dev;
+	unsigned long ramdump_size;
+	void *ramdump_va;
+	phys_addr_t ramdump_pa;
+	struct msm_dump_data dump_data;
+};
+
+struct cnss_dump_seg {
+	unsigned long address;
+	void *v_address;
+	unsigned long size;
+	u32 type;
+};
+
+struct cnss_dump_data {
+	u32 version;
+	u32 magic;
+	char name[32];
+	phys_addr_t paddr;
+	int nentries;
+	u32 seg_version;
+};
+
+struct cnss_ramdump_info_v2 {
+	struct ramdump_device *ramdump_dev;
+	unsigned long ramdump_size;
+	void *dump_data_vaddr;
+	bool dump_data_valid;
+	struct cnss_dump_data dump_data;
+};
+
+struct cnss_esoc_info {
+	struct esoc_desc *esoc_desc;
+	bool notify_modem_status;
+	void *modem_notify_handler;
+	int modem_current_status;
+};
+
+struct cnss_bus_bw_info {
+	struct msm_bus_scale_pdata *bus_scale_table;
+	u32 bus_client;
+	int current_bw_vote;
+};
+
+struct cnss_fw_mem {
+	size_t size;
+	void *va;
+	phys_addr_t pa;
+	bool valid;
+};
+
+enum cnss_driver_event_type {
+	CNSS_DRIVER_EVENT_SERVER_ARRIVE,
+	CNSS_DRIVER_EVENT_SERVER_EXIT,
+	CNSS_DRIVER_EVENT_REQUEST_MEM,
+	CNSS_DRIVER_EVENT_FW_MEM_READY,
+	CNSS_DRIVER_EVENT_FW_READY,
+	CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
+	CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
+	CNSS_DRIVER_EVENT_REGISTER_DRIVER,
+	CNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
+	CNSS_DRIVER_EVENT_RECOVERY,
+	CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
+	CNSS_DRIVER_EVENT_POWER_UP,
+	CNSS_DRIVER_EVENT_POWER_DOWN,
+	CNSS_DRIVER_EVENT_MAX,
+};
+
+enum cnss_driver_state {
+	CNSS_QMI_WLFW_CONNECTED,
+	CNSS_FW_MEM_READY,
+	CNSS_FW_READY,
+	CNSS_COLD_BOOT_CAL,
+	CNSS_DRIVER_LOADING,
+	CNSS_DRIVER_UNLOADING,
+	CNSS_DRIVER_PROBED,
+	CNSS_DRIVER_RECOVERY,
+	CNSS_FW_BOOT_RECOVERY,
+	CNSS_DEV_ERR_NOTIFY,
+	CNSS_DRIVER_DEBUG,
+};
+
+struct cnss_recovery_data {
+	enum cnss_recovery_reason reason;
+};
+
+enum cnss_pins {
+	CNSS_WLAN_EN,
+	CNSS_PCIE_TXP,
+	CNSS_PCIE_TXN,
+	CNSS_PCIE_RXP,
+	CNSS_PCIE_RXN,
+	CNSS_PCIE_REFCLKP,
+	CNSS_PCIE_REFCLKN,
+	CNSS_PCIE_RST,
+	CNSS_PCIE_WAKE,
+};
+
+struct cnss_pin_connect_result {
+	u32 fw_pwr_pin_result;
+	u32 fw_phy_io_pin_result;
+	u32 fw_rf_pin_result;
+	u32 host_pin_result;
+};
+
+struct cnss_plat_data {
+	struct platform_device *plat_dev;
+	void *bus_priv;
+	struct cnss_vreg_info *vreg_info;
+	struct cnss_pinctrl_info pinctrl_info;
+	struct cnss_subsys_info subsys_info;
+	struct cnss_ramdump_info ramdump_info;
+	struct cnss_ramdump_info_v2 ramdump_info_v2;
+	struct cnss_esoc_info esoc_info;
+	struct cnss_bus_bw_info bus_bw_info;
+	struct notifier_block modem_nb;
+	struct cnss_platform_cap cap;
+	struct pm_qos_request qos_request;
+	unsigned long device_id;
+	struct cnss_wlan_driver *driver_ops;
+	enum cnss_driver_status driver_status;
+	u32 recovery_count;
+	unsigned long driver_state;
+	struct list_head event_list;
+	spinlock_t event_lock; /* spinlock for driver work event handling */
+	struct work_struct event_work;
+	struct workqueue_struct *event_wq;
+	struct qmi_handle *qmi_wlfw_clnt;
+	struct work_struct qmi_recv_msg_work;
+	struct notifier_block qmi_wlfw_clnt_nb;
+	struct wlfw_rf_chip_info_s_v01 chip_info;
+	struct wlfw_rf_board_info_s_v01 board_info;
+	struct wlfw_soc_info_s_v01 soc_info;
+	struct wlfw_fw_version_info_s_v01 fw_version_info;
+	struct cnss_fw_mem fw_mem;
+	struct cnss_fw_mem m3_mem;
+	struct cnss_pin_connect_result pin_result;
+	struct dentry *root_dentry;
+	atomic_t pm_count;
+	struct timer_list fw_boot_timer;
+	struct completion power_up_complete;
+	struct mutex dev_lock; /* mutex for register access through debugfs */
+	u32 diag_reg_read_addr;
+	u32 diag_reg_read_mem_type;
+	u32 diag_reg_read_len;
+	u8 *diag_reg_read_buf;
+};
+
+void *cnss_bus_dev_to_bus_priv(struct device *dev);
+struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev);
+int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
+			   enum cnss_driver_event_type type,
+			   u32 flags, void *data);
+int cnss_get_vreg(struct cnss_plat_data *plat_priv);
+int cnss_get_pinctrl(struct cnss_plat_data *plat_priv);
+int cnss_power_on_device(struct cnss_plat_data *plat_priv);
+void cnss_power_off_device(struct cnss_plat_data *plat_priv);
+int cnss_register_subsys(struct cnss_plat_data *plat_priv);
+void cnss_unregister_subsys(struct cnss_plat_data *plat_priv);
+int cnss_register_ramdump(struct cnss_plat_data *plat_priv);
+void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv);
+void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv);
+u32 cnss_get_wake_msi(struct cnss_plat_data *plat_priv);
+
+#endif /* _CNSS_MAIN_H */
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
new file mode 100644
index 0000000..3c5bc72
--- /dev/null
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -0,0 +1,1615 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/firmware.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+
+#include "main.h"
+#include "debug.h"
+#include "pci.h"
+
+#define PCI_LINK_UP			1
+#define PCI_LINK_DOWN			0
+
+#define SAVE_PCI_CONFIG_SPACE		1
+#define RESTORE_PCI_CONFIG_SPACE	0
+
+#define PM_OPTIONS_DEFAULT		0
+#define PM_OPTIONS_LINK_DOWN \
+	(MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN)
+
+#define PCI_BAR_NUM			0
+
+#ifdef CONFIG_ARM_LPAE
+#define PCI_DMA_MASK			64
+#else
+#define PCI_DMA_MASK			32
+#endif
+
+#define MHI_NODE_NAME			"qcom,mhi"
+
+#define MAX_M3_FILE_NAME_LENGTH		13
+#define DEFAULT_M3_FILE_NAME		"m3.bin"
+
+static DEFINE_SPINLOCK(pci_link_down_lock);
+
+static unsigned int pci_link_down_panic;
+module_param(pci_link_down_panic, uint, 0600);
+MODULE_PARM_DESC(pci_link_down_panic,
+		 "Trigger kernel panic when PCI link down is detected");
+
+static bool fbc_bypass;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(fbc_bypass, bool, 0600);
+MODULE_PARM_DESC(fbc_bypass,
+		 "Bypass firmware download when loading WLAN driver");
+#endif
+
+static int cnss_set_pci_config_space(struct cnss_pci_data *pci_priv, bool save)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	bool link_down_or_recovery;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	link_down_or_recovery = pci_priv->pci_link_down_ind ||
+		(test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state));
+
+	if (save) {
+		if (link_down_or_recovery) {
+			pci_priv->saved_state = NULL;
+		} else {
+			pci_save_state(pci_dev);
+			pci_priv->saved_state = pci_store_saved_state(pci_dev);
+		}
+	} else {
+		if (link_down_or_recovery) {
+			pci_load_saved_state(pci_dev, pci_priv->default_state);
+			pci_restore_state(pci_dev);
+		} else if (pci_priv->saved_state) {
+			pci_load_and_free_saved_state(pci_dev,
+						      &pci_priv->saved_state);
+			pci_restore_state(pci_dev);
+		}
+	}
+
+	return 0;
+}
+
+static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+	ret = msm_pcie_pm_control(link_up ? MSM_PCIE_RESUME :
+				  MSM_PCIE_SUSPEND,
+				  pci_dev->bus->number,
+				  pci_dev, NULL,
+				  PM_OPTIONS_DEFAULT);
+	if (ret) {
+		cnss_pr_err("Failed to %s PCI link with default option, err = %d\n",
+			    link_up ? "resume" : "suspend", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Suspending PCI link\n");
+	if (!pci_priv->pci_link_state) {
+		cnss_pr_info("PCI link is already suspended!\n");
+		goto out;
+	}
+
+	ret = cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
+	if (ret)
+		goto out;
+
+	pci_disable_device(pci_priv->pci_dev);
+
+	if (pci_priv->pci_dev->device != QCA6174_DEVICE_ID) {
+		if (pci_set_power_state(pci_priv->pci_dev, PCI_D3hot))
+			cnss_pr_err("Failed to set D3Hot, err =  %d\n", ret);
+	}
+
+	ret = cnss_set_pci_link(pci_priv, PCI_LINK_DOWN);
+	if (ret)
+		goto out;
+
+	pci_priv->pci_link_state = PCI_LINK_DOWN;
+
+	return 0;
+out:
+	return ret;
+}
+
+int cnss_resume_pci_link(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Resuming PCI link\n");
+	if (pci_priv->pci_link_state) {
+		cnss_pr_info("PCI link is already resumed!\n");
+		goto out;
+	}
+
+	ret = cnss_set_pci_link(pci_priv, PCI_LINK_UP);
+	if (ret)
+		goto out;
+
+	pci_priv->pci_link_state = PCI_LINK_UP;
+
+	ret = cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
+	if (ret)
+		goto out;
+
+	ret = pci_enable_device(pci_priv->pci_dev);
+	if (ret) {
+		cnss_pr_err("Failed to enable PCI device, err = %d\n", ret);
+		goto out;
+	}
+
+	pci_set_master(pci_priv->pci_dev);
+
+	if (pci_priv->pci_link_down_ind)
+		pci_priv->pci_link_down_ind = false;
+
+	return 0;
+out:
+	return ret;
+}
+
+int cnss_pci_link_down(struct device *dev)
+{
+	unsigned long flags;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (pci_link_down_panic)
+		panic("cnss: PCI link is down!\n");
+
+	spin_lock_irqsave(&pci_link_down_lock, flags);
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_dbg("PCI link down recovery is in progress, ignore!\n");
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+		return -EINVAL;
+	}
+	pci_priv->pci_link_down_ind = true;
+	spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+	cnss_pr_err("PCI link down is detected by host driver, schedule recovery!\n");
+
+	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_NOTIFY_LINK_ERROR);
+	cnss_schedule_recovery(dev, CNSS_REASON_LINK_DOWN);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_pci_link_down);
+
+static int cnss_pci_init_smmu(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct device *dev;
+	struct dma_iommu_mapping *mapping;
+	int atomic_ctx = 1;
+	int s1_bypass = 1;
+
+	dev = &pci_priv->pci_dev->dev;
+
+	mapping = arm_iommu_create_mapping(&platform_bus_type,
+					   pci_priv->smmu_iova_start,
+					   pci_priv->smmu_iova_len);
+	if (IS_ERR(mapping)) {
+		ret = PTR_ERR(mapping);
+		cnss_pr_err("Failed to create SMMU mapping, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = iommu_domain_set_attr(mapping->domain,
+				    DOMAIN_ATTR_ATOMIC,
+				    &atomic_ctx);
+	if (ret) {
+		pr_err("Failed to set SMMU atomic_ctx attribute, err = %d\n",
+		       ret);
+		goto release_mapping;
+	}
+
+	ret = iommu_domain_set_attr(mapping->domain,
+				    DOMAIN_ATTR_S1_BYPASS,
+				    &s1_bypass);
+	if (ret) {
+		pr_err("Failed to set SMMU s1_bypass attribute, err = %d\n",
+		       ret);
+		goto release_mapping;
+	}
+
+	ret = arm_iommu_attach_device(dev, mapping);
+	if (ret) {
+		pr_err("Failed to attach SMMU device, err = %d\n", ret);
+		goto release_mapping;
+	}
+
+	pci_priv->smmu_mapping = mapping;
+
+	return ret;
+release_mapping:
+	arm_iommu_release_mapping(mapping);
+out:
+	return ret;
+}
+
+static void cnss_pci_deinit_smmu(struct cnss_pci_data *pci_priv)
+{
+	arm_iommu_detach_device(&pci_priv->pci_dev->dev);
+	arm_iommu_release_mapping(pci_priv->smmu_mapping);
+
+	pci_priv->smmu_mapping = NULL;
+}
+
+static void cnss_pci_event_cb(struct msm_pcie_notify *notify)
+{
+	unsigned long flags;
+	struct pci_dev *pci_dev;
+	struct cnss_pci_data *pci_priv;
+
+	if (!notify)
+		return;
+
+	pci_dev = notify->user;
+	if (!pci_dev)
+		return;
+
+	pci_priv = cnss_get_pci_priv(pci_dev);
+	if (!pci_priv)
+		return;
+
+	switch (notify->event) {
+	case MSM_PCIE_EVENT_LINKDOWN:
+		if (pci_link_down_panic)
+			panic("cnss: PCI link is down!\n");
+
+		spin_lock_irqsave(&pci_link_down_lock, flags);
+		if (pci_priv->pci_link_down_ind) {
+			cnss_pr_dbg("PCI link down recovery is in progress, ignore!\n");
+			spin_unlock_irqrestore(&pci_link_down_lock, flags);
+			return;
+		}
+		pci_priv->pci_link_down_ind = true;
+		spin_unlock_irqrestore(&pci_link_down_lock, flags);
+
+		cnss_pr_err("PCI link down, schedule recovery!\n");
+		cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_NOTIFY_LINK_ERROR);
+		if (pci_dev->device == QCA6174_DEVICE_ID)
+			disable_irq(pci_dev->irq);
+		cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN);
+		break;
+	case MSM_PCIE_EVENT_WAKEUP:
+		if (cnss_pci_get_monitor_wake_intr(pci_priv) &&
+		    cnss_pci_get_auto_suspended(pci_priv)) {
+			cnss_pci_set_monitor_wake_intr(pci_priv, false);
+			pm_request_resume(&pci_dev->dev);
+		}
+		break;
+	default:
+		cnss_pr_err("Received invalid PCI event: %d\n", notify->event);
+	}
+}
+
+static int cnss_reg_pci_event(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct msm_pcie_register_event *pci_event;
+
+	pci_event = &pci_priv->msm_pci_event;
+	pci_event->events = MSM_PCIE_EVENT_LINKDOWN |
+		MSM_PCIE_EVENT_WAKEUP;
+	pci_event->user = pci_priv->pci_dev;
+	pci_event->mode = MSM_PCIE_TRIGGER_CALLBACK;
+	pci_event->callback = cnss_pci_event_cb;
+	pci_event->options = MSM_PCIE_CONFIG_NO_RECOVERY;
+
+	ret = msm_pcie_register_event(pci_event);
+	if (ret)
+		cnss_pr_err("Failed to register MSM PCI event, err = %d\n",
+			    ret);
+
+	return ret;
+}
+
+static void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv)
+{
+	msm_pcie_deregister_event(&pci_priv->msm_pci_event);
+}
+
+static int cnss_pci_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_plat_data *plat_priv;
+	struct cnss_wlan_driver *driver_ops;
+
+	pm_message_t state = { .event = PM_EVENT_SUSPEND };
+
+	if (!pci_priv)
+		goto out;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		goto out;
+
+	driver_ops = plat_priv->driver_ops;
+	if (driver_ops && driver_ops->suspend) {
+		ret = driver_ops->suspend(pci_dev, state);
+		if (ret) {
+			cnss_pr_err("Failed to suspend host driver, err = %d\n",
+				    ret);
+			ret = -EAGAIN;
+			goto out;
+		}
+	}
+
+	if (pci_priv->pci_link_state) {
+		ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND);
+		if (ret) {
+			if (driver_ops && driver_ops->resume)
+				driver_ops->resume(pci_dev);
+			ret = -EAGAIN;
+			goto out;
+		}
+
+		cnss_set_pci_config_space(pci_priv,
+					  SAVE_PCI_CONFIG_SPACE);
+		pci_disable_device(pci_dev);
+
+		ret = pci_set_power_state(pci_dev, PCI_D3hot);
+		if (ret)
+			cnss_pr_err("Failed to set D3Hot, err = %d\n",
+				    ret);
+	}
+
+	cnss_pci_set_monitor_wake_intr(pci_priv, false);
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static int cnss_pci_resume(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_plat_data *plat_priv;
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		goto out;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		goto out;
+
+	if (pci_priv->pci_link_down_ind)
+		goto out;
+
+	ret = pci_enable_device(pci_dev);
+	if (ret)
+		cnss_pr_err("Failed to enable PCI device, err = %d\n", ret);
+
+	if (pci_priv->saved_state)
+		cnss_set_pci_config_space(pci_priv,
+					  RESTORE_PCI_CONFIG_SPACE);
+
+	pci_set_master(pci_dev);
+	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+
+	driver_ops = plat_priv->driver_ops;
+	if (driver_ops && driver_ops->resume) {
+		ret = driver_ops->resume(pci_dev);
+		if (ret)
+			cnss_pr_err("Failed to resume host driver, err = %d\n",
+				    ret);
+	}
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static int cnss_pci_suspend_noirq(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_plat_data *plat_priv;
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		goto out;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		goto out;
+
+	driver_ops = plat_priv->driver_ops;
+	if (driver_ops && driver_ops->suspend_noirq)
+		ret = driver_ops->suspend_noirq(pci_dev);
+
+out:
+	return ret;
+}
+
+static int cnss_pci_resume_noirq(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_plat_data *plat_priv;
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		goto out;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		goto out;
+
+	driver_ops = plat_priv->driver_ops;
+	if (driver_ops && driver_ops->resume_noirq &&
+	    !pci_priv->pci_link_down_ind)
+		ret = driver_ops->resume_noirq(pci_dev);
+
+out:
+	return ret;
+}
+
+static int cnss_pci_runtime_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_plat_data *plat_priv;
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		return -EAGAIN;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -EAGAIN;
+
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_dbg("PCI link down recovery is in progress!\n");
+		return -EAGAIN;
+	}
+
+	cnss_pr_dbg("Runtime suspend start\n");
+
+	driver_ops = plat_priv->driver_ops;
+	if (driver_ops && driver_ops->runtime_ops &&
+	    driver_ops->runtime_ops->runtime_suspend)
+		ret = driver_ops->runtime_ops->runtime_suspend(pci_dev);
+
+	cnss_pr_info("Runtime suspend status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_pci_runtime_resume(struct device *dev)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_plat_data *plat_priv;
+	struct cnss_wlan_driver *driver_ops;
+
+	if (!pci_priv)
+		return -EAGAIN;
+
+	plat_priv = pci_priv->plat_priv;
+	if (!plat_priv)
+		return -EAGAIN;
+
+	if (pci_priv->pci_link_down_ind) {
+		cnss_pr_dbg("PCI link down recovery is in progress!\n");
+		return -EAGAIN;
+	}
+
+	cnss_pr_dbg("Runtime resume start\n");
+
+	driver_ops = plat_priv->driver_ops;
+	if (driver_ops && driver_ops->runtime_ops &&
+	    driver_ops->runtime_ops->runtime_resume)
+		ret = driver_ops->runtime_ops->runtime_resume(pci_dev);
+
+	cnss_pr_info("Runtime resume status: %d\n", ret);
+
+	return ret;
+}
+
+static int cnss_pci_runtime_idle(struct device *dev)
+{
+	cnss_pr_dbg("Runtime idle\n");
+
+	pm_request_autosuspend(dev);
+
+	return -EBUSY;
+}
+
+int cnss_wlan_pm_control(struct device *dev, bool vote)
+{
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct cnss_pci_data *pci_priv;
+	struct pci_dev *pci_dev;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	pci_priv = plat_priv->bus_priv;
+	if (!pci_priv)
+		return -ENODEV;
+
+	pci_dev = pci_priv->pci_dev;
+
+	return msm_pcie_pm_control(vote ? MSM_PCIE_DISABLE_PC :
+				   MSM_PCIE_ENABLE_PC,
+				   pci_dev->bus->number, pci_dev,
+				   NULL, PM_OPTIONS_DEFAULT);
+}
+EXPORT_SYMBOL(cnss_wlan_pm_control);
+
+int cnss_auto_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct pci_dev *pci_dev;
+	struct cnss_pci_data *pci_priv;
+	struct cnss_bus_bw_info *bus_bw_info;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	pci_priv = plat_priv->bus_priv;
+	if (!pci_priv)
+		return -ENODEV;
+
+	pci_dev = pci_priv->pci_dev;
+
+	if (pci_priv->pci_link_state) {
+		if (cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND)) {
+			ret = -EAGAIN;
+			goto out;
+		}
+
+		cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
+		pci_disable_device(pci_dev);
+
+		ret = pci_set_power_state(pci_dev, PCI_D3hot);
+		if (ret)
+			cnss_pr_err("Failed to set D3Hot, err =  %d\n", ret);
+
+		cnss_pr_dbg("Suspending PCI link\n");
+		if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) {
+			cnss_pr_err("Failed to suspend PCI link!\n");
+			ret = -EAGAIN;
+			goto resume_mhi;
+		}
+
+		pci_priv->pci_link_state = PCI_LINK_DOWN;
+	}
+
+	cnss_pci_set_auto_suspended(pci_priv, 1);
+	cnss_pci_set_monitor_wake_intr(pci_priv, true);
+
+	bus_bw_info = &plat_priv->bus_bw_info;
+	msm_bus_scale_client_update_request(bus_bw_info->bus_client,
+					    CNSS_BUS_WIDTH_NONE);
+
+	return 0;
+
+resume_mhi:
+	if (pci_enable_device(pci_dev))
+		cnss_pr_err("Failed to enable PCI device!\n");
+	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_auto_suspend);
+
+int cnss_auto_resume(struct device *dev)
+{
+	int ret = 0;
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
+	struct pci_dev *pci_dev;
+	struct cnss_pci_data *pci_priv;
+	struct cnss_bus_bw_info *bus_bw_info;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	pci_priv = plat_priv->bus_priv;
+	if (!pci_priv)
+		return -ENODEV;
+
+	pci_dev = pci_priv->pci_dev;
+	if (!pci_priv->pci_link_state) {
+		cnss_pr_dbg("Resuming PCI link\n");
+		if (cnss_set_pci_link(pci_priv, PCI_LINK_UP)) {
+			cnss_pr_err("Failed to resume PCI link!\n");
+			ret = -EAGAIN;
+			goto out;
+		}
+		pci_priv->pci_link_state = PCI_LINK_UP;
+
+		ret = pci_enable_device(pci_dev);
+		if (ret)
+			cnss_pr_err("Failed to enable PCI device, err = %d\n",
+				    ret);
+
+		cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
+		pci_set_master(pci_dev);
+		cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+	}
+
+	cnss_pci_set_auto_suspended(pci_priv, 0);
+
+	bus_bw_info = &plat_priv->bus_bw_info;
+	msm_bus_scale_client_update_request(bus_bw_info->bus_client,
+					    bus_bw_info->current_bw_vote);
+out:
+	return ret;
+}
+EXPORT_SYMBOL(cnss_auto_resume);
+
+int cnss_pm_request_resume(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	pci_dev = pci_priv->pci_dev;
+	if (!pci_dev)
+		return -ENODEV;
+
+	return pm_request_resume(&pci_dev->dev);
+}
+
+int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+
+	if (!fw_mem->va && fw_mem->size) {
+		fw_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						fw_mem->size, &fw_mem->pa,
+						GFP_KERNEL);
+		if (!fw_mem->va) {
+			cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx\n",
+				    fw_mem->size);
+			fw_mem->size = 0;
+
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+
+	if (fw_mem->va && fw_mem->size) {
+		cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+			    fw_mem->va, &fw_mem->pa, fw_mem->size);
+		dma_free_coherent(&pci_priv->pci_dev->dev, fw_mem->size,
+				  fw_mem->va, fw_mem->pa);
+		fw_mem->va = NULL;
+		fw_mem->pa = 0;
+		fw_mem->size = 0;
+	}
+}
+
+int cnss_pci_load_m3(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+	char filename[MAX_M3_FILE_NAME_LENGTH];
+	const struct firmware *fw_entry;
+	int ret = 0;
+
+	if (!m3_mem->va && !m3_mem->size) {
+		snprintf(filename, sizeof(filename), DEFAULT_M3_FILE_NAME);
+
+		ret = request_firmware(&fw_entry, filename,
+				       &pci_priv->pci_dev->dev);
+		if (ret) {
+			cnss_pr_err("Failed to load M3 image: %s\n", filename);
+			return ret;
+		}
+
+		m3_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
+						fw_entry->size, &m3_mem->pa,
+						GFP_KERNEL);
+		if (!m3_mem->va) {
+			cnss_pr_err("Failed to allocate memory for M3, size: 0x%zx\n",
+				    fw_entry->size);
+			release_firmware(fw_entry);
+			return -ENOMEM;
+		}
+
+		memcpy(m3_mem->va, fw_entry->data, fw_entry->size);
+		m3_mem->size = fw_entry->size;
+		release_firmware(fw_entry);
+	}
+
+	return 0;
+}
+
+static void cnss_pci_free_m3_mem(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+
+	if (m3_mem->va && m3_mem->size) {
+		cnss_pr_dbg("Freeing memory for M3, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+			    m3_mem->va, &m3_mem->pa, m3_mem->size);
+		dma_free_coherent(&pci_priv->pci_dev->dev, m3_mem->size,
+				  m3_mem->va, m3_mem->pa);
+	}
+
+	m3_mem->va = NULL;
+	m3_mem->pa = 0;
+	m3_mem->size = 0;
+}
+
+int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va,
+			  phys_addr_t *pa)
+{
+	if (!pci_priv)
+		return -ENODEV;
+
+	*va = pci_priv->bar;
+	*pa = pci_resource_start(pci_priv->pci_dev, PCI_BAR_NUM);
+
+	return 0;
+}
+
+static struct cnss_msi_config msi_config = {
+	.total_vectors = 32,
+	.total_users = 4,
+	.users = (struct cnss_msi_user[]) {
+		{ .name = "MHI", .num_vectors = 2, .base_vector = 0 },
+		{ .name = "CE", .num_vectors = 11, .base_vector = 2 },
+		{ .name = "WAKE", .num_vectors = 1, .base_vector = 13 },
+		{ .name = "DP", .num_vectors = 18, .base_vector = 14 },
+	},
+};
+
+static int cnss_pci_get_msi_assignment(struct cnss_pci_data *pci_priv)
+{
+	pci_priv->msi_config = &msi_config;
+
+	return 0;
+}
+
+static int cnss_pci_enable_msi(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	int num_vectors;
+	struct cnss_msi_config *msi_config;
+	struct msi_desc *msi_desc;
+
+	ret = cnss_pci_get_msi_assignment(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to get MSI assignment, err = %d\n", ret);
+		goto out;
+	}
+
+	msi_config = pci_priv->msi_config;
+	if (!msi_config) {
+		cnss_pr_err("msi_config is NULL!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	num_vectors = pci_enable_msi_range(pci_dev,
+					   msi_config->total_vectors,
+					   msi_config->total_vectors);
+	if (num_vectors != msi_config->total_vectors) {
+		cnss_pr_err("Failed to get enough MSI vectors (%d), available vectors = %d",
+			    msi_config->total_vectors, num_vectors);
+		ret = -EINVAL;
+		goto reset_msi_config;
+	}
+
+	msi_desc = irq_get_msi_desc(pci_dev->irq);
+	if (!msi_desc) {
+		cnss_pr_err("msi_desc is NULL!\n");
+		ret = -EINVAL;
+		goto disable_msi;
+	}
+
+	pci_priv->msi_ep_base_data = msi_desc->msg.data;
+	if (!pci_priv->msi_ep_base_data) {
+		cnss_pr_err("Got 0 MSI base data!\n");
+		CNSS_ASSERT(0);
+	}
+
+	cnss_pr_dbg("MSI base data is %d\n", pci_priv->msi_ep_base_data);
+
+	return 0;
+
+disable_msi:
+	pci_disable_msi(pci_priv->pci_dev);
+reset_msi_config:
+	pci_priv->msi_config = NULL;
+out:
+	return ret;
+}
+
+static void cnss_pci_disable_msi(struct cnss_pci_data *pci_priv)
+{
+	pci_disable_msi(pci_priv->pci_dev);
+}
+
+int cnss_get_user_msi_assignment(struct device *dev, char *user_name,
+				 int *num_vectors, u32 *user_base_data,
+				 u32 *base_vector)
+{
+	struct cnss_pci_data *pci_priv = dev_get_drvdata(dev);
+	struct cnss_msi_config *msi_config;
+	int idx;
+
+	if (!pci_priv)
+		return -ENODEV;
+
+	msi_config = pci_priv->msi_config;
+	if (!msi_config) {
+		cnss_pr_err("MSI is not supported.\n");
+		return -EINVAL;
+	}
+
+	for (idx = 0; idx < msi_config->total_users; idx++) {
+		if (strcmp(user_name, msi_config->users[idx].name) == 0) {
+			*num_vectors = msi_config->users[idx].num_vectors;
+			*user_base_data = msi_config->users[idx].base_vector
+				+ pci_priv->msi_ep_base_data;
+			*base_vector = msi_config->users[idx].base_vector;
+
+			cnss_pr_dbg("Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
+				    user_name, *num_vectors, *user_base_data,
+				    *base_vector);
+
+			return 0;
+		}
+	}
+
+	cnss_pr_err("Failed to find MSI assignment for %s!\n", user_name);
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(cnss_get_user_msi_assignment);
+
+int cnss_get_msi_irq(struct device *dev, unsigned int vector)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+
+	return pci_dev->irq + vector;
+}
+EXPORT_SYMBOL(cnss_get_msi_irq);
+
+void cnss_get_msi_address(struct device *dev, u32 *msi_addr_low,
+			  u32 *msi_addr_high)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+
+	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO,
+			      msi_addr_low);
+
+	pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI,
+			      msi_addr_high);
+}
+EXPORT_SYMBOL(cnss_get_msi_address);
+
+static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	u16 device_id;
+
+	pci_read_config_word(pci_dev, PCI_DEVICE_ID, &device_id);
+	if (device_id != pci_priv->pci_device_id->device)  {
+		cnss_pr_err("PCI device ID mismatch, config ID: 0x%x, probe ID: 0x%x\n",
+			    device_id, pci_priv->pci_device_id->device);
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = pci_assign_resource(pci_dev, PCI_BAR_NUM);
+	if (ret) {
+		pr_err("Failed to assign PCI resource, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = pci_enable_device(pci_dev);
+	if (ret) {
+		cnss_pr_err("Failed to enable PCI device, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = pci_request_region(pci_dev, PCI_BAR_NUM, "cnss");
+	if (ret) {
+		cnss_pr_err("Failed to request PCI region, err = %d\n", ret);
+		goto disable_device;
+	}
+
+	ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK));
+	if (ret) {
+		cnss_pr_err("Failed to set PCI DMA mask (%d), err = %d\n",
+			    ret, PCI_DMA_MASK);
+		goto release_region;
+	}
+
+	ret = pci_set_consistent_dma_mask(pci_dev, DMA_BIT_MASK(PCI_DMA_MASK));
+	if (ret) {
+		cnss_pr_err("Failed to set PCI consistent DMA mask (%d), err = %d\n",
+			    ret, PCI_DMA_MASK);
+		goto release_region;
+	}
+
+	pci_set_master(pci_dev);
+
+	pci_priv->bar = pci_iomap(pci_dev, PCI_BAR_NUM, 0);
+	if (!pci_priv->bar) {
+		cnss_pr_err("Failed to do PCI IO map!\n");
+		ret = -EIO;
+		goto clear_master;
+	}
+	return 0;
+
+clear_master:
+	pci_clear_master(pci_dev);
+release_region:
+	pci_release_region(pci_dev, PCI_BAR_NUM);
+disable_device:
+	pci_disable_device(pci_dev);
+out:
+	return ret;
+}
+
+static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv)
+{
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+
+	if (pci_priv->bar) {
+		pci_iounmap(pci_dev, pci_priv->bar);
+		pci_priv->bar = NULL;
+	}
+
+	pci_clear_master(pci_dev);
+	pci_release_region(pci_dev, PCI_BAR_NUM);
+	pci_disable_device(pci_dev);
+}
+
+static int cnss_mhi_pm_runtime_get(struct pci_dev *pci_dev)
+{
+	return pm_runtime_get(&pci_dev->dev);
+}
+
+static void cnss_mhi_pm_runtime_put_noidle(struct pci_dev *pci_dev)
+{
+	pm_runtime_put_noidle(&pci_dev->dev);
+}
+
+static char *cnss_mhi_state_to_str(enum cnss_mhi_state mhi_state)
+{
+	switch (mhi_state) {
+	case CNSS_MHI_INIT:
+		return "INIT";
+	case CNSS_MHI_DEINIT:
+		return "DEINIT";
+	case CNSS_MHI_POWER_ON:
+		return "POWER_ON";
+	case CNSS_MHI_POWER_OFF:
+		return "POWER_OFF";
+	case CNSS_MHI_SUSPEND:
+		return "SUSPEND";
+	case CNSS_MHI_RESUME:
+		return "RESUME";
+	case CNSS_MHI_TRIGGER_RDDM:
+		return "TRIGGER_RDDM";
+	case CNSS_MHI_RDDM:
+		return "RDDM";
+	case CNSS_MHI_RDDM_KERNEL_PANIC:
+		return "RDDM_KERNEL_PANIC";
+	case CNSS_MHI_NOTIFY_LINK_ERROR:
+		return "NOTIFY_LINK_ERROR";
+	default:
+		return "UNKNOWN";
+	}
+};
+
+static void *cnss_pci_collect_dump_seg(struct cnss_pci_data *pci_priv,
+				       enum mhi_rddm_segment type,
+				       void *start_addr)
+{
+	int count;
+	struct scatterlist *sg_list, *s;
+	unsigned int i;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_dump_data *dump_data =
+		&plat_priv->ramdump_info_v2.dump_data;
+	struct cnss_dump_seg *dump_seg = start_addr;
+
+	count = mhi_xfer_rddm(&pci_priv->mhi_dev, type, &sg_list);
+	if (count <= 0 || !sg_list) {
+		cnss_pr_err("Invalid dump_seg for type %u, count %u, sg_list %pK\n",
+			    type, count, sg_list);
+		return start_addr;
+	}
+
+	cnss_pr_dbg("Collect dump seg: type %u, nentries %d\n", type, count);
+
+	for_each_sg(sg_list, s, count, i) {
+		dump_seg->address = sg_dma_address(s);
+		dump_seg->v_address = sg_virt(s);
+		dump_seg->size = s->length;
+		dump_seg->type = type;
+		cnss_pr_dbg("seg-%d: address 0x%lx, v_address %pK, size 0x%lx\n",
+			    i, dump_seg->address,
+			    dump_seg->v_address, dump_seg->size);
+		dump_seg++;
+	}
+
+	dump_data->nentries += count;
+
+	return dump_seg;
+}
+
+void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	struct cnss_dump_data *dump_data =
+		&plat_priv->ramdump_info_v2.dump_data;
+	void *start_addr, *end_addr;
+
+	dump_data->nentries = 0;
+
+	start_addr = plat_priv->ramdump_info_v2.dump_data_vaddr;
+	end_addr = cnss_pci_collect_dump_seg(pci_priv,
+					     MHI_RDDM_FW_SEGMENT, start_addr);
+
+	start_addr = end_addr;
+	end_addr = cnss_pci_collect_dump_seg(pci_priv,
+					     MHI_RDDM_RD_SEGMENT, start_addr);
+
+	if (dump_data->nentries > 0)
+		plat_priv->ramdump_info_v2.dump_data_valid = true;
+}
+
+void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+
+	plat_priv->ramdump_info_v2.dump_data.nentries = 0;
+	plat_priv->ramdump_info_v2.dump_data_valid = false;
+}
+
+static void cnss_mhi_notify_status(enum MHI_CB_REASON reason, void *priv)
+{
+	struct cnss_pci_data *pci_priv = priv;
+	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
+	enum cnss_recovery_reason cnss_reason = CNSS_REASON_RDDM;
+
+	if (!pci_priv)
+		return;
+
+	cnss_pr_dbg("MHI status cb is called with reason %d\n", reason);
+
+	set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
+	del_timer(&plat_priv->fw_boot_timer);
+
+	if (reason == MHI_CB_SYS_ERROR)
+		cnss_reason = CNSS_REASON_TIMEOUT;
+
+	cnss_schedule_recovery(&pci_priv->pci_dev->dev,
+			       cnss_reason);
+}
+
+static int cnss_pci_register_mhi(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+	struct pci_dev *pci_dev = pci_priv->pci_dev;
+	struct mhi_device *mhi_dev = &pci_priv->mhi_dev;
+
+	mhi_dev->dev = &pci_priv->plat_priv->plat_dev->dev;
+	mhi_dev->pci_dev = pci_dev;
+
+	mhi_dev->resources[0].start = (resource_size_t)pci_priv->bar;
+	mhi_dev->resources[0].end = (resource_size_t)pci_priv->bar +
+		pci_resource_len(pci_dev, PCI_BAR_NUM);
+	mhi_dev->resources[0].flags =
+		pci_resource_flags(pci_dev, PCI_BAR_NUM);
+	mhi_dev->resources[0].name = "BAR";
+	cnss_pr_dbg("BAR start is %pa, BAR end is %pa\n",
+		    &mhi_dev->resources[0].start, &mhi_dev->resources[0].end);
+
+	if (!mhi_dev->resources[1].start) {
+		mhi_dev->resources[1].start = pci_dev->irq;
+		mhi_dev->resources[1].end = pci_dev->irq + 1;
+		mhi_dev->resources[1].flags = IORESOURCE_IRQ;
+		mhi_dev->resources[1].name = "IRQ";
+	}
+	cnss_pr_dbg("IRQ start is %pa, IRQ end is %pa\n",
+		    &mhi_dev->resources[1].start, &mhi_dev->resources[1].end);
+
+	mhi_dev->pm_runtime_get = cnss_mhi_pm_runtime_get;
+	mhi_dev->pm_runtime_put_noidle = cnss_mhi_pm_runtime_put_noidle;
+
+	mhi_dev->support_rddm = true;
+	mhi_dev->rddm_size = pci_priv->plat_priv->ramdump_info_v2.ramdump_size;
+	mhi_dev->status_cb = cnss_mhi_notify_status;
+
+	ret = mhi_register_device(mhi_dev, MHI_NODE_NAME, pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to register as MHI device, err = %d\n",
+			    ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void cnss_pci_unregister_mhi(struct cnss_pci_data *pci_priv)
+{
+}
+
+static enum mhi_dev_ctrl cnss_to_mhi_dev_state(enum cnss_mhi_state state)
+{
+	switch (state) {
+	case CNSS_MHI_INIT:
+		return MHI_DEV_CTRL_INIT;
+	case CNSS_MHI_DEINIT:
+		return MHI_DEV_CTRL_DE_INIT;
+	case CNSS_MHI_POWER_ON:
+		return MHI_DEV_CTRL_POWER_ON;
+	case CNSS_MHI_POWER_OFF:
+		return MHI_DEV_CTRL_POWER_OFF;
+	case CNSS_MHI_SUSPEND:
+		return MHI_DEV_CTRL_SUSPEND;
+	case CNSS_MHI_RESUME:
+		return MHI_DEV_CTRL_RESUME;
+	case CNSS_MHI_TRIGGER_RDDM:
+		return MHI_DEV_CTRL_TRIGGER_RDDM;
+	case CNSS_MHI_RDDM:
+		return MHI_DEV_CTRL_RDDM;
+	case CNSS_MHI_RDDM_KERNEL_PANIC:
+		return MHI_DEV_CTRL_RDDM_KERNEL_PANIC;
+	case CNSS_MHI_NOTIFY_LINK_ERROR:
+		return MHI_DEV_CTRL_NOTIFY_LINK_ERROR;
+	default:
+		cnss_pr_err("Unknown CNSS MHI state (%d)\n", state);
+		return -EINVAL;
+	}
+}
+
+static int cnss_pci_check_mhi_state_bit(struct cnss_pci_data *pci_priv,
+					enum cnss_mhi_state mhi_state)
+{
+	switch (mhi_state) {
+	case CNSS_MHI_INIT:
+		if (!test_bit(CNSS_MHI_INIT, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_DEINIT:
+	case CNSS_MHI_POWER_ON:
+		if (test_bit(CNSS_MHI_INIT, &pci_priv->mhi_state) &&
+		    !test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_POWER_OFF:
+	case CNSS_MHI_SUSPEND:
+		if (test_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state) &&
+		    !test_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_RESUME:
+		if (test_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state))
+			return 0;
+		break;
+	case CNSS_MHI_TRIGGER_RDDM:
+	case CNSS_MHI_RDDM:
+	case CNSS_MHI_RDDM_KERNEL_PANIC:
+	case CNSS_MHI_NOTIFY_LINK_ERROR:
+		return 0;
+	default:
+		cnss_pr_err("Unhandled MHI state: %s(%d)\n",
+			    cnss_mhi_state_to_str(mhi_state), mhi_state);
+	}
+
+	cnss_pr_err("Cannot set MHI state %s(%d) in current MHI state (0x%lx)\n",
+		    cnss_mhi_state_to_str(mhi_state), mhi_state,
+		    pci_priv->mhi_state);
+
+	return -EINVAL;
+}
+
+static void cnss_pci_set_mhi_state_bit(struct cnss_pci_data *pci_priv,
+				       enum cnss_mhi_state mhi_state)
+{
+	switch (mhi_state) {
+	case CNSS_MHI_INIT:
+		set_bit(CNSS_MHI_INIT, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_DEINIT:
+		clear_bit(CNSS_MHI_INIT, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_POWER_ON:
+		set_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_POWER_OFF:
+		clear_bit(CNSS_MHI_POWER_ON, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_SUSPEND:
+		set_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_RESUME:
+		clear_bit(CNSS_MHI_SUSPEND, &pci_priv->mhi_state);
+		break;
+	case CNSS_MHI_TRIGGER_RDDM:
+	case CNSS_MHI_RDDM:
+	case CNSS_MHI_RDDM_KERNEL_PANIC:
+	case CNSS_MHI_NOTIFY_LINK_ERROR:
+		break;
+	default:
+		cnss_pr_err("Unhandled MHI state (%d)\n", mhi_state);
+	}
+}
+
+int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv,
+			   enum cnss_mhi_state mhi_state)
+{
+	int ret = 0;
+	enum mhi_dev_ctrl mhi_dev_state = cnss_to_mhi_dev_state(mhi_state);
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL!\n");
+		return -ENODEV;
+	}
+
+	if (pci_priv->device_id == QCA6174_DEVICE_ID)
+		return 0;
+
+	if (mhi_dev_state < 0) {
+		cnss_pr_err("Invalid MHI DEV state (%d)\n", mhi_dev_state);
+		return -EINVAL;
+	}
+
+	ret = cnss_pci_check_mhi_state_bit(pci_priv, mhi_state);
+	if (ret)
+		goto out;
+
+	cnss_pr_dbg("Setting MHI state: %s(%d)\n",
+		    cnss_mhi_state_to_str(mhi_state), mhi_state);
+	ret = mhi_pm_control_device(&pci_priv->mhi_dev, mhi_dev_state);
+	if (ret) {
+		cnss_pr_err("Failed to set MHI state: %s(%d)\n",
+			    cnss_mhi_state_to_str(mhi_state), mhi_state);
+		goto out;
+	}
+
+	cnss_pci_set_mhi_state_bit(pci_priv, mhi_state);
+
+out:
+	return ret;
+}
+
+int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv)
+{
+	int ret = 0;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL!\n");
+		return -ENODEV;
+	}
+
+	if (fbc_bypass)
+		return 0;
+
+	ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_INIT);
+	if (ret)
+		goto out;
+
+	ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_ON);
+	if (ret)
+		goto out;
+
+	return 0;
+
+out:
+	return ret;
+}
+
+void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv)
+{
+	struct cnss_plat_data *plat_priv;
+
+	if (!pci_priv) {
+		cnss_pr_err("pci_priv is NULL!\n");
+		return;
+	}
+
+	if (fbc_bypass)
+		return;
+
+	plat_priv = pci_priv->plat_priv;
+
+	cnss_pci_set_mhi_state_bit(pci_priv, CNSS_MHI_RESUME);
+	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_POWER_OFF);
+
+	if (plat_priv->ramdump_info_v2.dump_data_valid ||
+	    test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state))
+		return;
+
+	cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_DEINIT);
+}
+
+static int cnss_pci_probe(struct pci_dev *pci_dev,
+			  const struct pci_device_id *id)
+{
+	int ret = 0;
+	struct cnss_pci_data *pci_priv;
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+	struct resource *res;
+
+	cnss_pr_dbg("PCI is probing, vendor ID: 0x%x, device ID: 0x%x\n",
+		    id->vendor, pci_dev->device);
+
+	switch (pci_dev->device) {
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		if (!mhi_is_device_ready(&plat_priv->plat_dev->dev,
+					 MHI_NODE_NAME)) {
+			cnss_pr_err("MHI driver is not ready, defer PCI probe!\n");
+			ret = -EPROBE_DEFER;
+			goto out;
+		}
+		break;
+	default:
+		break;
+	}
+
+	pci_priv = devm_kzalloc(&pci_dev->dev, sizeof(*pci_priv),
+				GFP_KERNEL);
+	if (!pci_priv) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	pci_priv->pci_link_state = PCI_LINK_UP;
+	pci_priv->plat_priv = plat_priv;
+	pci_priv->pci_dev = pci_dev;
+	pci_priv->pci_device_id = id;
+	pci_priv->device_id = pci_dev->device;
+	cnss_set_pci_priv(pci_dev, pci_priv);
+	plat_priv->device_id = pci_dev->device;
+	plat_priv->bus_priv = pci_priv;
+
+	ret = cnss_register_subsys(plat_priv);
+	if (ret)
+		goto reset_ctx;
+
+	ret = cnss_register_ramdump(plat_priv);
+	if (ret)
+		goto unregister_subsys;
+
+	res = platform_get_resource_byname(plat_priv->plat_dev, IORESOURCE_MEM,
+					   "smmu_iova_base");
+	if (res) {
+		pci_priv->smmu_iova_start = res->start;
+		pci_priv->smmu_iova_len = resource_size(res);
+		cnss_pr_dbg("smmu_iova_start: %pa, smmu_iova_len: %zu\n",
+			    &pci_priv->smmu_iova_start,
+			    pci_priv->smmu_iova_len);
+
+		ret = cnss_pci_init_smmu(pci_priv);
+		if (ret) {
+			cnss_pr_err("Failed to init SMMU, err = %d\n", ret);
+			goto unregister_ramdump;
+		}
+	}
+
+	ret = cnss_reg_pci_event(pci_priv);
+	if (ret) {
+		cnss_pr_err("Failed to register PCI event, err = %d\n", ret);
+		goto deinit_smmu;
+	}
+
+	ret = cnss_pci_enable_bus(pci_priv);
+	if (ret)
+		goto dereg_pci_event;
+
+	pci_save_state(pci_dev);
+	pci_priv->default_state = pci_store_saved_state(pci_dev);
+
+	switch (pci_dev->device) {
+	case QCA6174_DEVICE_ID:
+		pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET,
+				     &pci_priv->revision_id);
+		ret = cnss_suspend_pci_link(pci_priv);
+		if (ret)
+			cnss_pr_err("Failed to suspend PCI link, err = %d\n",
+				    ret);
+		cnss_power_off_device(plat_priv);
+		break;
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		ret = cnss_pci_enable_msi(pci_priv);
+		if (ret)
+			goto disable_bus;
+		ret = cnss_pci_register_mhi(pci_priv);
+		if (ret) {
+			cnss_pci_disable_msi(pci_priv);
+			goto disable_bus;
+		}
+		ret = cnss_suspend_pci_link(pci_priv);
+		if (ret)
+			cnss_pr_err("Failed to suspend PCI link, err = %d\n",
+				    ret);
+		cnss_power_off_device(plat_priv);
+		break;
+	default:
+		cnss_pr_err("Unknown PCI device found: 0x%x\n",
+			    pci_dev->device);
+		ret = -ENODEV;
+		goto disable_bus;
+	}
+
+	return 0;
+
+disable_bus:
+	cnss_pci_disable_bus(pci_priv);
+dereg_pci_event:
+	cnss_dereg_pci_event(pci_priv);
+deinit_smmu:
+	if (pci_priv->smmu_mapping)
+		cnss_pci_deinit_smmu(pci_priv);
+unregister_ramdump:
+	cnss_unregister_ramdump(plat_priv);
+unregister_subsys:
+	cnss_unregister_subsys(plat_priv);
+reset_ctx:
+	plat_priv->bus_priv = NULL;
+out:
+	return ret;
+}
+
+static void cnss_pci_remove(struct pci_dev *pci_dev)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_plat_data *plat_priv =
+		cnss_bus_dev_to_plat_priv(&pci_dev->dev);
+
+	cnss_pci_free_m3_mem(pci_priv);
+	cnss_pci_free_fw_mem(pci_priv);
+
+	switch (pci_dev->device) {
+	case QCA6290_EMULATION_DEVICE_ID:
+	case QCA6290_DEVICE_ID:
+		cnss_pci_unregister_mhi(pci_priv);
+		cnss_pci_disable_msi(pci_priv);
+		break;
+	default:
+		break;
+	}
+
+	pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state);
+
+	cnss_pci_disable_bus(pci_priv);
+	cnss_dereg_pci_event(pci_priv);
+	if (pci_priv->smmu_mapping)
+		cnss_pci_deinit_smmu(pci_priv);
+	cnss_unregister_ramdump(plat_priv);
+	cnss_unregister_subsys(plat_priv);
+	plat_priv->bus_priv = NULL;
+}
+
+static const struct pci_device_id cnss_pci_id_table[] = {
+	{ QCA6174_VENDOR_ID, QCA6174_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ QCA6290_EMULATION_VENDOR_ID, QCA6290_EMULATION_DEVICE_ID,
+	  PCI_ANY_ID, PCI_ANY_ID },
+	{ QCA6290_VENDOR_ID, QCA6290_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, cnss_pci_id_table);
+
+static const struct dev_pm_ops cnss_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend, cnss_pci_resume)
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cnss_pci_suspend_noirq,
+				      cnss_pci_resume_noirq)
+	SET_RUNTIME_PM_OPS(cnss_pci_runtime_suspend, cnss_pci_runtime_resume,
+			   cnss_pci_runtime_idle)
+};
+
+struct pci_driver cnss_pci_driver = {
+	.name     = "cnss_pci",
+	.id_table = cnss_pci_id_table,
+	.probe    = cnss_pci_probe,
+	.remove   = cnss_pci_remove,
+	.driver = {
+		.pm = &cnss_pm_ops,
+	},
+};
+
+int cnss_pci_init(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct device *dev = &plat_priv->plat_dev->dev;
+	u32 rc_num;
+
+	ret = of_property_read_u32(dev->of_node, "qcom,wlan-rc-num", &rc_num);
+	if (ret) {
+		cnss_pr_err("Failed to find PCIe RC number, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = msm_pcie_enumerate(rc_num);
+	if (ret) {
+		cnss_pr_err("Failed to enable PCIe RC%x, err = %d\n",
+			    rc_num, ret);
+		goto out;
+	}
+
+	ret = pci_register_driver(&cnss_pci_driver);
+	if (ret) {
+		cnss_pr_err("Failed to register to PCI framework, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+void cnss_pci_deinit(struct cnss_plat_data *plat_priv)
+{
+	pci_unregister_driver(&cnss_pci_driver);
+}
diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h
new file mode 100644
index 0000000..89edc60
--- /dev/null
+++ b/drivers/net/wireless/cnss2/pci.h
@@ -0,0 +1,143 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CNSS_PCI_H
+#define _CNSS_PCI_H
+
+#include <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#include <linux/msm_mhi.h>
+#include <linux/msm_pcie.h>
+#include <linux/pci.h>
+
+#include "main.h"
+
+#define QCA6174_VENDOR_ID		0x168C
+#define QCA6174_DEVICE_ID		0x003E
+#define QCA6174_REV_ID_OFFSET		0x08
+#define QCA6174_REV3_VERSION		0x5020000
+#define QCA6174_REV3_2_VERSION		0x5030000
+#define QCA6290_VENDOR_ID		0x17CB
+#define QCA6290_DEVICE_ID		0x1100
+#define QCA6290_EMULATION_VENDOR_ID	0x168C
+#define QCA6290_EMULATION_DEVICE_ID	0xABCD
+
+enum cnss_mhi_state {
+	CNSS_MHI_INIT,
+	CNSS_MHI_DEINIT,
+	CNSS_MHI_SUSPEND,
+	CNSS_MHI_RESUME,
+	CNSS_MHI_POWER_OFF,
+	CNSS_MHI_POWER_ON,
+	CNSS_MHI_TRIGGER_RDDM,
+	CNSS_MHI_RDDM,
+	CNSS_MHI_RDDM_KERNEL_PANIC,
+	CNSS_MHI_NOTIFY_LINK_ERROR,
+};
+
+struct cnss_msi_user {
+	char *name;
+	int num_vectors;
+	u32 base_vector;
+};
+
+struct cnss_msi_config {
+	int total_vectors;
+	int total_users;
+	struct cnss_msi_user *users;
+};
+
+struct cnss_pci_data {
+	struct pci_dev *pci_dev;
+	struct cnss_plat_data *plat_priv;
+	const struct pci_device_id *pci_device_id;
+	u32 device_id;
+	u16 revision_id;
+	bool pci_link_state;
+	bool pci_link_down_ind;
+	struct pci_saved_state *saved_state;
+	struct pci_saved_state *default_state;
+	struct msm_pcie_register_event msm_pci_event;
+	atomic_t auto_suspended;
+	bool monitor_wake_intr;
+	struct dma_iommu_mapping *smmu_mapping;
+	dma_addr_t smmu_iova_start;
+	size_t smmu_iova_len;
+	void __iomem *bar;
+	struct cnss_msi_config *msi_config;
+	u32 msi_ep_base_data;
+	struct mhi_device mhi_dev;
+	unsigned long mhi_state;
+};
+
+static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data)
+{
+	pci_set_drvdata(pci_dev, data);
+}
+
+static inline struct cnss_pci_data *cnss_get_pci_priv(struct pci_dev *pci_dev)
+{
+	return pci_get_drvdata(pci_dev);
+}
+
+static inline struct cnss_plat_data *cnss_pci_priv_to_plat_priv(void *bus_priv)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	return pci_priv->plat_priv;
+}
+
+static inline void cnss_pci_set_monitor_wake_intr(void *bus_priv, bool val)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	pci_priv->monitor_wake_intr = val;
+}
+
+static inline bool cnss_pci_get_monitor_wake_intr(void *bus_priv)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	return pci_priv->monitor_wake_intr;
+}
+
+static inline void cnss_pci_set_auto_suspended(void *bus_priv, int val)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	atomic_set(&pci_priv->auto_suspended, val);
+}
+
+static inline int cnss_pci_get_auto_suspended(void *bus_priv)
+{
+	struct cnss_pci_data *pci_priv = bus_priv;
+
+	return atomic_read(&pci_priv->auto_suspended);
+}
+
+int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv);
+int cnss_resume_pci_link(struct cnss_pci_data *pci_priv);
+int cnss_pci_init(struct cnss_plat_data *plat_priv);
+void cnss_pci_deinit(struct cnss_plat_data *plat_priv);
+int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv);
+int cnss_pci_load_m3(struct cnss_pci_data *pci_priv);
+int cnss_pci_get_bar_info(struct cnss_pci_data *pci_priv, void __iomem **va,
+			  phys_addr_t *pa);
+int cnss_pci_set_mhi_state(struct cnss_pci_data *pci_priv,
+			   enum cnss_mhi_state state);
+int cnss_pci_start_mhi(struct cnss_pci_data *pci_priv);
+void cnss_pci_stop_mhi(struct cnss_pci_data *pci_priv);
+void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv);
+void cnss_pci_clear_dump_info(struct cnss_pci_data *pci_priv);
+int cnss_pm_request_resume(struct cnss_pci_data *pci_priv);
+
+#endif /* _CNSS_PCI_H */
diff --git a/drivers/net/wireless/cnss2/power.c b/drivers/net/wireless/cnss2/power.c
new file mode 100644
index 0000000..8ed1507
--- /dev/null
+++ b/drivers/net/wireless/cnss2/power.c
@@ -0,0 +1,386 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include "main.h"
+#include "debug.h"
+
+static struct cnss_vreg_info cnss_vreg_info[] = {
+	{NULL, "vdd-wlan-core", 1300000, 1300000, 0, 0},
+	{NULL, "vdd-wlan-io", 1800000, 1800000, 0, 0},
+	{NULL, "vdd-wlan-xtal-aon", 0, 0, 0, 0},
+	{NULL, "vdd-wlan-xtal", 1800000, 1800000, 0, 2},
+	{NULL, "vdd-wlan", 0, 0, 0, 0},
+	{NULL, "vdd-wlan-sp2t", 2700000, 2700000, 0, 0},
+	{NULL, "wlan-ant-switch", 2700000, 2700000, 20000, 0},
+	{NULL, "wlan-soc-swreg", 1200000, 1200000, 0, 0},
+	{NULL, "vdd-wlan-en", 0, 0, 0, 10},
+};
+
+#define CNSS_VREG_INFO_SIZE		ARRAY_SIZE(cnss_vreg_info)
+#define MAX_PROP_SIZE			32
+
+#define BOOTSTRAP_GPIO			"qcom,enable-bootstrap-gpio"
+#define BOOTSTRAP_ACTIVE		"bootstrap_active"
+#define WLAN_EN_GPIO			"wlan-en-gpio"
+#define WLAN_EN_ACTIVE			"wlan_en_active"
+#define WLAN_EN_SLEEP			"wlan_en_sleep"
+
+#define BOOTSTRAP_DELAY			1000
+#define WLAN_ENABLE_DELAY		1000
+
+int cnss_get_vreg(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	int i;
+	struct cnss_vreg_info *vreg_info;
+	struct device *dev;
+	struct regulator *reg;
+	const __be32 *prop;
+	char prop_name[MAX_PROP_SIZE];
+	int len;
+
+	dev = &plat_priv->plat_dev->dev;
+
+	plat_priv->vreg_info = devm_kzalloc(dev, sizeof(cnss_vreg_info),
+					    GFP_KERNEL);
+	if (!plat_priv->vreg_info) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memcpy(plat_priv->vreg_info, cnss_vreg_info, sizeof(cnss_vreg_info));
+
+	for (i = 0; i < CNSS_VREG_INFO_SIZE; i++) {
+		vreg_info = &plat_priv->vreg_info[i];
+		reg = devm_regulator_get_optional(dev, vreg_info->name);
+		if (IS_ERR(reg)) {
+			ret = PTR_ERR(reg);
+			if (ret == -ENODEV)
+				continue;
+			else if (ret == -EPROBE_DEFER)
+				cnss_pr_info("EPROBE_DEFER for regulator: %s\n",
+					     vreg_info->name);
+			else
+				cnss_pr_err("Failed to get regulator %s, err = %d\n",
+					    vreg_info->name, ret);
+			goto out;
+		}
+
+		vreg_info->reg = reg;
+
+		snprintf(prop_name, MAX_PROP_SIZE, "qcom,%s-info",
+			 vreg_info->name);
+
+		prop = of_get_property(dev->of_node, prop_name, &len);
+		cnss_pr_dbg("Got regulator info, name: %s, len: %d\n",
+			    prop_name, len);
+
+		if (!prop || len != (4 * sizeof(__be32))) {
+			cnss_pr_dbg("Property %s %s, use default\n", prop_name,
+				    prop ? "invalid format" : "doesn't exist");
+		} else {
+			vreg_info->min_uv = be32_to_cpup(&prop[0]);
+			vreg_info->max_uv = be32_to_cpup(&prop[1]);
+			vreg_info->load_ua = be32_to_cpup(&prop[2]);
+			vreg_info->delay_us = be32_to_cpup(&prop[3]);
+		}
+
+		cnss_pr_dbg("Got regulator: %s, min_uv: %u, max_uv: %u, load_ua: %u, delay_us: %u\n",
+			    vreg_info->name, vreg_info->min_uv,
+			    vreg_info->max_uv, vreg_info->load_ua,
+			    vreg_info->delay_us);
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+static int cnss_vreg_on(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_vreg_info *vreg_info;
+	int i;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < CNSS_VREG_INFO_SIZE; i++) {
+		vreg_info = &plat_priv->vreg_info[i];
+
+		if (!vreg_info->reg)
+			continue;
+
+		cnss_pr_dbg("Regulator %s is being enabled\n", vreg_info->name);
+
+		if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0) {
+			ret = regulator_set_voltage(vreg_info->reg,
+						    vreg_info->min_uv,
+						    vreg_info->max_uv);
+
+			if (ret) {
+				cnss_pr_err("Failed to set voltage for regulator %s, min_uv: %u, max_uv: %u, err = %d\n",
+					    vreg_info->name, vreg_info->min_uv,
+					    vreg_info->max_uv, ret);
+				break;
+			}
+		}
+
+		if (vreg_info->load_ua) {
+			ret = regulator_set_load(vreg_info->reg,
+						 vreg_info->load_ua);
+
+			if (ret < 0) {
+				cnss_pr_err("Failed to set load for regulator %s, load: %u, err = %d\n",
+					    vreg_info->name, vreg_info->load_ua,
+					    ret);
+				break;
+			}
+		}
+
+		if (vreg_info->delay_us)
+			udelay(vreg_info->delay_us);
+
+		ret = regulator_enable(vreg_info->reg);
+		if (ret) {
+			cnss_pr_err("Failed to enable regulator %s, err = %d\n",
+				    vreg_info->name, ret);
+			break;
+		}
+	}
+
+	if (ret) {
+		for (; i >= 0; i--) {
+			vreg_info = &plat_priv->vreg_info[i];
+
+			if (!vreg_info->reg)
+				continue;
+
+			regulator_disable(vreg_info->reg);
+			if (vreg_info->load_ua)
+				regulator_set_load(vreg_info->reg, 0);
+			if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0)
+				regulator_set_voltage(vreg_info->reg, 0,
+						      vreg_info->max_uv);
+		}
+
+		return ret;
+	}
+
+	return 0;
+}
+
+static int cnss_vreg_off(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct cnss_vreg_info *vreg_info;
+	int i;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return -ENODEV;
+	}
+
+	for (i = CNSS_VREG_INFO_SIZE - 1; i >= 0; i--) {
+		vreg_info = &plat_priv->vreg_info[i];
+
+		if (!vreg_info->reg)
+			continue;
+
+		cnss_pr_dbg("Regulator %s is being disabled\n",
+			    vreg_info->name);
+
+		ret = regulator_disable(vreg_info->reg);
+		if (ret)
+			cnss_pr_err("Failed to disable regulator %s, err = %d\n",
+				    vreg_info->name, ret);
+
+		if (vreg_info->load_ua) {
+			ret = regulator_set_load(vreg_info->reg, 0);
+			if (ret < 0)
+				cnss_pr_err("Failed to set load for regulator %s, err = %d\n",
+					    vreg_info->name, ret);
+		}
+
+		if (vreg_info->min_uv != 0 && vreg_info->max_uv != 0) {
+			ret = regulator_set_voltage(vreg_info->reg, 0,
+						    vreg_info->max_uv);
+			if (ret)
+				cnss_pr_err("Failed to set voltage for regulator %s, err = %d\n",
+					    vreg_info->name, ret);
+		}
+	}
+
+	return ret;
+}
+
+int cnss_get_pinctrl(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+	struct device *dev;
+	struct cnss_pinctrl_info *pinctrl_info;
+
+	dev = &plat_priv->plat_dev->dev;
+	pinctrl_info = &plat_priv->pinctrl_info;
+
+	pinctrl_info->pinctrl = devm_pinctrl_get(dev);
+	if (IS_ERR_OR_NULL(pinctrl_info->pinctrl)) {
+		ret = PTR_ERR(pinctrl_info->pinctrl);
+		cnss_pr_err("Failed to get pinctrl, err = %d\n", ret);
+		goto out;
+	}
+
+	if (of_find_property(dev->of_node, BOOTSTRAP_GPIO, NULL)) {
+		pinctrl_info->bootstrap_active =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     BOOTSTRAP_ACTIVE);
+		if (IS_ERR_OR_NULL(pinctrl_info->bootstrap_active)) {
+			ret = PTR_ERR(pinctrl_info->bootstrap_active);
+			cnss_pr_err("Failed to get bootstrap active state, err = %d\n",
+				    ret);
+			goto out;
+		}
+	}
+
+	if (of_find_property(dev->of_node, WLAN_EN_GPIO, NULL)) {
+		pinctrl_info->wlan_en_active =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     WLAN_EN_ACTIVE);
+		if (IS_ERR_OR_NULL(pinctrl_info->wlan_en_active)) {
+			ret = PTR_ERR(pinctrl_info->wlan_en_active);
+			cnss_pr_err("Failed to get wlan_en active state, err = %d\n",
+				    ret);
+			goto out;
+		}
+
+		pinctrl_info->wlan_en_sleep =
+			pinctrl_lookup_state(pinctrl_info->pinctrl,
+					     WLAN_EN_SLEEP);
+		if (IS_ERR_OR_NULL(pinctrl_info->wlan_en_sleep)) {
+			ret = PTR_ERR(pinctrl_info->wlan_en_sleep);
+			cnss_pr_err("Failed to get wlan_en sleep state, err = %d\n",
+				    ret);
+			goto out;
+		}
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+static int cnss_select_pinctrl_state(struct cnss_plat_data *plat_priv,
+				     bool state)
+{
+	int ret = 0;
+	struct cnss_pinctrl_info *pinctrl_info;
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	pinctrl_info = &plat_priv->pinctrl_info;
+
+	if (state) {
+		if (!IS_ERR_OR_NULL(pinctrl_info->bootstrap_active)) {
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+						   pinctrl_info->
+						   bootstrap_active);
+			if (ret) {
+				cnss_pr_err("Failed to select bootstrap active state, err = %d\n",
+					    ret);
+				goto out;
+			}
+			udelay(BOOTSTRAP_DELAY);
+		}
+
+		if (!IS_ERR_OR_NULL(pinctrl_info->wlan_en_active)) {
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+						   pinctrl_info->
+						   wlan_en_active);
+			if (ret) {
+				cnss_pr_err("Failed to select wlan_en active state, err = %d\n",
+					    ret);
+				goto out;
+			}
+			udelay(WLAN_ENABLE_DELAY);
+		}
+	} else {
+		if (!IS_ERR_OR_NULL(pinctrl_info->wlan_en_sleep)) {
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+						   pinctrl_info->wlan_en_sleep);
+			if (ret) {
+				cnss_pr_err("Failed to select wlan_en sleep state, err = %d\n",
+					    ret);
+				goto out;
+			}
+		}
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+int cnss_power_on_device(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	ret = cnss_vreg_on(plat_priv);
+	if (ret) {
+		cnss_pr_err("Failed to turn on vreg, err = %d\n", ret);
+		goto out;
+	}
+
+	ret = cnss_select_pinctrl_state(plat_priv, true);
+	if (ret) {
+		cnss_pr_err("Failed to select pinctrl state, err = %d\n", ret);
+		goto vreg_off;
+	}
+
+	return 0;
+vreg_off:
+	cnss_vreg_off(plat_priv);
+out:
+	return ret;
+}
+
+void cnss_power_off_device(struct cnss_plat_data *plat_priv)
+{
+	cnss_select_pinctrl_state(plat_priv, false);
+	cnss_vreg_off(plat_priv);
+}
+
+void cnss_set_pin_connect_status(struct cnss_plat_data *plat_priv)
+{
+	unsigned long pin_status = 0;
+
+	set_bit(CNSS_WLAN_EN, &pin_status);
+	set_bit(CNSS_PCIE_TXN, &pin_status);
+	set_bit(CNSS_PCIE_TXP, &pin_status);
+	set_bit(CNSS_PCIE_RXN, &pin_status);
+	set_bit(CNSS_PCIE_RXP, &pin_status);
+	set_bit(CNSS_PCIE_REFCLKN, &pin_status);
+	set_bit(CNSS_PCIE_REFCLKP, &pin_status);
+	set_bit(CNSS_PCIE_RST, &pin_status);
+
+	plat_priv->pin_result.host_pin_result = pin_status;
+}
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
new file mode 100644
index 0000000..f4344ae
--- /dev/null
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -0,0 +1,1037 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/qmi_encdec.h>
+#include <soc/qcom/msm_qmi_interface.h>
+
+#include "main.h"
+#include "debug.h"
+#include "qmi.h"
+
+#define WLFW_SERVICE_INS_ID_V01		1
+#define WLFW_CLIENT_ID			0x4b4e454c
+#define MAX_BDF_FILE_NAME		11
+#define DEFAULT_BDF_FILE_NAME		"bdwlan.elf"
+#define BDF_FILE_NAME_PREFIX		"bdwlan.e"
+
+#ifdef CONFIG_CNSS2_DEBUG
+static unsigned int qmi_timeout = 10000;
+module_param(qmi_timeout, uint, 0600);
+MODULE_PARM_DESC(qmi_timeout, "Timeout for QMI message in milliseconds");
+
+#define QMI_WLFW_TIMEOUT_MS		qmi_timeout
+#else
+#define QMI_WLFW_TIMEOUT_MS		10000
+#endif
+
+static bool daemon_support;
+module_param(daemon_support, bool, 0600);
+MODULE_PARM_DESC(daemon_support, "User space has cnss-daemon support or not");
+
+static bool bdf_bypass;
+#ifdef CONFIG_CNSS2_DEBUG
+module_param(bdf_bypass, bool, 0600);
+MODULE_PARM_DESC(bdf_bypass, "If BDF is not found, send dummy BDF to FW");
+#endif
+
+enum cnss_bdf_type {
+	CNSS_BDF_BIN,
+	CNSS_BDF_ELF,
+};
+
+static char *cnss_qmi_mode_to_str(enum wlfw_driver_mode_enum_v01 mode)
+{
+	switch (mode) {
+	case QMI_WLFW_MISSION_V01:
+		return "MISSION";
+	case QMI_WLFW_FTM_V01:
+		return "FTM";
+	case QMI_WLFW_EPPING_V01:
+		return "EPPING";
+	case QMI_WLFW_WALTEST_V01:
+		return "WALTEST";
+	case QMI_WLFW_OFF_V01:
+		return "OFF";
+	case QMI_WLFW_CCPM_V01:
+		return "CCPM";
+	case QMI_WLFW_QVIT_V01:
+		return "QVIT";
+	case QMI_WLFW_CALIBRATION_V01:
+		return "CALIBRATION";
+	default:
+		return "UNKNOWN";
+	}
+};
+
+static void cnss_wlfw_clnt_notifier_work(struct work_struct *work)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(work, struct cnss_plat_data, qmi_recv_msg_work);
+	int ret = 0;
+
+	cnss_pr_dbg("Receiving QMI WLFW event in work queue context\n");
+
+	do {
+		ret = qmi_recv_msg(plat_priv->qmi_wlfw_clnt);
+	} while (ret == 0);
+
+	if (ret != -ENOMSG)
+		cnss_pr_err("Error receiving message: %d\n", ret);
+
+	cnss_pr_dbg("Receiving QMI event completed\n");
+}
+
+static void cnss_wlfw_clnt_notifier(struct qmi_handle *handle,
+				    enum qmi_event_type event,
+				    void *notify_priv)
+{
+	struct cnss_plat_data *plat_priv = notify_priv;
+
+	cnss_pr_dbg("Received QMI WLFW event: %d\n", event);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return;
+	}
+
+	switch (event) {
+	case QMI_RECV_MSG:
+		schedule_work(&plat_priv->qmi_recv_msg_work);
+		break;
+	case QMI_SERVER_EXIT:
+		break;
+	default:
+		cnss_pr_dbg("Unhandled QMI event: %d\n", event);
+		break;
+	}
+}
+
+static int cnss_wlfw_clnt_svc_event_notifier(struct notifier_block *nb,
+					     unsigned long code, void *_cmd)
+{
+	struct cnss_plat_data *plat_priv =
+		container_of(nb, struct cnss_plat_data, qmi_wlfw_clnt_nb);
+	int ret = 0;
+
+	cnss_pr_dbg("Received QMI WLFW service event: %ld\n", code);
+
+	switch (code) {
+	case QMI_SERVER_ARRIVE:
+		ret = cnss_driver_event_post(plat_priv,
+					     CNSS_DRIVER_EVENT_SERVER_ARRIVE,
+					     0, NULL);
+		break;
+
+	case QMI_SERVER_EXIT:
+		ret = cnss_driver_event_post(plat_priv,
+					     CNSS_DRIVER_EVENT_SERVER_EXIT,
+					     0, NULL);
+		break;
+	default:
+		cnss_pr_dbg("Invalid QMI service event: %ld\n", code);
+		break;
+	}
+
+	return ret;
+}
+
+static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_host_cap_req_msg_v01 req;
+	struct wlfw_host_cap_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending host capability message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	memset(&req, 0, sizeof(req));
+	memset(&resp, 0, sizeof(resp));
+
+	req.daemon_support_valid = 1;
+	req.daemon_support = daemon_support;
+
+	cnss_pr_dbg("daemon_support is %d\n", req.daemon_support);
+
+	req.wake_msi = cnss_get_wake_msi(plat_priv);
+	if (req.wake_msi) {
+		cnss_pr_dbg("WAKE MSI base data is %d\n", req.wake_msi);
+		req.wake_msi_valid = 1;
+	}
+
+	req_desc.max_msg_len = WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_HOST_CAP_REQ_V01;
+	req_desc.ei_array = wlfw_host_cap_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_HOST_CAP_RESP_V01;
+	resp_desc.ei_array = wlfw_host_cap_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+				sizeof(req), &resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Failed to send host capability request, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Host capability request failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+	return 0;
+out:
+	CNSS_ASSERT(0);
+	return ret;
+}
+
+static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_ind_register_req_msg_v01 req;
+	struct wlfw_ind_register_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending indication register message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	memset(&req, 0, sizeof(req));
+	memset(&resp, 0, sizeof(resp));
+
+	req.client_id_valid = 1;
+	req.client_id = WLFW_CLIENT_ID;
+	req.fw_ready_enable_valid = 1;
+	req.fw_ready_enable = 1;
+	req.request_mem_enable_valid = 1;
+	req.request_mem_enable = 1;
+	req.fw_mem_ready_enable_valid = 1;
+	req.fw_mem_ready_enable = 1;
+	req.cold_boot_cal_done_enable_valid = 1;
+	req.cold_boot_cal_done_enable = 1;
+	req.pin_connect_result_enable_valid = 1;
+	req.pin_connect_result_enable = 1;
+
+	req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01;
+	req_desc.ei_array = wlfw_ind_register_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_IND_REGISTER_RESP_V01;
+	resp_desc.ei_array = wlfw_ind_register_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+				sizeof(req), &resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Failed to send indication register request, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Indication register request failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+	return 0;
+out:
+	CNSS_ASSERT(0);
+	return ret;
+}
+
+static int cnss_wlfw_request_mem_ind_hdlr(struct cnss_plat_data *plat_priv,
+					  void *msg, unsigned int msg_len)
+{
+	struct msg_desc ind_desc;
+	struct wlfw_request_mem_ind_msg_v01 ind_msg;
+	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+	int ret = 0;
+
+	ind_desc.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01;
+	ind_desc.max_msg_len = WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN;
+	ind_desc.ei_array = wlfw_request_mem_ind_msg_v01_ei;
+
+	ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+	if (ret < 0) {
+		cnss_pr_err("Failed to decode request memory indication, msg_len: %u, err = %d\n",
+			    ret, msg_len);
+		return ret;
+	}
+
+	fw_mem->size = ind_msg.size;
+
+	cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,
+			       0, NULL);
+
+	return 0;
+}
+
+static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv,
+					void *msg, unsigned int msg_len)
+{
+	struct msg_desc ind_desc;
+	struct wlfw_pin_connect_result_ind_msg_v01 ind_msg;
+	int ret = 0;
+
+	ind_desc.msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01;
+	ind_desc.max_msg_len = WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN;
+	ind_desc.ei_array = wlfw_pin_connect_result_ind_msg_v01_ei;
+
+	ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+	if (ret < 0) {
+		cnss_pr_err("Failed to decode pin connect result indication, msg_len: %u, err = %d\n",
+			    msg_len, ret);
+		return ret;
+	}
+	if (ind_msg.pwr_pin_result_valid)
+		plat_priv->pin_result.fw_pwr_pin_result =
+		    ind_msg.pwr_pin_result;
+	if (ind_msg.phy_io_pin_result_valid)
+		plat_priv->pin_result.fw_phy_io_pin_result =
+		    ind_msg.phy_io_pin_result;
+	if (ind_msg.rf_pin_result_valid)
+		plat_priv->pin_result.fw_rf_pin_result = ind_msg.rf_pin_result;
+
+	cnss_pr_dbg("Pin connect Result: pwr_pin: 0x%x phy_io_pin: 0x%x rf_io_pin: 0x%x\n",
+		    ind_msg.pwr_pin_result, ind_msg.phy_io_pin_result,
+		    ind_msg.rf_pin_result);
+	return ret;
+}
+
+int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_respond_mem_req_msg_v01 req;
+	struct wlfw_respond_mem_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	if (!fw_mem->pa || !fw_mem->size) {
+		cnss_pr_err("Memory for FW is not available!\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+		    fw_mem->va, &fw_mem->pa, fw_mem->size);
+
+	memset(&req, 0, sizeof(req));
+	memset(&resp, 0, sizeof(resp));
+
+	req.addr = fw_mem->pa;
+	req.size = fw_mem->size;
+
+	req_desc.max_msg_len = WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_RESPOND_MEM_REQ_V01;
+	req_desc.ei_array = wlfw_respond_mem_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_RESPOND_MEM_RESP_V01;
+	resp_desc.ei_array = wlfw_respond_mem_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+				sizeof(req), &resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Failed to send respond memory request, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Respond memory request failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+	return 0;
+out:
+	CNSS_ASSERT(0);
+	return ret;
+}
+
+int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_cap_req_msg_v01 req;
+	struct wlfw_cap_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending target capability message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	memset(&req, 0, sizeof(req));
+	memset(&resp, 0, sizeof(resp));
+
+	req_desc.max_msg_len = WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_CAP_REQ_V01;
+	req_desc.ei_array = wlfw_cap_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_CAP_RESP_V01;
+	resp_desc.ei_array = wlfw_cap_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+				sizeof(req), &resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Failed to send target capability request, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Target capability request failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+	if (resp.chip_info_valid)
+		plat_priv->chip_info = resp.chip_info;
+	if (resp.board_info_valid)
+		plat_priv->board_info = resp.board_info;
+	else
+		plat_priv->board_info.board_id = 0xFF;
+	if (resp.soc_info_valid)
+		plat_priv->soc_info = resp.soc_info;
+	if (resp.fw_version_info_valid)
+		plat_priv->fw_version_info = resp.fw_version_info;
+
+	cnss_pr_dbg("Target capability: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x, fw_version: 0x%x, fw_build_timestamp: %s",
+		    plat_priv->chip_info.chip_id,
+		    plat_priv->chip_info.chip_family,
+		    plat_priv->board_info.board_id, plat_priv->soc_info.soc_id,
+		    plat_priv->fw_version_info.fw_version,
+		    plat_priv->fw_version_info.fw_build_timestamp);
+
+	return 0;
+out:
+	CNSS_ASSERT(0);
+	return ret;
+}
+
+int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_bdf_download_req_msg_v01 *req;
+	struct wlfw_bdf_download_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	char filename[MAX_BDF_FILE_NAME];
+	const struct firmware *fw_entry;
+	const u8 *temp;
+	unsigned int remaining;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending BDF download message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (plat_priv->board_info.board_id == 0xFF)
+		snprintf(filename, sizeof(filename), DEFAULT_BDF_FILE_NAME);
+	else
+		snprintf(filename, sizeof(filename),
+			 BDF_FILE_NAME_PREFIX "%02x",
+			 plat_priv->board_info.board_id);
+
+	ret = request_firmware(&fw_entry, filename, &plat_priv->plat_dev->dev);
+	if (ret) {
+		cnss_pr_err("Failed to load BDF: %s\n", filename);
+		if (bdf_bypass) {
+			cnss_pr_info("bdf_bypass is enabled, sending dummy BDF\n");
+			temp = filename;
+			remaining = MAX_BDF_FILE_NAME;
+			goto bypass_bdf;
+		} else {
+			goto err_req_fw;
+		}
+	}
+
+	temp = fw_entry->data;
+	remaining = fw_entry->size;
+
+bypass_bdf:
+	cnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining);
+
+	memset(&resp, 0, sizeof(resp));
+
+	req_desc.max_msg_len = WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_BDF_DOWNLOAD_REQ_V01;
+	req_desc.ei_array = wlfw_bdf_download_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_BDF_DOWNLOAD_RESP_V01;
+	resp_desc.ei_array = wlfw_bdf_download_resp_msg_v01_ei;
+
+	while (remaining) {
+		req->valid = 1;
+		req->file_id_valid = 1;
+		req->file_id = plat_priv->board_info.board_id;
+		req->total_size_valid = 1;
+		req->total_size = remaining;
+		req->seg_id_valid = 1;
+		req->data_valid = 1;
+		req->end_valid = 1;
+		req->bdf_type_valid = 1;
+		req->bdf_type = CNSS_BDF_ELF;
+
+		if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
+			req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
+		} else {
+			req->data_len = remaining;
+			req->end = 1;
+		}
+
+		memcpy(req->data, temp, req->data_len);
+
+		ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc,
+					req, sizeof(*req), &resp_desc, &resp,
+					sizeof(resp), QMI_WLFW_TIMEOUT_MS);
+		if (ret < 0) {
+			cnss_pr_err("Failed to send BDF download request, err = %d\n",
+				    ret);
+			goto err_send;
+		}
+
+		if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+			cnss_pr_err("BDF download request failed, result: %d, err: %d\n",
+				    resp.resp.result, resp.resp.error);
+			ret = resp.resp.result;
+			goto err_send;
+		}
+
+		remaining -= req->data_len;
+		temp += req->data_len;
+		req->seg_id++;
+	}
+
+err_send:
+	if (!bdf_bypass)
+		release_firmware(fw_entry);
+err_req_fw:
+	kfree(req);
+out:
+	if (ret)
+		CNSS_ASSERT(0);
+	return ret;
+}
+
+int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv)
+{
+	struct wlfw_m3_info_req_msg_v01 req;
+	struct wlfw_m3_info_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending M3 information message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	if (!m3_mem->pa || !m3_mem->size) {
+		cnss_pr_err("Memory for M3 is not available!\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	cnss_pr_dbg("M3 memory, va: 0x%pK, pa: %pa, size: 0x%zx\n",
+		    m3_mem->va, &m3_mem->pa, m3_mem->size);
+
+	memset(&req, 0, sizeof(req));
+	memset(&resp, 0, sizeof(resp));
+
+	req.addr = plat_priv->m3_mem.pa;
+	req.size = plat_priv->m3_mem.size;
+
+	req_desc.max_msg_len = WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_M3_INFO_REQ_V01;
+	req_desc.ei_array = wlfw_m3_info_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_M3_INFO_RESP_V01;
+	resp_desc.ei_array = wlfw_m3_info_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+				sizeof(req), &resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Failed to send M3 information request, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("M3 information request failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+	return 0;
+
+out:
+	CNSS_ASSERT(0);
+	return ret;
+}
+
+int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
+				  enum wlfw_driver_mode_enum_v01 mode)
+{
+	struct wlfw_wlan_mode_req_msg_v01 req;
+	struct wlfw_wlan_mode_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending mode message, mode: %s(%d), state: 0x%lx\n",
+		    cnss_qmi_mode_to_str(mode), mode, plat_priv->driver_state);
+
+	if (mode == QMI_WLFW_OFF_V01 &&
+	    test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
+		cnss_pr_dbg("Recovery is in progress, ignore mode off request.\n");
+		return 0;
+	}
+
+	memset(&req, 0, sizeof(req));
+	memset(&resp, 0, sizeof(resp));
+
+	req.mode = mode;
+	req.hw_debug_valid = 1;
+	req.hw_debug = 0;
+
+	req_desc.max_msg_len = WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_WLAN_MODE_REQ_V01;
+	req_desc.ei_array = wlfw_wlan_mode_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_WLAN_MODE_RESP_V01;
+	resp_desc.ei_array = wlfw_wlan_mode_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+				sizeof(req), &resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		if (mode == QMI_WLFW_OFF_V01 && ret == -ENETRESET) {
+			cnss_pr_dbg("WLFW service is disconnected while sending mode off request.\n");
+			return 0;
+		}
+		cnss_pr_err("Failed to send mode request, mode: %s(%d), err: %d\n",
+			    cnss_qmi_mode_to_str(mode), mode, ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("Mode request failed, mode: %s(%d), result: %d, err: %d\n",
+			    cnss_qmi_mode_to_str(mode), mode, resp.resp.result,
+			    resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+	return 0;
+out:
+	if (mode != QMI_WLFW_OFF_V01)
+		CNSS_ASSERT(0);
+	return ret;
+}
+
+int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
+				 struct wlfw_wlan_cfg_req_msg_v01 *data)
+{
+	struct wlfw_wlan_cfg_req_msg_v01 req;
+	struct wlfw_wlan_cfg_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	int ret = 0;
+
+	cnss_pr_dbg("Sending WLAN config message, state: 0x%lx\n",
+		    plat_priv->driver_state);
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	memset(&req, 0, sizeof(req));
+	memset(&resp, 0, sizeof(resp));
+
+	memcpy(&req, data, sizeof(req));
+
+	req_desc.max_msg_len = WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_WLAN_CFG_REQ_V01;
+	req_desc.ei_array = wlfw_wlan_cfg_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_WLAN_CFG_RESP_V01;
+	resp_desc.ei_array = wlfw_wlan_cfg_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+				sizeof(req), &resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Failed to send WLAN config request, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("WLAN config request failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+	return 0;
+out:
+	CNSS_ASSERT(0);
+	return ret;
+}
+
+int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
+				     u32 offset, u32 mem_type,
+				     u32 data_len, u8 *data)
+{
+	struct wlfw_athdiag_read_req_msg_v01 req;
+	struct wlfw_athdiag_read_resp_msg_v01 *resp;
+	struct msg_desc req_desc, resp_desc;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!plat_priv->qmi_wlfw_clnt)
+		return -EINVAL;
+
+	cnss_pr_dbg("athdiag read: state 0x%lx, offset %x, mem_type %x, data_len %u\n",
+		    plat_priv->driver_state, offset, mem_type, data_len);
+
+	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	memset(&req, 0, sizeof(req));
+
+	req.offset = offset;
+	req.mem_type = mem_type;
+	req.data_len = data_len;
+
+	req_desc.max_msg_len = WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_ATHDIAG_READ_REQ_V01;
+	req_desc.ei_array = wlfw_athdiag_read_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_ATHDIAG_READ_RESP_V01;
+	resp_desc.ei_array = wlfw_athdiag_read_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
+				sizeof(req), &resp_desc, resp, sizeof(*resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Failed to send athdiag read request, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("athdiag read request failed, result: %d, err: %d\n",
+			    resp->resp.result, resp->resp.error);
+		ret = resp->resp.result;
+		goto out;
+	}
+
+	if (!resp->data_valid || resp->data_len != data_len) {
+		cnss_pr_err("athdiag read data is invalid, data_valid = %u, data_len = %u\n",
+			    resp->data_valid, resp->data_len);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	memcpy(data, resp->data, resp->data_len);
+
+out:
+	kfree(resp);
+	return ret;
+}
+
+int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
+				      u32 offset, u32 mem_type,
+				      u32 data_len, u8 *data)
+{
+	struct wlfw_athdiag_write_req_msg_v01 *req;
+	struct wlfw_athdiag_write_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	if (!plat_priv->qmi_wlfw_clnt)
+		return -EINVAL;
+
+	cnss_pr_dbg("athdiag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %p\n",
+		    plat_priv->driver_state, offset, mem_type, data_len, data);
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	memset(&resp, 0, sizeof(resp));
+
+	req->offset = offset;
+	req->mem_type = mem_type;
+	req->data_len = data_len;
+	memcpy(req->data, data, data_len);
+
+	req_desc.max_msg_len = WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_ATHDIAG_WRITE_REQ_V01;
+	req_desc.ei_array = wlfw_athdiag_write_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_ATHDIAG_WRITE_RESP_V01;
+	resp_desc.ei_array = wlfw_athdiag_write_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, req,
+				sizeof(*req), &resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Failed to send athdiag write request, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("athdiag write request failed, result: %d, err: %d\n",
+			    resp.resp.result, resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+out:
+	kfree(req);
+	return ret;
+}
+
+int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
+			    u8 fw_log_mode)
+{
+	int ret;
+	struct wlfw_ini_req_msg_v01 req;
+	struct wlfw_ini_resp_msg_v01 resp;
+	struct msg_desc req_desc, resp_desc;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	cnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log_mode: %d\n",
+		    plat_priv->driver_state, fw_log_mode);
+
+	memset(&req, 0, sizeof(req));
+	memset(&resp, 0, sizeof(resp));
+
+	req.enablefwlog_valid = 1;
+	req.enablefwlog = fw_log_mode;
+
+	req_desc.max_msg_len = WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN;
+	req_desc.msg_id = QMI_WLFW_INI_REQ_V01;
+	req_desc.ei_array = wlfw_ini_req_msg_v01_ei;
+
+	resp_desc.max_msg_len = WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN;
+	resp_desc.msg_id = QMI_WLFW_INI_RESP_V01;
+	resp_desc.ei_array = wlfw_ini_resp_msg_v01_ei;
+
+	ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt,
+				&req_desc, &req, sizeof(req),
+				&resp_desc, &resp, sizeof(resp),
+				QMI_WLFW_TIMEOUT_MS);
+	if (ret < 0) {
+		cnss_pr_err("Send INI req failed fw_log_mode: %d, ret: %d\n",
+			    fw_log_mode, ret);
+		goto out;
+	}
+
+	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+		cnss_pr_err("QMI INI request rejected, fw_log_mode:%d result:%d error:%d\n",
+			    fw_log_mode, resp.resp.result, resp.resp.error);
+		ret = resp.resp.result;
+		goto out;
+	}
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
+			       unsigned int msg_id, void *msg,
+			       unsigned int msg_len, void *ind_cb_priv)
+{
+	struct cnss_plat_data *plat_priv = ind_cb_priv;
+
+	cnss_pr_dbg("Received QMI WLFW indication, msg_id: 0x%x, msg_len: %d\n",
+		    msg_id, msg_len);
+
+	if (!plat_priv) {
+		cnss_pr_err("plat_priv is NULL!\n");
+		return;
+	}
+
+	switch (msg_id) {
+	case QMI_WLFW_REQUEST_MEM_IND_V01:
+		cnss_wlfw_request_mem_ind_hdlr(plat_priv, msg, msg_len);
+		break;
+	case QMI_WLFW_FW_MEM_READY_IND_V01:
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_FW_MEM_READY,
+				       0, NULL);
+		break;
+	case QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01:
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
+				       0, NULL);
+		break;
+	case QMI_WLFW_FW_READY_IND_V01:
+		cnss_driver_event_post(plat_priv,
+				       CNSS_DRIVER_EVENT_FW_READY,
+				       0, NULL);
+		break;
+	case QMI_WLFW_PIN_CONNECT_RESULT_IND_V01:
+		cnss_qmi_pin_result_ind_hdlr(plat_priv, msg, msg_len);
+		break;
+	default:
+		cnss_pr_err("Invalid QMI WLFW indication, msg_id: 0x%x\n",
+			    msg_id);
+		break;
+	}
+}
+
+unsigned int cnss_get_qmi_timeout(void)
+{
+	cnss_pr_dbg("QMI timeout is %u ms\n", QMI_WLFW_TIMEOUT_MS);
+
+	return QMI_WLFW_TIMEOUT_MS;
+}
+EXPORT_SYMBOL(cnss_get_qmi_timeout);
+
+int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	if (!plat_priv)
+		return -ENODEV;
+
+	plat_priv->qmi_wlfw_clnt =
+		qmi_handle_create(cnss_wlfw_clnt_notifier, plat_priv);
+	if (!plat_priv->qmi_wlfw_clnt) {
+		cnss_pr_err("Failed to create QMI client handle!\n");
+		ret = -ENOMEM;
+		goto err_create_handle;
+	}
+
+	ret = qmi_connect_to_service(plat_priv->qmi_wlfw_clnt,
+				     WLFW_SERVICE_ID_V01,
+				     WLFW_SERVICE_VERS_V01,
+				     WLFW_SERVICE_INS_ID_V01);
+	if (ret < 0) {
+		cnss_pr_err("Failed to connect to QMI WLFW service, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	ret = qmi_register_ind_cb(plat_priv->qmi_wlfw_clnt,
+				  cnss_wlfw_clnt_ind, plat_priv);
+	if (ret < 0) {
+		cnss_pr_err("Failed to register QMI WLFW service indication callback, err = %d\n",
+			    ret);
+		goto out;
+	}
+
+	set_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state);
+
+	cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n",
+		     plat_priv->driver_state);
+
+	ret = cnss_wlfw_host_cap_send_sync(plat_priv);
+	if (ret < 0)
+		goto out;
+
+	ret = cnss_wlfw_ind_register_send_sync(plat_priv);
+	if (ret < 0)
+		goto out;
+
+	return 0;
+out:
+	qmi_handle_destroy(plat_priv->qmi_wlfw_clnt);
+	plat_priv->qmi_wlfw_clnt = NULL;
+err_create_handle:
+	CNSS_ASSERT(0);
+	return ret;
+}
+
+int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv)
+{
+	if (!plat_priv)
+		return -ENODEV;
+
+	qmi_handle_destroy(plat_priv->qmi_wlfw_clnt);
+	plat_priv->qmi_wlfw_clnt = NULL;
+
+	clear_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state);
+
+	cnss_pr_info("QMI WLFW service disconnected, state: 0x%lx\n",
+		     plat_priv->driver_state);
+
+	return 0;
+}
+
+int cnss_qmi_init(struct cnss_plat_data *plat_priv)
+{
+	int ret = 0;
+
+	INIT_WORK(&plat_priv->qmi_recv_msg_work,
+		  cnss_wlfw_clnt_notifier_work);
+
+	plat_priv->qmi_wlfw_clnt_nb.notifier_call =
+		cnss_wlfw_clnt_svc_event_notifier;
+
+	ret = qmi_svc_event_notifier_register(WLFW_SERVICE_ID_V01,
+					      WLFW_SERVICE_VERS_V01,
+					      WLFW_SERVICE_INS_ID_V01,
+					      &plat_priv->qmi_wlfw_clnt_nb);
+	if (ret < 0)
+		cnss_pr_err("Failed to register QMI event notifier, err = %d\n",
+			    ret);
+
+	return ret;
+}
+
+void cnss_qmi_deinit(struct cnss_plat_data *plat_priv)
+{
+	qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01,
+					  WLFW_SERVICE_VERS_V01,
+					  WLFW_SERVICE_INS_ID_V01,
+					  &plat_priv->qmi_wlfw_clnt_nb);
+}
diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h
new file mode 100644
index 0000000..70d8d40
--- /dev/null
+++ b/drivers/net/wireless/cnss2/qmi.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CNSS_QMI_H
+#define _CNSS_QMI_H
+
+#include "wlan_firmware_service_v01.h"
+
+struct cnss_plat_data;
+
+int cnss_qmi_init(struct cnss_plat_data *plat_priv);
+void cnss_qmi_deinit(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv);
+int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
+				  enum wlfw_driver_mode_enum_v01 mode);
+int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
+				 struct wlfw_wlan_cfg_req_msg_v01 *data);
+int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
+				     u32 offset, u32 mem_type,
+				     u32 data_len, u8 *data);
+int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
+				      u32 offset, u32 mem_type,
+				      u32 data_len, u8 *data);
+int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
+			    u8 fw_log_mode);
+
+#endif /* _CNSS_QMI_H */
diff --git a/drivers/net/wireless/cnss2/utils.c b/drivers/net/wireless/cnss2/utils.c
new file mode 100644
index 0000000..9ffe386
--- /dev/null
+++ b/drivers/net/wireless/cnss2/utils.c
@@ -0,0 +1,129 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define CNSS_MAX_CH_NUM			45
+
+#include <linux/module.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(unsafe_channel_list_lock);
+static DEFINE_MUTEX(dfs_nol_info_lock);
+
+static struct cnss_unsafe_channel_list {
+	u16 unsafe_ch_count;
+	u16 unsafe_ch_list[CNSS_MAX_CH_NUM];
+} unsafe_channel_list;
+
+static struct cnss_dfs_nol_info {
+	void *dfs_nol_info;
+	u16 dfs_nol_info_len;
+} dfs_nol_info;
+
+int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
+{
+	mutex_lock(&unsafe_channel_list_lock);
+	if ((!unsafe_ch_list) || (ch_count > CNSS_MAX_CH_NUM)) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	unsafe_channel_list.unsafe_ch_count = ch_count;
+
+	if (ch_count != 0) {
+		memcpy((char *)unsafe_channel_list.unsafe_ch_list,
+		       (char *)unsafe_ch_list, ch_count * sizeof(u16));
+	}
+	mutex_unlock(&unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_set_wlan_unsafe_channel);
+
+int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list,
+				 u16 *ch_count, u16 buf_len)
+{
+	mutex_lock(&unsafe_channel_list_lock);
+	if (!unsafe_ch_list || !ch_count) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -EINVAL;
+	}
+
+	if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
+		mutex_unlock(&unsafe_channel_list_lock);
+		return -ENOMEM;
+	}
+
+	*ch_count = unsafe_channel_list.unsafe_ch_count;
+	memcpy((char *)unsafe_ch_list,
+	       (char *)unsafe_channel_list.unsafe_ch_list,
+	       unsafe_channel_list.unsafe_ch_count * sizeof(u16));
+	mutex_unlock(&unsafe_channel_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_get_wlan_unsafe_channel);
+
+int cnss_wlan_set_dfs_nol(const void *info, u16 info_len)
+{
+	void *temp;
+	struct cnss_dfs_nol_info *dfs_info;
+
+	mutex_lock(&dfs_nol_info_lock);
+	if (!info || !info_len) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -EINVAL;
+	}
+
+	temp = kmalloc(info_len, GFP_KERNEL);
+	if (!temp) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -ENOMEM;
+	}
+
+	memcpy(temp, info, info_len);
+	dfs_info = &dfs_nol_info;
+	kfree(dfs_info->dfs_nol_info);
+
+	dfs_info->dfs_nol_info = temp;
+	dfs_info->dfs_nol_info_len = info_len;
+	mutex_unlock(&dfs_nol_info_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cnss_wlan_set_dfs_nol);
+
+int cnss_wlan_get_dfs_nol(void *info, u16 info_len)
+{
+	int len;
+	struct cnss_dfs_nol_info *dfs_info;
+
+	mutex_lock(&dfs_nol_info_lock);
+	if (!info || !info_len) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -EINVAL;
+	}
+
+	dfs_info = &dfs_nol_info;
+
+	if (!dfs_info->dfs_nol_info || dfs_info->dfs_nol_info_len == 0) {
+		mutex_unlock(&dfs_nol_info_lock);
+		return -ENOENT;
+	}
+
+	len = min(info_len, dfs_info->dfs_nol_info_len);
+
+	memcpy(info, dfs_info->dfs_nol_info, len);
+	mutex_unlock(&dfs_nol_info_lock);
+
+	return len;
+}
+EXPORT_SYMBOL(cnss_wlan_get_dfs_nol);
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
new file mode 100644
index 0000000..7d6a771
--- /dev/null
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
@@ -0,0 +1,2221 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "wlan_firmware_service_v01.h"
+
+static struct elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+					   pipe_num),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_pipedir_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+					   pipe_dir),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+					   nentries),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+					   nbytes_max),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+					   flags),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+					   service_id),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_pipedir_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+					   pipe_dir),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+					   pipe_num),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_shadow_reg_cfg_s_v01,
+					   id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_shadow_reg_cfg_s_v01,
+					   offset),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_shadow_reg_v2_cfg_s_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_memory_region_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_memory_region_info_s_v01,
+					   region_addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_memory_region_info_s_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_memory_region_info_s_v01,
+					   secure_flag),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_rf_chip_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_rf_chip_info_s_v01,
+					   chip_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_rf_chip_info_s_v01,
+					   chip_family),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_rf_board_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_rf_board_info_s_v01,
+					   board_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_soc_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_soc_info_s_v01,
+					   soc_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+static struct elem_info wlfw_fw_version_info_s_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_fw_version_info_s_v01,
+					   fw_version),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0,
+		.offset         = offsetof(struct wlfw_fw_version_info_s_v01,
+					   fw_build_timestamp),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_ind_register_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_req_msg_v01,
+					   fw_ready_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   fw_ready_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   initiate_cal_download_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   initiate_cal_download_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   initiate_cal_update_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   initiate_cal_update_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   msa_ready_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   msa_ready_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   pin_connect_result_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   pin_connect_result_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   client_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   client_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   request_mem_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x16,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   request_mem_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   fw_mem_ready_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x17,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   fw_mem_ready_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   cold_boot_cal_done_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x18,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   cold_boot_cal_done_enable),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   rejuvenate_enable_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x19,
+		.offset         = offsetof(struct wlfw_ind_register_req_msg_v01,
+					   rejuvenate_enable),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_ind_register_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_resp_msg_v01,
+					   fw_status_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_ind_register_resp_msg_v01,
+					   fw_status),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_fw_ready_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_msa_ready_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   pwr_pin_result_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   pwr_pin_result),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   phy_io_pin_result_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   phy_io_pin_result),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   rf_pin_result_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct
+					   wlfw_pin_connect_result_ind_msg_v01,
+					   rf_pin_result),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_wlan_mode_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_driver_mode_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+					   mode),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+					   hw_debug_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+					   hw_debug),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_wlan_mode_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   host_version_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_STR_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   host_version),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   tgt_cfg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   tgt_cfg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_CE_V01,
+		.elem_size      = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   tgt_cfg),
+		.ei_array      = wlfw_ce_tgt_pipe_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   svc_cfg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   svc_cfg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_SVC_V01,
+		.elem_size      = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   svc_cfg),
+		.ei_array      = wlfw_ce_svc_pipe_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_SHADOW_REG_V01,
+		.elem_size      = sizeof(struct wlfw_shadow_reg_cfg_s_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg),
+		.ei_array      = wlfw_shadow_reg_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v2_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v2_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01,
+		.elem_size      = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+					   shadow_reg_v2),
+		.ei_array      = wlfw_shadow_reg_v2_cfg_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_wlan_cfg_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cap_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cap_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   chip_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_rf_chip_info_s_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   chip_info),
+		.ei_array      = wlfw_rf_chip_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   board_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_rf_board_info_s_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   board_info),
+		.ei_array      = wlfw_rf_board_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   soc_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_soc_info_s_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   soc_info),
+		.ei_array      = wlfw_soc_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   fw_version_info_valid),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct wlfw_fw_version_info_s_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   fw_version_info),
+		.ei_array      = wlfw_fw_version_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   fw_build_id_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   fw_build_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   num_macs_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct wlfw_cap_resp_msg_v01,
+					   num_macs),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_bdf_download_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   valid),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   file_id_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   bdf_type_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x15,
+		.offset         = offsetof(struct wlfw_bdf_download_req_msg_v01,
+					   bdf_type),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_bdf_download_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_bdf_download_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cal_report_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_cal_report_req_msg_v01,
+					   meta_data_len),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = QMI_WLFW_MAX_NUM_CAL_V01,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_cal_report_req_msg_v01,
+					   meta_data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_cal_report_req_msg_v01,
+					   xo_cal_data_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_cal_report_req_msg_v01,
+					   xo_cal_data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cal_report_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_cal_report_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(
+				  struct wlfw_initiate_cal_download_ind_msg_v01,
+				  cal_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cal_download_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   valid),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   file_id_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_cal_download_req_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cal_download_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_cal_download_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_update_ind_msg_v01,
+					   cal_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_initiate_cal_update_ind_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cal_update_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_cal_update_req_msg_v01,
+					   cal_id),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_cal_update_req_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cal_update_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   file_id_valid),
+	},
+	{
+		.data_type      = QMI_SIGNED_4_BYTE_ENUM,
+		.elem_len       = 1,
+		.elem_size      = sizeof(enum wlfw_cal_temp_id_enum_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   file_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   total_size_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   total_size),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   seg_id_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   seg_id),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   end_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x14,
+		.offset         = offsetof(struct wlfw_cal_update_resp_msg_v01,
+					   end),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_msa_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_msa_info_req_msg_v01,
+					   msa_addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_msa_info_req_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_msa_info_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_msa_info_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct wlfw_msa_info_resp_msg_v01,
+					   mem_region_info_len),
+	},
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01,
+		.elem_size      = sizeof(struct wlfw_memory_region_info_s_v01),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct wlfw_msa_info_resp_msg_v01,
+					   mem_region_info),
+		.ei_array      = wlfw_memory_region_info_s_v01_ei,
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_msa_ready_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_msa_ready_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_msa_ready_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_ini_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_ini_req_msg_v01,
+					   enablefwlog_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_ini_req_msg_v01,
+					   enablefwlog),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_ini_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_ini_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_athdiag_read_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+					   offset),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+					   mem_type),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_resp_msg_v01,
+					   data_valid),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_resp_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_read_resp_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_athdiag_write_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_req_msg_v01,
+					   offset),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_req_msg_v01,
+					   mem_type),
+	},
+	{
+		.data_type      = QMI_DATA_LEN,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_req_msg_v01,
+					   data_len),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.is_array       = VAR_LEN_ARRAY,
+		.tlv_type       = 0x03,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_req_msg_v01,
+					   data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_athdiag_write_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_vbatt_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_vbatt_req_msg_v01,
+					   voltage_uv),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_vbatt_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_vbatt_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_mac_addr_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_mac_addr_req_msg_v01,
+					   mac_addr_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = QMI_WLFW_MAC_ADDR_SIZE_V01,
+		.elem_size      = sizeof(u8),
+		.is_array       = STATIC_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_mac_addr_req_msg_v01,
+					   mac_addr),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_mac_addr_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_mac_addr_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_host_cap_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   daemon_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   daemon_support),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   wake_msi_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   wake_msi),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_host_cap_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_host_cap_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_request_mem_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_request_mem_ind_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_respond_mem_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_respond_mem_req_msg_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_respond_mem_req_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_respond_mem_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_respond_mem_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+					   cause_for_rejuvenation_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+					   cause_for_rejuvenation),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+					   requesting_sub_system_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+					   requesting_sub_system),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+					   line_number_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_2_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u16),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x12,
+		.offset         = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+					   line_number),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+					   function_name_valid),
+	},
+	{
+		.data_type      = QMI_STRING,
+		.elem_len       = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1,
+		.elem_size      = sizeof(char),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x13,
+		.offset         = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+					   function_name),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct
+					   wlfw_rejuvenate_ack_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(
+				struct wlfw_dynamic_feature_mask_req_msg_v01,
+				mask_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(
+				struct wlfw_dynamic_feature_mask_req_msg_v01,
+				mask),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(
+				struct wlfw_dynamic_feature_mask_resp_msg_v01,
+				resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(
+				struct wlfw_dynamic_feature_mask_resp_msg_v01,
+				prev_mask_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(
+				struct wlfw_dynamic_feature_mask_resp_msg_v01,
+				prev_mask),
+	},
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(
+				struct wlfw_dynamic_feature_mask_resp_msg_v01,
+				curr_mask_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x11,
+		.offset         = offsetof(
+				struct wlfw_dynamic_feature_mask_resp_msg_v01,
+				curr_mask),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_m3_info_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_8_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u64),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_m3_info_req_msg_v01,
+					   addr),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_4_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u32),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_m3_info_req_msg_v01,
+					   size),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_m3_info_resp_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_STRUCT,
+		.elem_len       = 1,
+		.elem_size      = sizeof(struct qmi_response_type_v01),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x02,
+		.offset         = offsetof(struct wlfw_m3_info_resp_msg_v01,
+					   resp),
+		.ei_array      = get_qmi_response_type_v01_ei(),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
+
+struct elem_info wlfw_xo_cal_ind_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.is_array       = NO_ARRAY,
+		.tlv_type       = 0x01,
+		.offset         = offsetof(struct wlfw_xo_cal_ind_msg_v01,
+					   xo_cal_data),
+	},
+	{
+		.data_type      = QMI_EOTI,
+		.is_array       = NO_ARRAY,
+		.is_array       = QMI_COMMON_TLV_TYPE,
+	},
+};
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
new file mode 100644
index 0000000..9b56eb0
--- /dev/null
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
@@ -0,0 +1,657 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef WLAN_FIRMWARE_SERVICE_V01_H
+#define WLAN_FIRMWARE_SERVICE_V01_H
+
+#include <linux/qmi_encdec.h>
+#include <soc/qcom/msm_qmi_interface.h>
+
+#define WLFW_SERVICE_ID_V01 0x45
+#define WLFW_SERVICE_VERS_V01 0x01
+
+#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
+#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
+#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
+#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B
+#define QMI_WLFW_M3_INFO_REQ_V01 0x003C
+#define QMI_WLFW_CAP_REQ_V01 0x0024
+#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026
+#define QMI_WLFW_M3_INFO_RESP_V01 0x003C
+#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
+#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027
+#define QMI_WLFW_XO_CAL_IND_V01 0x003D
+#define QMI_WLFW_INI_RESP_V01 0x002F
+#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
+#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033
+#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028
+#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034
+#define QMI_WLFW_MSA_READY_IND_V01 0x002B
+#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031
+#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
+#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
+#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
+#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0038
+#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
+#define QMI_WLFW_REJUVENATE_IND_V01 0x0039
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
+#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031
+#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022
+#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036
+#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C
+#define QMI_WLFW_FW_READY_IND_V01 0x0021
+#define QMI_WLFW_MSA_READY_RESP_V01 0x002E
+#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029
+#define QMI_WLFW_INI_REQ_V01 0x002F
+#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025
+#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A
+#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D
+#define QMI_WLFW_MSA_READY_REQ_V01 0x002E
+#define QMI_WLFW_CAP_RESP_V01 0x0024
+#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A
+#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030
+#define QMI_WLFW_VBATT_REQ_V01 0x0032
+#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033
+#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036
+#define QMI_WLFW_VBATT_RESP_V01 0x0032
+#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D
+#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027
+#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030
+#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023
+#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
+
+#define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2
+#define QMI_WLFW_MAX_NUM_CAL_V01 5
+#define QMI_WLFW_MAX_DATA_SIZE_V01 6144
+#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
+#define QMI_WLFW_MAX_NUM_CE_V01 12
+#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
+#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144
+#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
+#define QMI_WLFW_MAX_STR_LEN_V01 16
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
+#define QMI_WLFW_MAC_ADDR_SIZE_V01 6
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01 36
+#define QMI_WLFW_MAX_NUM_SVC_V01 24
+
+enum wlfw_driver_mode_enum_v01 {
+	WLFW_DRIVER_MODE_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_MISSION_V01 = 0,
+	QMI_WLFW_FTM_V01 = 1,
+	QMI_WLFW_EPPING_V01 = 2,
+	QMI_WLFW_WALTEST_V01 = 3,
+	QMI_WLFW_OFF_V01 = 4,
+	QMI_WLFW_CCPM_V01 = 5,
+	QMI_WLFW_QVIT_V01 = 6,
+	QMI_WLFW_CALIBRATION_V01 = 7,
+	WLFW_DRIVER_MODE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_cal_temp_id_enum_v01 {
+	WLFW_CAL_TEMP_ID_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0,
+	QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1,
+	QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2,
+	QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3,
+	QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4,
+	WLFW_CAL_TEMP_ID_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_pipedir_enum_v01 {
+	WLFW_PIPEDIR_ENUM_MIN_VAL_V01 = INT_MIN,
+	QMI_WLFW_PIPEDIR_NONE_V01 = 0,
+	QMI_WLFW_PIPEDIR_IN_V01 = 1,
+	QMI_WLFW_PIPEDIR_OUT_V01 = 2,
+	QMI_WLFW_PIPEDIR_INOUT_V01 = 3,
+	WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00)
+#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01)
+#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02)
+#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((u32)0x04)
+#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((u32)0x08)
+#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((u32)0x10)
+
+#define QMI_WLFW_ALREADY_REGISTERED_V01 ((u64)0x01ULL)
+#define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL)
+#define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL)
+#define QMI_WLFW_FW_MEM_READY_V01 ((u64)0x08ULL)
+
+#define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL)
+
+struct wlfw_ce_tgt_pipe_cfg_s_v01 {
+	u32 pipe_num;
+	enum wlfw_pipedir_enum_v01 pipe_dir;
+	u32 nentries;
+	u32 nbytes_max;
+	u32 flags;
+};
+
+struct wlfw_ce_svc_pipe_cfg_s_v01 {
+	u32 service_id;
+	enum wlfw_pipedir_enum_v01 pipe_dir;
+	u32 pipe_num;
+};
+
+struct wlfw_shadow_reg_cfg_s_v01 {
+	u16 id;
+	u16 offset;
+};
+
+struct wlfw_shadow_reg_v2_cfg_s_v01 {
+	u32 addr;
+};
+
+struct wlfw_memory_region_info_s_v01 {
+	u64 region_addr;
+	u32 size;
+	u8 secure_flag;
+};
+
+struct wlfw_rf_chip_info_s_v01 {
+	u32 chip_id;
+	u32 chip_family;
+};
+
+struct wlfw_rf_board_info_s_v01 {
+	u32 board_id;
+};
+
+struct wlfw_soc_info_s_v01 {
+	u32 soc_id;
+};
+
+struct wlfw_fw_version_info_s_v01 {
+	u32 fw_version;
+	char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1];
+};
+
+struct wlfw_ind_register_req_msg_v01 {
+	u8 fw_ready_enable_valid;
+	u8 fw_ready_enable;
+	u8 initiate_cal_download_enable_valid;
+	u8 initiate_cal_download_enable;
+	u8 initiate_cal_update_enable_valid;
+	u8 initiate_cal_update_enable;
+	u8 msa_ready_enable_valid;
+	u8 msa_ready_enable;
+	u8 pin_connect_result_enable_valid;
+	u8 pin_connect_result_enable;
+	u8 client_id_valid;
+	u32 client_id;
+	u8 request_mem_enable_valid;
+	u8 request_mem_enable;
+	u8 fw_mem_ready_enable_valid;
+	u8 fw_mem_ready_enable;
+	u8 cold_boot_cal_done_enable_valid;
+	u8 cold_boot_cal_done_enable;
+	u8 rejuvenate_enable_valid;
+	u32 rejuvenate_enable;
+};
+
+#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 46
+extern struct elem_info wlfw_ind_register_req_msg_v01_ei[];
+
+struct wlfw_ind_register_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 fw_status_valid;
+	u64 fw_status;
+};
+
+#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_ind_register_resp_msg_v01_ei[];
+
+struct wlfw_fw_ready_ind_msg_v01 {
+	char placeholder;
+};
+
+#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_fw_ready_ind_msg_v01_ei[];
+
+struct wlfw_msa_ready_ind_msg_v01 {
+	char placeholder;
+};
+
+#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_msa_ready_ind_msg_v01_ei[];
+
+struct wlfw_pin_connect_result_ind_msg_v01 {
+	u8 pwr_pin_result_valid;
+	u32 pwr_pin_result;
+	u8 phy_io_pin_result_valid;
+	u32 phy_io_pin_result;
+	u8 rf_pin_result_valid;
+	u32 rf_pin_result;
+};
+
+#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21
+extern struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[];
+
+struct wlfw_wlan_mode_req_msg_v01 {
+	enum wlfw_driver_mode_enum_v01 mode;
+	u8 hw_debug_valid;
+	u8 hw_debug;
+};
+
+#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_wlan_mode_req_msg_v01_ei[];
+
+struct wlfw_wlan_mode_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_req_msg_v01 {
+	u8 host_version_valid;
+	char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+	u8 tgt_cfg_valid;
+	u32 tgt_cfg_len;
+	struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01];
+	u8 svc_cfg_valid;
+	u32 svc_cfg_len;
+	struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01];
+	u8 shadow_reg_valid;
+	u32 shadow_reg_len;
+	struct wlfw_shadow_reg_cfg_s_v01
+		shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01];
+	u8 shadow_reg_v2_valid;
+	u32 shadow_reg_v2_len;
+	struct wlfw_shadow_reg_v2_cfg_s_v01
+		shadow_reg_v2[QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01];
+};
+
+#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803
+extern struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[];
+
+struct wlfw_cap_req_msg_v01 {
+	char placeholder;
+};
+
+#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_cap_req_msg_v01_ei[];
+
+struct wlfw_cap_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 chip_info_valid;
+	struct wlfw_rf_chip_info_s_v01 chip_info;
+	u8 board_info_valid;
+	struct wlfw_rf_board_info_s_v01 board_info;
+	u8 soc_info_valid;
+	struct wlfw_soc_info_s_v01 soc_info;
+	u8 fw_version_info_valid;
+	struct wlfw_fw_version_info_s_v01 fw_version_info;
+	u8 fw_build_id_valid;
+	char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1];
+	u8 num_macs_valid;
+	u8 num_macs;
+};
+
+#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 207
+extern struct elem_info wlfw_cap_resp_msg_v01_ei[];
+
+struct wlfw_bdf_download_req_msg_v01 {
+	u8 valid;
+	u8 file_id_valid;
+	enum wlfw_cal_temp_id_enum_v01 file_id;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+	u8 bdf_type_valid;
+	u8 bdf_type;
+};
+
+#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6182
+extern struct elem_info wlfw_bdf_download_req_msg_v01_ei[];
+
+struct wlfw_bdf_download_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_bdf_download_resp_msg_v01_ei[];
+
+struct wlfw_cal_report_req_msg_v01 {
+	u32 meta_data_len;
+	enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01];
+	u8 xo_cal_data_valid;
+	u8 xo_cal_data;
+};
+
+#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 28
+extern struct elem_info wlfw_cal_report_req_msg_v01_ei[];
+
+struct wlfw_cal_report_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_cal_report_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_download_ind_msg_v01 {
+	enum wlfw_cal_temp_id_enum_v01 cal_id;
+};
+
+#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[];
+
+struct wlfw_cal_download_req_msg_v01 {
+	u8 valid;
+	u8 file_id_valid;
+	enum wlfw_cal_temp_id_enum_v01 file_id;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+};
+
+#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178
+extern struct elem_info wlfw_cal_download_req_msg_v01_ei[];
+
+struct wlfw_cal_download_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_cal_download_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_update_ind_msg_v01 {
+	enum wlfw_cal_temp_id_enum_v01 cal_id;
+	u32 total_size;
+};
+
+#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14
+extern struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[];
+
+struct wlfw_cal_update_req_msg_v01 {
+	enum wlfw_cal_temp_id_enum_v01 cal_id;
+	u32 seg_id;
+};
+
+#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14
+extern struct elem_info wlfw_cal_update_req_msg_v01_ei[];
+
+struct wlfw_cal_update_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 file_id_valid;
+	enum wlfw_cal_temp_id_enum_v01 file_id;
+	u8 total_size_valid;
+	u32 total_size;
+	u8 seg_id_valid;
+	u32 seg_id;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+	u8 end_valid;
+	u8 end;
+};
+
+#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181
+extern struct elem_info wlfw_cal_update_resp_msg_v01_ei[];
+
+struct wlfw_msa_info_req_msg_v01 {
+	u64 msa_addr;
+	u32 size;
+};
+
+#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_msa_info_req_msg_v01_ei[];
+
+struct wlfw_msa_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u32 mem_region_info_len;
+	struct wlfw_memory_region_info_s_v01
+		mem_region_info[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01];
+};
+
+#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37
+extern struct elem_info wlfw_msa_info_resp_msg_v01_ei[];
+
+struct wlfw_msa_ready_req_msg_v01 {
+	char placeholder;
+};
+
+#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_msa_ready_req_msg_v01_ei[];
+
+struct wlfw_msa_ready_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_msa_ready_resp_msg_v01_ei[];
+
+struct wlfw_ini_req_msg_v01 {
+	u8 enablefwlog_valid;
+	u8 enablefwlog;
+};
+
+#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct elem_info wlfw_ini_req_msg_v01_ei[];
+
+struct wlfw_ini_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_ini_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_read_req_msg_v01 {
+	u32 offset;
+	u32 mem_type;
+	u32 data_len;
+};
+
+#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21
+extern struct elem_info wlfw_athdiag_read_req_msg_v01_ei[];
+
+struct wlfw_athdiag_read_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 data_valid;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
+};
+
+#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156
+extern struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_write_req_msg_v01 {
+	u32 offset;
+	u32 mem_type;
+	u32 data_len;
+	u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
+};
+
+#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163
+extern struct elem_info wlfw_athdiag_write_req_msg_v01_ei[];
+
+struct wlfw_athdiag_write_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[];
+
+struct wlfw_vbatt_req_msg_v01 {
+	u64 voltage_uv;
+};
+
+#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_vbatt_req_msg_v01_ei[];
+
+struct wlfw_vbatt_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_vbatt_resp_msg_v01_ei[];
+
+struct wlfw_mac_addr_req_msg_v01 {
+	u8 mac_addr_valid;
+	u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01];
+};
+
+#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9
+extern struct elem_info wlfw_mac_addr_req_msg_v01_ei[];
+
+struct wlfw_mac_addr_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_mac_addr_resp_msg_v01_ei[];
+
+struct wlfw_host_cap_req_msg_v01 {
+	u8 daemon_support_valid;
+	u8 daemon_support;
+	u8 wake_msi_valid;
+	u32 wake_msi;
+};
+
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_host_cap_req_msg_v01_ei[];
+
+struct wlfw_host_cap_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_host_cap_resp_msg_v01_ei[];
+
+struct wlfw_request_mem_ind_msg_v01 {
+	u32 size;
+};
+
+#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_request_mem_ind_msg_v01_ei[];
+
+struct wlfw_respond_mem_req_msg_v01 {
+	u64 addr;
+	u32 size;
+};
+
+#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_respond_mem_req_msg_v01_ei[];
+
+struct wlfw_respond_mem_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_respond_mem_resp_msg_v01_ei[];
+
+struct wlfw_fw_mem_ready_ind_msg_v01 {
+	char placeholder;
+};
+
+#define WLFW_FW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[];
+
+struct wlfw_cold_boot_cal_done_ind_msg_v01 {
+	char placeholder;
+};
+
+#define WLFW_COLD_BOOT_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ind_msg_v01 {
+	u8 cause_for_rejuvenation_valid;
+	u8 cause_for_rejuvenation;
+	u8 requesting_sub_system_valid;
+	u8 requesting_sub_system;
+	u8 line_number_valid;
+	u16 line_number;
+	u8 function_name_valid;
+	char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
+};
+
+#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144
+extern struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_req_msg_v01 {
+	char placeholder;
+};
+
+#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_req_msg_v01 {
+	u8 mask_valid;
+	u64 mask;
+};
+
+#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+	u8 prev_mask_valid;
+	u64 prev_mask;
+	u8 curr_mask_valid;
+	u64 curr_mask;
+};
+
+#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29
+extern struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[];
+
+struct wlfw_m3_info_req_msg_v01 {
+	u64 addr;
+	u32 size;
+};
+
+#define WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_m3_info_req_msg_v01_ei[];
+
+struct wlfw_m3_info_resp_msg_v01 {
+	struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_m3_info_resp_msg_v01_ei[];
+
+struct wlfw_xo_cal_ind_msg_v01 {
+	u8 xo_cal_data;
+};
+
+#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4
+extern struct elem_info wlfw_xo_cal_ind_msg_v01_ei[];
+
+#endif
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index eb05f5ef..69c8cb0 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -36,6 +36,7 @@
 #include <linux/reset.h>
 #include <linux/msm-bus.h>
 #include <linux/msm-bus-board.h>
+#include <linux/seq_file.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
@@ -121,6 +122,15 @@
 #define PCIE20_PLR_IATU_LTAR	     0x918
 #define PCIE20_PLR_IATU_UTAR	     0x91c
 
+#define PCIE_IATU_BASE(n)	(n * 0x200)
+
+#define PCIE_IATU_CTRL1(n)	(PCIE_IATU_BASE(n) + 0x00)
+#define PCIE_IATU_CTRL2(n)	(PCIE_IATU_BASE(n) + 0x04)
+#define PCIE_IATU_LBAR(n)	(PCIE_IATU_BASE(n) + 0x08)
+#define PCIE_IATU_UBAR(n)	(PCIE_IATU_BASE(n) + 0x0c)
+#define PCIE_IATU_LAR(n)	(PCIE_IATU_BASE(n) + 0x10)
+#define PCIE_IATU_LTAR(n)	(PCIE_IATU_BASE(n) + 0x14)
+#define PCIE_IATU_UTAR(n)	(PCIE_IATU_BASE(n) + 0x18)
 
 #define PCIE20_PORT_LINK_CTRL_REG	0x710
 #define PCIE20_GEN3_RELATED_REG	0x890
@@ -177,7 +187,7 @@
 #define MAX_PROP_SIZE 32
 #define MAX_RC_NAME_LEN 15
 #define MSM_PCIE_MAX_VREG 4
-#define MSM_PCIE_MAX_CLK 12
+#define MSM_PCIE_MAX_CLK 13
 #define MSM_PCIE_MAX_PIPE_CLK 1
 #define MAX_RC_NUM 3
 #define MAX_DEVICE_NUM 20
@@ -185,7 +195,6 @@
 #define PCIE_TLP_RD_SIZE 0x5
 #define PCIE_MSI_NR_IRQS 256
 #define MSM_PCIE_MAX_MSI 32
-#define MAX_MSG_LEN 80
 #define PCIE_LOG_PAGES (50)
 #define PCIE_CONF_SPACE_DW			1024
 #define PCIE_CLEAR				0xDEADBEEF
@@ -217,6 +226,9 @@
 #endif
 #define PCIE_LOWER_ADDR(addr) ((u32)((addr) & 0xffffffff))
 
+#define PCIE_BUS_PRIV_DATA(bus) \
+	(struct msm_pcie_dev_t *)(bus->sysdata)
+
 /* Config Space Offsets */
 #define BDF_OFFSET(bus, devfn) \
 	((bus << 24) | (devfn << 16))
@@ -287,6 +299,7 @@
 	MSM_PCIE_RES_PHY,
 	MSM_PCIE_RES_DM_CORE,
 	MSM_PCIE_RES_ELBI,
+	MSM_PCIE_RES_IATU,
 	MSM_PCIE_RES_CONF,
 	MSM_PCIE_RES_IO,
 	MSM_PCIE_RES_BARS,
@@ -363,6 +376,76 @@
 	MSM_PCIE_NO_WAKE_ENUMERATION = BIT(1)
 };
 
+enum msm_pcie_debugfs_option {
+	MSM_PCIE_OUTPUT_PCIE_INFO,
+	MSM_PCIE_DISABLE_LINK,
+	MSM_PCIE_ENABLE_LINK,
+	MSM_PCIE_DISABLE_ENABLE_LINK,
+	MSM_PCIE_DUMP_SHADOW_REGISTER,
+	MSM_PCIE_DISABLE_L0S,
+	MSM_PCIE_ENABLE_L0S,
+	MSM_PCIE_DISABLE_L1,
+	MSM_PCIE_ENABLE_L1,
+	MSM_PCIE_DISABLE_L1SS,
+	MSM_PCIE_ENABLE_L1SS,
+	MSM_PCIE_ENUMERATION,
+	MSM_PCIE_READ_PCIE_REGISTER,
+	MSM_PCIE_WRITE_PCIE_REGISTER,
+	MSM_PCIE_DUMP_PCIE_REGISTER_SPACE,
+	MSM_PCIE_ALLOCATE_DDR_MAP_LBAR,
+	MSM_PCIE_FREE_DDR_UNMAP_LBAR,
+	MSM_PCIE_OUTPUT_DDR_LBAR_ADDRESS,
+	MSM_PCIE_CONFIGURE_LOOPBACK,
+	MSM_PCIE_SETUP_LOOPBACK_IATU,
+	MSM_PCIE_READ_DDR,
+	MSM_PCIE_READ_LBAR,
+	MSM_PCIE_WRITE_DDR,
+	MSM_PCIE_WRITE_LBAR,
+	MSM_PCIE_DISABLE_AER,
+	MSM_PCIE_ENABLE_AER,
+	MSM_PCIE_GPIO_STATUS,
+	MSM_PCIE_ASSERT_PERST,
+	MSM_PCIE_DEASSERT_PERST,
+	MSM_PCIE_KEEP_RESOURCES_ON,
+	MSM_PCIE_FORCE_GEN1,
+	MSM_PCIE_MAX_DEBUGFS_OPTION
+};
+
+static const char * const
+	msm_pcie_debugfs_option_desc[MSM_PCIE_MAX_DEBUGFS_OPTION] = {
+	"OUTPUT PCIE INFO",
+	"DISABLE LINK",
+	"ENABLE LINK",
+	"DISABLE AND ENABLE LINK",
+	"DUMP PCIE SHADOW REGISTER",
+	"DISABLE L0S",
+	"ENABLE L0S",
+	"DISABLE L1",
+	"ENABLE L1",
+	"DISABLE L1SS",
+	"ENABLE L1SS",
+	"ENUMERATE",
+	"READ A PCIE REGISTER",
+	"WRITE TO PCIE REGISTER",
+	"DUMP PCIE REGISTER SPACE",
+	"ALLOCATE DDR AND MAP LBAR",
+	"FREE DDR AND UNMAP LBAR",
+	"OUTPUT DDR AND LBAR VIR ADDRESS",
+	"CONFIGURE PCIE LOOPBACK",
+	"SETUP LOOPBACK IATU",
+	"READ DDR",
+	"READ LBAR",
+	"WRITE DDR",
+	"WRITE LBAR",
+	"SET AER ENABLE FLAG",
+	"CLEAR AER ENABLE FLAG",
+	"OUTPUT PERST AND WAKE GPIO STATUS",
+	"ASSERT PERST",
+	"DE-ASSERT PERST",
+	"SET KEEP_RESOURCES_ON FLAG",
+	"FORCE GEN 1 SPEED FOR LINK TRAINING"
+};
+
 /* gpio info structure */
 struct msm_pcie_gpio_info_t {
 	char	*name;
@@ -452,6 +535,7 @@
 	void __iomem		     *parf;
 	void __iomem		     *phy;
 	void __iomem		     *elbi;
+	void __iomem		     *iatu;
 	void __iomem		     *dm_core;
 	void __iomem		     *conf;
 	void __iomem		     *bars;
@@ -520,10 +604,8 @@
 	bool				 enumerated;
 	struct work_struct	     handle_wake_work;
 	struct mutex		     recovery_lock;
-	spinlock_t                   linkdown_lock;
 	spinlock_t                   wakeup_lock;
-	spinlock_t			global_irq_lock;
-	spinlock_t			aer_lock;
+	spinlock_t			irq_lock;
 	ulong				linkdown_counter;
 	ulong				link_turned_on_counter;
 	ulong				link_turned_off_counter;
@@ -589,13 +671,32 @@
 module_param_named(keep_resources_on, msm_pcie_keep_resources_on,
 			    int, 0644);
 
+/*
+ * For each bit set, force the corresponding root complex
+ * to do link training at gen1 speed.
+ */
+static int msm_pcie_force_gen1;
+module_param_named(force_gen1, msm_pcie_force_gen1,
+			    int, 0644);
+
+
+/*
+ * For each bit set in BIT[3:0] determines which corresponding
+ * root complex will use the value in BIT[31:4] to override the
+ * default (LINK_UP_CHECK_MAX_COUNT) max check count for link training.
+ * Each iteration is LINK_UP_TIMEOUT_US_MIN long.
+ */
+static int msm_pcie_link_check_max_count;
+module_param_named(link_check_max_count, msm_pcie_link_check_max_count,
+			    int, 0644);
+
 /* debugfs values */
-static u32 rc_sel;
+static u32 rc_sel = BIT(0);
 static u32 base_sel;
 static u32 wr_offset;
 static u32 wr_mask;
 static u32 wr_value;
-static ulong corr_counter_limit = 5;
+static u32 corr_counter_limit = 5;
 
 /* Table to track info of PCIe devices */
 static struct msm_pcie_device_info
@@ -677,6 +778,7 @@
 	{NULL, "pcie_0_ldo", 0, false, true},
 	{NULL, "pcie_0_smmu_clk", 0, false, false},
 	{NULL, "pcie_0_slv_q2a_axi_clk", 0, false, false},
+	{NULL, "pcie_0_sleep_clk", 0, false, false},
 	{NULL, "pcie_phy_refgen_clk", 0, false, false},
 	{NULL, "pcie_tbu_clk", 0, false, false},
 	{NULL, "pcie_phy_cfg_ahb_clk", 0, false, false},
@@ -691,6 +793,7 @@
 	{NULL, "pcie_1_ldo", 0, false, true},
 	{NULL, "pcie_1_smmu_clk", 0, false, false},
 	{NULL, "pcie_1_slv_q2a_axi_clk", 0, false, false},
+	{NULL, "pcie_1_sleep_clk", 0, false, false},
 	{NULL, "pcie_phy_refgen_clk", 0, false, false},
 	{NULL, "pcie_tbu_clk", 0, false, false},
 	{NULL, "pcie_phy_cfg_ahb_clk", 0, false, false},
@@ -705,6 +808,7 @@
 	{NULL, "pcie_2_ldo", 0, false, true},
 	{NULL, "pcie_2_smmu_clk", 0, false, false},
 	{NULL, "pcie_2_slv_q2a_axi_clk", 0, false, false},
+	{NULL, "pcie_2_sleep_clk", 0, false, false},
 	{NULL, "pcie_phy_refgen_clk", 0, false, false},
 	{NULL, "pcie_tbu_clk", 0, false, false},
 	{NULL, "pcie_phy_cfg_ahb_clk", 0, false, false},
@@ -732,6 +836,7 @@
 	{"phy",     NULL, NULL},
 	{"dm_core",	NULL, NULL},
 	{"elbi",	NULL, NULL},
+	{"iatu",	NULL, NULL},
 	{"conf",	NULL, NULL},
 	{"io",		NULL, NULL},
 	{"bars",	NULL, NULL},
@@ -768,36 +873,21 @@
 };
 
 static int msm_pcie_config_device(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l0s_disable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l0s_enable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l1_disable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l1_enable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l1ss_disable(struct pci_dev *dev, void *pdev);
+static int msm_pcie_config_l1ss_enable(struct pci_dev *dev, void *pdev);
 static void msm_pcie_config_link_pm_rc(struct msm_pcie_dev_t *dev,
 				struct pci_dev *pdev, bool enable);
 
 #ifdef CONFIG_ARM
-#define PCIE_BUS_PRIV_DATA(bus) \
-	(((struct pci_sys_data *)bus->sysdata)->private_data)
-
-static struct pci_sys_data msm_pcie_sys_data[MAX_RC_NUM];
-
-static inline void *msm_pcie_setup_sys_data(struct msm_pcie_dev_t *dev)
-{
-	msm_pcie_sys_data[dev->rc_idx].domain = dev->rc_idx;
-	msm_pcie_sys_data[dev->rc_idx].private_data = dev;
-
-	return &msm_pcie_sys_data[dev->rc_idx];
-}
-
 static inline void msm_pcie_fixup_irqs(struct msm_pcie_dev_t *dev)
 {
 	pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
 }
 #else
-#define PCIE_BUS_PRIV_DATA(bus) \
-	(struct msm_pcie_dev_t *)(bus->sysdata)
-
-static inline void *msm_pcie_setup_sys_data(struct msm_pcie_dev_t *dev)
-{
-	return dev;
-}
-
 static inline void msm_pcie_fixup_irqs(struct msm_pcie_dev_t *dev)
 {
 }
@@ -1236,56 +1326,24 @@
 static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
 					u32 testcase)
 {
-	phys_addr_t dbi_base_addr =
-		dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
+	u32 dbi_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
 	phys_addr_t loopback_lbar_phy =
-		dbi_base_addr + LOOPBACK_BASE_ADDR_OFFSET;
+		dev->res[MSM_PCIE_RES_DM_CORE].resource->start +
+		LOOPBACK_BASE_ADDR_OFFSET;
 	static uint32_t loopback_val = 0x1;
-	static u64 loopback_ddr_phy;
+	static dma_addr_t loopback_ddr_phy;
 	static uint32_t *loopback_ddr_vir;
 	static void __iomem *loopback_lbar_vir;
 	int ret, i;
 	u32 base_sel_size = 0;
-	u32 val = 0;
-	u32 current_offset = 0;
-	u32 ep_l1sub_ctrl1_offset = 0;
-	u32 ep_l1sub_cap_reg1_offset = 0;
-	u32 ep_link_ctrlstts_offset = 0;
-	u32 ep_dev_ctrl2stts2_offset = 0;
-
-	if (testcase >= 5 && testcase <= 10) {
-		current_offset =
-			readl_relaxed(dev->conf + PCIE_CAP_PTR_OFFSET) & 0xff;
-
-		while (current_offset) {
-			val = readl_relaxed(dev->conf + current_offset);
-			if ((val & 0xff) == PCIE20_CAP_ID) {
-				ep_link_ctrlstts_offset = current_offset +
-								0x10;
-				ep_dev_ctrl2stts2_offset = current_offset +
-								0x28;
-				break;
-			}
-			current_offset = (val >> 8) & 0xff;
-		}
-
-		if (!ep_link_ctrlstts_offset)
-			PCIE_DBG(dev,
-				"RC%d endpoint does not support PCIe capability registers\n",
-				dev->rc_idx);
-		else
-			PCIE_DBG(dev,
-				"RC%d: ep_link_ctrlstts_offset: 0x%x\n",
-				dev->rc_idx, ep_link_ctrlstts_offset);
-	}
 
 	switch (testcase) {
-	case 0: /* output status */
+	case MSM_PCIE_OUTPUT_PCIE_INFO:
 		PCIE_DBG_FS(dev, "\n\nPCIe: Status for RC%d:\n",
 			dev->rc_idx);
 		msm_pcie_show_status(dev);
 		break;
-	case 1: /* disable link */
+	case MSM_PCIE_DISABLE_LINK:
 		PCIE_DBG_FS(dev,
 			"\n\nPCIe: RC%d: disable link\n\n", dev->rc_idx);
 		ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, 0,
@@ -1298,7 +1356,7 @@
 			PCIE_DBG_FS(dev, "PCIe:%s:disabled link\n",
 				__func__);
 		break;
-	case 2: /* enable link and recover config space for RC and EP */
+	case MSM_PCIE_ENABLE_LINK:
 		PCIE_DBG_FS(dev,
 			"\n\nPCIe: RC%d: enable link and recover config space\n\n",
 			dev->rc_idx);
@@ -1313,10 +1371,7 @@
 			msm_pcie_recover_config(dev->dev);
 		}
 		break;
-	case 3: /*
-		 * disable and enable link, recover config space for
-		 * RC and EP
-		 */
+	case MSM_PCIE_DISABLE_ENABLE_LINK:
 		PCIE_DBG_FS(dev,
 			"\n\nPCIe: RC%d: disable and enable link then recover config space\n\n",
 			dev->rc_idx);
@@ -1339,7 +1394,7 @@
 			msm_pcie_recover_config(dev->dev);
 		}
 		break;
-	case 4: /* dump shadow registers for RC and EP */
+	case MSM_PCIE_DUMP_SHADOW_REGISTER:
 		PCIE_DBG_FS(dev,
 			"\n\nPCIe: RC%d: dumping RC shadow registers\n",
 			dev->rc_idx);
@@ -1350,236 +1405,97 @@
 			dev->rc_idx);
 		msm_pcie_shadow_dump(dev, false);
 		break;
-	case 5: /* disable L0s */
+	case MSM_PCIE_DISABLE_L0S:
 		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L0s\n\n",
 			dev->rc_idx);
-		msm_pcie_write_mask(dev->dm_core +
-				PCIE20_CAP_LINKCTRLSTATUS,
-				BIT(0), 0);
-		msm_pcie_write_mask(dev->conf +
-				ep_link_ctrlstts_offset,
-				BIT(0), 0);
-		if (dev->shadow_en) {
-			dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] =
-					readl_relaxed(dev->dm_core +
-					PCIE20_CAP_LINKCTRLSTATUS);
-			dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] =
-					readl_relaxed(dev->conf +
-					ep_link_ctrlstts_offset);
+		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+			struct pci_bus *bus, *c_bus;
+			struct list_head *children = &dev->dev->bus->children;
+
+			msm_pcie_config_l0s_disable(dev->dev, dev);
+
+			list_for_each_entry_safe(bus, c_bus, children, node)
+				pci_walk_bus(bus,
+					&msm_pcie_config_l0s_disable, dev);
 		}
-		PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n",
-			readl_relaxed(dev->dm_core +
-			PCIE20_CAP_LINKCTRLSTATUS));
-		PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n",
-			readl_relaxed(dev->conf +
-			ep_link_ctrlstts_offset));
+		dev->l0s_supported = false;
 		break;
-	case 6: /* enable L0s */
+	case MSM_PCIE_ENABLE_L0S:
 		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L0s\n\n",
 			dev->rc_idx);
-		msm_pcie_write_mask(dev->dm_core +
-				PCIE20_CAP_LINKCTRLSTATUS,
-				0, BIT(0));
-		msm_pcie_write_mask(dev->conf +
-				ep_link_ctrlstts_offset,
-				0, BIT(0));
-		if (dev->shadow_en) {
-			dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] =
-					readl_relaxed(dev->dm_core +
-					PCIE20_CAP_LINKCTRLSTATUS);
-			dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] =
-					readl_relaxed(dev->conf +
-					ep_link_ctrlstts_offset);
+		dev->l0s_supported = true;
+		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+			struct pci_bus *bus, *c_bus;
+			struct list_head *children = &dev->dev->bus->children;
+
+			list_for_each_entry_safe(bus, c_bus, children, node)
+				pci_walk_bus(bus,
+					&msm_pcie_config_l0s_enable, dev);
+
+			msm_pcie_config_l0s_enable(dev->dev, dev);
 		}
-		PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n",
-			readl_relaxed(dev->dm_core +
-			PCIE20_CAP_LINKCTRLSTATUS));
-		PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n",
-			readl_relaxed(dev->conf +
-			ep_link_ctrlstts_offset));
 		break;
-	case 7: /* disable L1 */
+	case MSM_PCIE_DISABLE_L1:
 		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1\n\n",
 			dev->rc_idx);
-		msm_pcie_write_mask(dev->dm_core +
-				PCIE20_CAP_LINKCTRLSTATUS,
-				BIT(1), 0);
-		msm_pcie_write_mask(dev->conf +
-				ep_link_ctrlstts_offset,
-				BIT(1), 0);
-		if (dev->shadow_en) {
-			dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] =
-					readl_relaxed(dev->dm_core +
-					PCIE20_CAP_LINKCTRLSTATUS);
-			dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] =
-					readl_relaxed(dev->conf +
-					ep_link_ctrlstts_offset);
+		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+			struct pci_bus *bus, *c_bus;
+			struct list_head *children = &dev->dev->bus->children;
+
+			msm_pcie_config_l1_disable(dev->dev, dev);
+
+			list_for_each_entry_safe(bus, c_bus, children, node)
+				pci_walk_bus(bus,
+					&msm_pcie_config_l1_disable, dev);
 		}
-		PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n",
-			readl_relaxed(dev->dm_core +
-			PCIE20_CAP_LINKCTRLSTATUS));
-		PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n",
-			readl_relaxed(dev->conf +
-			ep_link_ctrlstts_offset));
+		dev->l1_supported = false;
 		break;
-	case 8: /* enable L1 */
+	case MSM_PCIE_ENABLE_L1:
 		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1\n\n",
 			dev->rc_idx);
-		msm_pcie_write_mask(dev->dm_core +
-				PCIE20_CAP_LINKCTRLSTATUS,
-				0, BIT(1));
-		msm_pcie_write_mask(dev->conf +
-				ep_link_ctrlstts_offset,
-				0, BIT(1));
-		if (dev->shadow_en) {
-			dev->rc_shadow[PCIE20_CAP_LINKCTRLSTATUS / 4] =
-					readl_relaxed(dev->dm_core +
-					PCIE20_CAP_LINKCTRLSTATUS);
-			dev->ep_shadow[0][ep_link_ctrlstts_offset / 4] =
-					readl_relaxed(dev->conf +
-					ep_link_ctrlstts_offset);
+		dev->l1_supported = true;
+		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+			struct pci_bus *bus, *c_bus;
+			struct list_head *children = &dev->dev->bus->children;
+
+			list_for_each_entry_safe(bus, c_bus, children, node)
+				pci_walk_bus(bus,
+					&msm_pcie_config_l1_enable, dev);
+
+			msm_pcie_config_l1_enable(dev->dev, dev);
 		}
-		PCIE_DBG_FS(dev, "PCIe: RC's CAP_LINKCTRLSTATUS:0x%x\n",
-			readl_relaxed(dev->dm_core +
-			PCIE20_CAP_LINKCTRLSTATUS));
-		PCIE_DBG_FS(dev, "PCIe: EP's CAP_LINKCTRLSTATUS:0x%x\n",
-			readl_relaxed(dev->conf +
-			ep_link_ctrlstts_offset));
 		break;
-	case 9: /* disable L1ss */
+	case MSM_PCIE_DISABLE_L1SS:
 		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1ss\n\n",
 			dev->rc_idx);
-		current_offset = PCIE_EXT_CAP_OFFSET;
-		while (current_offset) {
-			val = readl_relaxed(dev->conf + current_offset);
-			if ((val & 0xffff) == L1SUB_CAP_ID) {
-				ep_l1sub_ctrl1_offset =
-						current_offset + 0x8;
-				break;
-			}
-			current_offset = val >> 20;
-		}
-		if (!ep_l1sub_ctrl1_offset) {
-			PCIE_DBG_FS(dev,
-				"PCIe: RC%d endpoint does not support l1ss registers\n",
-				dev->rc_idx);
-			break;
-		}
+		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+			struct pci_bus *bus, *c_bus;
+			struct list_head *children = &dev->dev->bus->children;
 
-		PCIE_DBG_FS(dev, "PCIe: RC%d: ep_l1sub_ctrl1_offset: 0x%x\n",
-				dev->rc_idx, ep_l1sub_ctrl1_offset);
+			msm_pcie_config_l1ss_disable(dev->dev, dev);
 
-		msm_pcie_write_reg_field(dev->dm_core,
-					PCIE20_L1SUB_CONTROL1,
-					0xf, 0);
-		msm_pcie_write_mask(dev->dm_core +
-					PCIE20_DEVICE_CONTROL2_STATUS2,
-					BIT(10), 0);
-		msm_pcie_write_reg_field(dev->conf,
-					ep_l1sub_ctrl1_offset,
-					0xf, 0);
-		msm_pcie_write_mask(dev->conf +
-					ep_dev_ctrl2stts2_offset,
-					BIT(10), 0);
-		if (dev->shadow_en) {
-			dev->rc_shadow[PCIE20_L1SUB_CONTROL1 / 4] =
-				readl_relaxed(dev->dm_core +
-				PCIE20_L1SUB_CONTROL1);
-			dev->rc_shadow[PCIE20_DEVICE_CONTROL2_STATUS2 / 4] =
-				readl_relaxed(dev->dm_core +
-				PCIE20_DEVICE_CONTROL2_STATUS2);
-			dev->ep_shadow[0][ep_l1sub_ctrl1_offset / 4] =
-				readl_relaxed(dev->conf +
-				ep_l1sub_ctrl1_offset);
-			dev->ep_shadow[0][ep_dev_ctrl2stts2_offset / 4] =
-				readl_relaxed(dev->conf +
-				ep_dev_ctrl2stts2_offset);
+			list_for_each_entry_safe(bus, c_bus, children, node)
+				pci_walk_bus(bus,
+					&msm_pcie_config_l1ss_disable, dev);
 		}
-		PCIE_DBG_FS(dev, "PCIe: RC's L1SUB_CONTROL1:0x%x\n",
-			readl_relaxed(dev->dm_core +
-			PCIE20_L1SUB_CONTROL1));
-		PCIE_DBG_FS(dev, "PCIe: RC's DEVICE_CONTROL2_STATUS2:0x%x\n",
-			readl_relaxed(dev->dm_core +
-			PCIE20_DEVICE_CONTROL2_STATUS2));
-		PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CONTROL1:0x%x\n",
-			readl_relaxed(dev->conf +
-			ep_l1sub_ctrl1_offset));
-		PCIE_DBG_FS(dev, "PCIe: EP's DEVICE_CONTROL2_STATUS2:0x%x\n",
-			readl_relaxed(dev->conf +
-			ep_dev_ctrl2stts2_offset));
+		dev->l1ss_supported = false;
 		break;
-	case 10: /* enable L1ss */
+	case MSM_PCIE_ENABLE_L1SS:
 		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1ss\n\n",
 			dev->rc_idx);
-		current_offset = PCIE_EXT_CAP_OFFSET;
-		while (current_offset) {
-			val = readl_relaxed(dev->conf + current_offset);
-			if ((val & 0xffff) == L1SUB_CAP_ID) {
-				ep_l1sub_cap_reg1_offset =
-						current_offset + 0x4;
-				ep_l1sub_ctrl1_offset =
-						current_offset + 0x8;
-				break;
-			}
-			current_offset = val >> 20;
+		dev->l1ss_supported = true;
+		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
+			struct pci_bus *bus, *c_bus;
+			struct list_head *children = &dev->dev->bus->children;
+
+			list_for_each_entry_safe(bus, c_bus, children, node)
+				pci_walk_bus(bus,
+					&msm_pcie_config_l1ss_enable, dev);
+
+			msm_pcie_config_l1ss_enable(dev->dev, dev);
 		}
-		if (!ep_l1sub_ctrl1_offset) {
-			PCIE_DBG_FS(dev,
-				"PCIe: RC%d endpoint does not support l1ss registers\n",
-				dev->rc_idx);
-			break;
-		}
-
-		val = readl_relaxed(dev->conf +
-				ep_l1sub_cap_reg1_offset);
-
-		PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CAPABILITY_REG_1: 0x%x\n",
-			val);
-		PCIE_DBG_FS(dev, "PCIe: RC%d: ep_l1sub_ctrl1_offset: 0x%x\n",
-			dev->rc_idx, ep_l1sub_ctrl1_offset);
-
-		val &= 0xf;
-
-		msm_pcie_write_reg_field(dev->dm_core,
-					PCIE20_L1SUB_CONTROL1,
-					0xf, val);
-		msm_pcie_write_mask(dev->dm_core +
-					PCIE20_DEVICE_CONTROL2_STATUS2,
-					0, BIT(10));
-		msm_pcie_write_reg_field(dev->conf,
-					ep_l1sub_ctrl1_offset,
-					0xf, val);
-		msm_pcie_write_mask(dev->conf +
-					ep_dev_ctrl2stts2_offset,
-					0, BIT(10));
-		if (dev->shadow_en) {
-			dev->rc_shadow[PCIE20_L1SUB_CONTROL1 / 4] =
-				readl_relaxed(dev->dm_core +
-					PCIE20_L1SUB_CONTROL1);
-			dev->rc_shadow[PCIE20_DEVICE_CONTROL2_STATUS2 / 4] =
-				readl_relaxed(dev->dm_core +
-				PCIE20_DEVICE_CONTROL2_STATUS2);
-			dev->ep_shadow[0][ep_l1sub_ctrl1_offset / 4] =
-				readl_relaxed(dev->conf +
-				ep_l1sub_ctrl1_offset);
-			dev->ep_shadow[0][ep_dev_ctrl2stts2_offset / 4] =
-				readl_relaxed(dev->conf +
-				ep_dev_ctrl2stts2_offset);
-		}
-		PCIE_DBG_FS(dev, "PCIe: RC's L1SUB_CONTROL1:0x%x\n",
-			readl_relaxed(dev->dm_core +
-			PCIE20_L1SUB_CONTROL1));
-		PCIE_DBG_FS(dev, "PCIe: RC's DEVICE_CONTROL2_STATUS2:0x%x\n",
-			readl_relaxed(dev->dm_core +
-			PCIE20_DEVICE_CONTROL2_STATUS2));
-		PCIE_DBG_FS(dev, "PCIe: EP's L1SUB_CONTROL1:0x%x\n",
-			readl_relaxed(dev->conf +
-			ep_l1sub_ctrl1_offset));
-		PCIE_DBG_FS(dev, "PCIe: EP's DEVICE_CONTROL2_STATUS2:0x%x\n",
-			readl_relaxed(dev->conf +
-			ep_dev_ctrl2stts2_offset));
 		break;
-	case 11: /* enumerate PCIe  */
+	case MSM_PCIE_ENUMERATION:
 		PCIE_DBG_FS(dev, "\n\nPCIe: attempting to enumerate RC%d\n\n",
 			dev->rc_idx);
 		if (dev->enumerated)
@@ -1596,7 +1512,41 @@
 					dev->rc_idx);
 		}
 		break;
-	case 12: /* write a value to a register */
+	case MSM_PCIE_READ_PCIE_REGISTER:
+		PCIE_DBG_FS(dev,
+			"\n\nPCIe: RC%d: read a PCIe register\n\n",
+			dev->rc_idx);
+		if (!base_sel) {
+			PCIE_DBG_FS(dev, "Invalid base_sel: 0x%x\n", base_sel);
+			break;
+		}
+
+		PCIE_DBG_FS(dev, "base: %s: 0x%pK\nwr_offset: 0x%x\n",
+			dev->res[base_sel - 1].name,
+			dev->res[base_sel - 1].base,
+			wr_offset);
+
+		base_sel_size = resource_size(dev->res[base_sel - 1].resource);
+
+		if (wr_offset >  base_sel_size - 4 ||
+			msm_pcie_check_align(dev, wr_offset)) {
+			PCIE_DBG_FS(dev,
+				"PCIe: RC%d: Invalid wr_offset: 0x%x. wr_offset should be no more than 0x%x\n",
+				dev->rc_idx, wr_offset, base_sel_size - 4);
+		} else {
+			phys_addr_t wr_register =
+				dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
+
+			wr_register += wr_offset;
+			PCIE_DBG_FS(dev,
+				"PCIe: RC%d: register: 0x%pa value: 0x%x\n",
+				dev->rc_idx, &wr_register,
+				readl_relaxed(dev->res[base_sel - 1].base +
+					wr_offset));
+		}
+
+		break;
+	case MSM_PCIE_WRITE_PCIE_REGISTER:
 		PCIE_DBG_FS(dev,
 			"\n\nPCIe: RC%d: writing a value to a register\n\n",
 			dev->rc_idx);
@@ -1607,7 +1557,7 @@
 		}
 
 		PCIE_DBG_FS(dev,
-			"base: %s: 0x%p\nwr_offset: 0x%x\nwr_mask: 0x%x\nwr_value: 0x%x\n",
+			"base: %s: 0x%pK\nwr_offset: 0x%x\nwr_mask: 0x%x\nwr_value: 0x%x\n",
 			dev->res[base_sel - 1].name,
 			dev->res[base_sel - 1].base,
 			wr_offset, wr_mask, wr_value);
@@ -1624,7 +1574,7 @@
 				wr_offset, wr_mask, wr_value);
 
 		break;
-	case 13: /* dump all registers of base_sel */
+	case MSM_PCIE_DUMP_PCIE_REGISTER_SPACE:
 		if (!base_sel) {
 			PCIE_DBG_FS(dev, "Invalid base_sel: 0x%x\n", base_sel);
 			break;
@@ -1657,7 +1607,7 @@
 			readl_relaxed(dev->res[base_sel - 1].base + (i + 28)));
 		}
 		break;
-	case 14:
+	case MSM_PCIE_ALLOCATE_DDR_MAP_LBAR:
 		PCIE_DBG_FS(dev,
 			"PCIe: RC%d: Allocate 4K DDR memory and map LBAR.\n",
 			dev->rc_idx);
@@ -1673,25 +1623,25 @@
 				"PCIe: RC%d: VIR DDR memory address: 0x%pK\n",
 				dev->rc_idx, loopback_ddr_vir);
 			PCIE_DBG_FS(dev,
-				"PCIe: RC%d: PHY DDR memory address: 0x%llx\n",
-				dev->rc_idx, loopback_ddr_phy);
+				"PCIe: RC%d: PHY DDR memory address: %pad\n",
+				dev->rc_idx, &loopback_ddr_phy);
 		}
 
-		PCIE_DBG_FS(dev, "PCIe: RC%d: map LBAR: 0x%llx\n",
-			dev->rc_idx, loopback_lbar_phy);
+		PCIE_DBG_FS(dev, "PCIe: RC%d: map LBAR: %pa\n",
+			dev->rc_idx, &loopback_lbar_phy);
 		loopback_lbar_vir = devm_ioremap(&dev->pdev->dev,
 			loopback_lbar_phy, SZ_4K);
 		if (!loopback_lbar_vir) {
-			PCIE_DBG_FS(dev, "PCIe: RC%d: failed to map 0x%llx\n",
-				dev->rc_idx, loopback_lbar_phy);
+			PCIE_DBG_FS(dev, "PCIe: RC%d: failed to map %pa\n",
+				dev->rc_idx, &loopback_lbar_phy);
 		} else {
 			PCIE_DBG_FS(dev,
-				"PCIe: RC%d: successfully mapped 0x%llx to 0x%pK\n",
-				dev->rc_idx, loopback_lbar_phy,
+				"PCIe: RC%d: successfully mapped %pa to 0x%pK\n",
+				dev->rc_idx, &loopback_lbar_phy,
 				loopback_lbar_vir);
 		}
 		break;
-	case 15:
+	case MSM_PCIE_FREE_DDR_UNMAP_LBAR:
 		PCIE_DBG_FS(dev,
 			"PCIe: RC%d: Release 4K DDR memory and unmap LBAR.\n",
 			dev->rc_idx);
@@ -1708,7 +1658,7 @@
 			loopback_lbar_vir = NULL;
 		}
 		break;
-	case 16:
+	case MSM_PCIE_OUTPUT_DDR_LBAR_ADDRESS:
 		PCIE_DBG_FS(dev,
 			"PCIe: RC%d: Print DDR and LBAR addresses.\n",
 			dev->rc_idx);
@@ -1721,19 +1671,19 @@
 		}
 
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PHY DDR address: 0x%llx\n",
-			dev->rc_idx, loopback_ddr_phy);
+			"PCIe: RC%d: PHY DDR address: %pad\n",
+			dev->rc_idx, &loopback_ddr_phy);
 		PCIE_DBG_FS(dev,
 			"PCIe: RC%d: VIR DDR address: 0x%pK\n",
 			dev->rc_idx, loopback_ddr_vir);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PHY LBAR address: 0x%llx\n",
-			dev->rc_idx, loopback_lbar_phy);
+			"PCIe: RC%d: PHY LBAR address: %pa\n",
+			dev->rc_idx, &loopback_lbar_phy);
 		PCIE_DBG_FS(dev,
 			"PCIe: RC%d: VIR LBAR address: 0x%pK\n",
 			dev->rc_idx, loopback_lbar_vir);
 		break;
-	case 17:
+	case MSM_PCIE_CONFIGURE_LOOPBACK:
 		PCIE_DBG_FS(dev,
 			"PCIe: RC%d: Configure Loopback.\n",
 			dev->rc_idx);
@@ -1741,7 +1691,7 @@
 		writel_relaxed(0x10000,
 			dev->dm_core + PCIE20_GEN3_RELATED_REG);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: 0x%llx: 0x%x\n",
+			"PCIe: RC%d: 0x%x: 0x%x\n",
 			dev->rc_idx,
 			dbi_base_addr + PCIE20_GEN3_RELATED_REG,
 			readl_relaxed(dev->dm_core +
@@ -1750,7 +1700,7 @@
 		writel_relaxed(0x80000001,
 			dev->dm_core + PCIE20_PIPE_LOOPBACK_CONTROL);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: 0x%llx: 0x%x\n",
+			"PCIe: RC%d: 0x%x: 0x%x\n",
 			dev->rc_idx,
 			dbi_base_addr + PCIE20_PIPE_LOOPBACK_CONTROL,
 			readl_relaxed(dev->dm_core +
@@ -1759,13 +1709,13 @@
 		writel_relaxed(0x00010124,
 			dev->dm_core + PCIE20_PORT_LINK_CTRL_REG);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: 0x%llx: 0x%x\n",
+			"PCIe: RC%d: 0x%x: 0x%x\n",
 			dev->rc_idx,
 			dbi_base_addr + PCIE20_PORT_LINK_CTRL_REG,
 			readl_relaxed(dev->dm_core +
 				PCIE20_PORT_LINK_CTRL_REG));
 		break;
-	case 18:
+	case MSM_PCIE_SETUP_LOOPBACK_IATU:
 		PCIE_DBG_FS(dev, "PCIe: RC%d: Setup iATU.\n", dev->rc_idx);
 
 		if (!loopback_ddr_vir) {
@@ -1777,57 +1727,57 @@
 
 		writel_relaxed(0x0, dev->dm_core + PCIE20_PLR_IATU_VIEWPORT);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PCIE20_PLR_IATU_VIEWPORT:\t0x%llx: 0x%x\n",
+			"PCIe: RC%d: PCIE20_PLR_IATU_VIEWPORT:\t0x%x: 0x%x\n",
 			dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_VIEWPORT,
 			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_VIEWPORT));
 
 		writel_relaxed(0x0, dev->dm_core + PCIE20_PLR_IATU_CTRL1);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PCIE20_PLR_IATU_CTRL1:\t0x%llx: 0x%x\n",
+			"PCIe: RC%d: PCIE20_PLR_IATU_CTRL1:\t0x%x: 0x%x\n",
 			dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_CTRL1,
 			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL1));
 
 		writel_relaxed(loopback_lbar_phy,
 			dev->dm_core + PCIE20_PLR_IATU_LBAR);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PCIE20_PLR_IATU_LBAR:\t0x%llx: 0x%x\n",
+			"PCIe: RC%d: PCIE20_PLR_IATU_LBAR:\t0x%x: 0x%x\n",
 			dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_LBAR,
 			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LBAR));
 
 		writel_relaxed(0x0, dev->dm_core + PCIE20_PLR_IATU_UBAR);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PCIE20_PLR_IATU_UBAR:\t0x%llx: 0x%x\n",
+			"PCIe: RC%d: PCIE20_PLR_IATU_UBAR:\t0x%x: 0x%x\n",
 			dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_UBAR,
 			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UBAR));
 
 		writel_relaxed(loopback_lbar_phy + 0xfff,
 			dev->dm_core + PCIE20_PLR_IATU_LAR);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PCIE20_PLR_IATU_LAR:\t0x%llx: 0x%x\n",
+			"PCIe: RC%d: PCIE20_PLR_IATU_LAR:\t0x%x: 0x%x\n",
 			dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_LAR,
 			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LAR));
 
 		writel_relaxed(loopback_ddr_phy,
 			dev->dm_core + PCIE20_PLR_IATU_LTAR);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PCIE20_PLR_IATU_LTAR:\t0x%llx: 0x%x\n",
+			"PCIe: RC%d: PCIE20_PLR_IATU_LTAR:\t0x%x: 0x%x\n",
 			dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_LTAR,
 			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LTAR));
 
 		writel_relaxed(0, dev->dm_core + PCIE20_PLR_IATU_UTAR);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PCIE20_PLR_IATU_UTAR:\t0x%llx: 0x%x\n",
+			"PCIe: RC%d: PCIE20_PLR_IATU_UTAR:\t0x%x: 0x%x\n",
 			dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_UTAR,
 			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UTAR));
 
 		writel_relaxed(0x80000000,
 			dev->dm_core + PCIE20_PLR_IATU_CTRL2);
 		PCIE_DBG_FS(dev,
-			"PCIe: RC%d: PCIE20_PLR_IATU_CTRL2:\t0x%llx: 0x%x\n",
+			"PCIe: RC%d: PCIE20_PLR_IATU_CTRL2:\t0x%x: 0x%x\n",
 			dev->rc_idx, dbi_base_addr + PCIE20_PLR_IATU_CTRL2,
 			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL2));
 		break;
-	case 19:
+	case MSM_PCIE_READ_DDR:
 		PCIE_DBG_FS(dev,
 			"PCIe: RC%d: Read DDR values.\n",
 			dev->rc_idx);
@@ -1853,7 +1803,7 @@
 				loopback_ddr_vir[i + 7]);
 		}
 		break;
-	case 20:
+	case MSM_PCIE_READ_LBAR:
 		PCIE_DBG_FS(dev,
 			"PCIe: RC%d: Read LBAR values.\n",
 			dev->rc_idx);
@@ -1879,7 +1829,7 @@
 				readl_relaxed(loopback_lbar_vir + (i + 28)));
 		}
 		break;
-	case 21:
+	case MSM_PCIE_WRITE_DDR:
 		PCIE_DBG_FS(dev, "PCIe: RC%d: Write 0x%x to DDR.\n",
 			dev->rc_idx, loopback_val);
 
@@ -1898,7 +1848,7 @@
 		else
 			loopback_val++;
 		break;
-	case 22:
+	case MSM_PCIE_WRITE_LBAR:
 		PCIE_DBG_FS(dev, "PCIe: RC%d: Write 0x%x to LBAR.\n",
 			dev->rc_idx, loopback_val);
 
@@ -1933,6 +1883,53 @@
 		else
 			loopback_val++;
 		break;
+	case MSM_PCIE_DISABLE_AER:
+		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: clear AER enable flag\n\n",
+			dev->rc_idx);
+		dev->aer_enable = false;
+		break;
+	case MSM_PCIE_ENABLE_AER:
+		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: set AER enable flag\n\n",
+			dev->rc_idx);
+		dev->aer_enable = true;
+		break;
+	case MSM_PCIE_GPIO_STATUS:
+		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: PERST and WAKE status\n\n",
+			dev->rc_idx);
+		PCIE_DBG_FS(dev,
+			"PCIe: RC%d: PERST: gpio%u value: %d\n",
+			dev->rc_idx, dev->gpio[MSM_PCIE_GPIO_PERST].num,
+			gpio_get_value(dev->gpio[MSM_PCIE_GPIO_PERST].num));
+		PCIE_DBG_FS(dev,
+			"PCIe: RC%d: WAKE: gpio%u value: %d\n",
+			dev->rc_idx, dev->gpio[MSM_PCIE_GPIO_WAKE].num,
+			gpio_get_value(dev->gpio[MSM_PCIE_GPIO_WAKE].num));
+		break;
+	case MSM_PCIE_ASSERT_PERST:
+		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: assert PERST\n\n",
+			dev->rc_idx);
+		gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num,
+					dev->gpio[MSM_PCIE_GPIO_PERST].on);
+		usleep_range(dev->perst_delay_us_min, dev->perst_delay_us_max);
+		break;
+	case MSM_PCIE_DEASSERT_PERST:
+		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: de-assert PERST\n\n",
+			dev->rc_idx);
+		gpio_set_value(dev->gpio[MSM_PCIE_GPIO_PERST].num,
+					1 - dev->gpio[MSM_PCIE_GPIO_PERST].on);
+		usleep_range(dev->perst_delay_us_min, dev->perst_delay_us_max);
+		break;
+	case MSM_PCIE_KEEP_RESOURCES_ON:
+		PCIE_DBG_FS(dev,
+			"\n\nPCIe: RC%d: set keep resources on flag\n\n",
+			dev->rc_idx);
+		msm_pcie_keep_resources_on |= BIT(dev->rc_idx);
+		break;
+	case MSM_PCIE_FORCE_GEN1:
+		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: set force gen1 flag\n\n",
+			dev->rc_idx);
+		msm_pcie_force_gen1 |= BIT(dev->rc_idx);
+		break;
 	default:
 		PCIE_DBG_FS(dev, "Invalid testcase: %d.\n", testcase);
 		break;
@@ -1950,8 +1947,10 @@
 		return -ENODEV;
 	}
 
-	if (option == 12 || option == 13) {
-		if (!base || base > 5) {
+	if (option == MSM_PCIE_READ_PCIE_REGISTER ||
+		option == MSM_PCIE_WRITE_PCIE_REGISTER ||
+		option == MSM_PCIE_DUMP_PCIE_REGISTER_SPACE) {
+		if (!base || base >= MSM_PCIE_MAX_RES) {
 			PCIE_DBG_FS(pdev, "Invalid base_sel: 0x%x\n", base);
 			PCIE_DBG_FS(pdev,
 				"PCIe: base_sel is still 0x%x\n", base_sel);
@@ -1961,7 +1960,8 @@
 		base_sel = base;
 		PCIE_DBG_FS(pdev, "PCIe: base_sel is now 0x%x\n", base_sel);
 
-		if (option == 12) {
+		if (option == MSM_PCIE_READ_PCIE_REGISTER ||
+			option == MSM_PCIE_WRITE_PCIE_REGISTER) {
 			wr_offset = offset;
 			wr_mask = mask;
 			wr_value = value;
@@ -1976,7 +1976,7 @@
 	}
 
 	pdev = PCIE_BUS_PRIV_DATA(dev->bus);
-	rc_sel = 1 << pdev->rc_idx;
+	rc_sel = BIT(pdev->rc_idx);
 
 	msm_pcie_sel_debug_testcase(pdev, option);
 
@@ -2041,59 +2041,87 @@
 
 static u32 rc_sel_max;
 
-static ssize_t msm_pcie_cmd_debug(struct file *file,
+static int msm_pcie_debugfs_parse_input(const char __user *buf,
+					size_t count, unsigned int *data)
+{
+	unsigned long ret;
+	char *str, *str_temp;
+
+	str = kmalloc(count + 1, GFP_KERNEL);
+	if (!str)
+		return -ENOMEM;
+
+	ret = copy_from_user(str, buf, count);
+	if (ret) {
+		kfree(str);
+		return -EFAULT;
+	}
+
+	str[count] = 0;
+	str_temp = str;
+
+	ret = get_option(&str_temp, data);
+	kfree(str);
+	if (ret != 1)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int msm_pcie_debugfs_case_show(struct seq_file *m, void *v)
+{
+	int i;
+
+	for (i = 0; i < MSM_PCIE_MAX_DEBUGFS_OPTION; i++)
+		seq_printf(m, "\t%d:\t %s\n", i,
+			msm_pcie_debugfs_option_desc[i]);
+
+	return 0;
+}
+
+static int msm_pcie_debugfs_case_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_pcie_debugfs_case_show, NULL);
+}
+
+static ssize_t msm_pcie_debugfs_case_select(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
+	int i, ret;
 	unsigned int testcase = 0;
-	int i;
-	u32 size = sizeof(str) < count ? sizeof(str) : count;
 
-	memset(str, 0, size);
-	ret = copy_from_user(str, buf, size);
+	ret = msm_pcie_debugfs_parse_input(buf, count, &testcase);
 	if (ret)
-		return -EFAULT;
-
-	for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		testcase = (testcase * 10) + (str[i] - '0');
-
-	if (!rc_sel)
-		rc_sel = 1;
+		return ret;
 
 	pr_alert("PCIe: TEST: %d\n", testcase);
 
 	for (i = 0; i < MAX_RC_NUM; i++) {
-		if (!((rc_sel >> i) & 0x1))
-			continue;
-		msm_pcie_sel_debug_testcase(&msm_pcie_dev[i], testcase);
+		if (rc_sel & BIT(i))
+			msm_pcie_sel_debug_testcase(&msm_pcie_dev[i], testcase);
 	}
 
 	return count;
 }
 
-static const struct file_operations msm_pcie_cmd_debug_ops = {
-	.write = msm_pcie_cmd_debug,
+static const struct file_operations msm_pcie_debugfs_case_ops = {
+	.open = msm_pcie_debugfs_case_open,
+	.release = single_release,
+	.read = seq_read,
+	.write = msm_pcie_debugfs_case_select,
 };
 
-static ssize_t msm_pcie_set_rc_sel(struct file *file,
+static ssize_t msm_pcie_debugfs_rc_select(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
-	int i;
+	int i, ret;
 	u32 new_rc_sel = 0;
-	u32 size = sizeof(str) < count ? sizeof(str) : count;
 
-	memset(str, 0, size);
-	ret = copy_from_user(str, buf, size);
+	ret = msm_pcie_debugfs_parse_input(buf, count, &new_rc_sel);
 	if (ret)
-		return -EFAULT;
-
-	for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		new_rc_sel = (new_rc_sel * 10) + (str[i] - '0');
+		return ret;
 
 	if ((!new_rc_sel) || (new_rc_sel > rc_sel_max)) {
 		pr_alert("PCIe: invalid value for rc_sel: 0x%x\n", new_rc_sel);
@@ -2104,232 +2132,151 @@
 	}
 
 	pr_alert("PCIe: the following RC(s) will be tested:\n");
-	for (i = 0; i < MAX_RC_NUM; i++) {
-		if (!rc_sel) {
+	for (i = 0; i < MAX_RC_NUM; i++)
+		if (rc_sel & BIT(i))
 			pr_alert("RC %d\n", i);
-			break;
-		} else if (rc_sel & (1 << i)) {
-			pr_alert("RC %d\n", i);
-		}
-	}
 
 	return count;
 }
 
-static const struct file_operations msm_pcie_rc_sel_ops = {
-	.write = msm_pcie_set_rc_sel,
+static const struct file_operations msm_pcie_debugfs_rc_select_ops = {
+	.write = msm_pcie_debugfs_rc_select,
 };
 
-static ssize_t msm_pcie_set_base_sel(struct file *file,
+static ssize_t msm_pcie_debugfs_base_select(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
-	int i;
+	int ret;
 	u32 new_base_sel = 0;
-	char *base_sel_name;
-	u32 size = sizeof(str) < count ? sizeof(str) : count;
 
-	memset(str, 0, size);
-	ret = copy_from_user(str, buf, size);
+	ret = msm_pcie_debugfs_parse_input(buf, count, &new_base_sel);
 	if (ret)
-		return -EFAULT;
+		return ret;
 
-	for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		new_base_sel = (new_base_sel * 10) + (str[i] - '0');
-
-	if (!new_base_sel || new_base_sel > 5) {
+	if (!new_base_sel || new_base_sel > MSM_PCIE_MAX_RES) {
 		pr_alert("PCIe: invalid value for base_sel: 0x%x\n",
 			new_base_sel);
 		pr_alert("PCIe: base_sel is still 0x%x\n", base_sel);
 	} else {
 		base_sel = new_base_sel;
 		pr_alert("PCIe: base_sel is now 0x%x\n", base_sel);
+		pr_alert("%s\n", msm_pcie_res_info[base_sel - 1].name);
 	}
 
-	switch (base_sel) {
-	case 1:
-		base_sel_name = "PARF";
-		break;
-	case 2:
-		base_sel_name = "PHY";
-		break;
-	case 3:
-		base_sel_name = "RC CONFIG SPACE";
-		break;
-	case 4:
-		base_sel_name = "ELBI";
-		break;
-	case 5:
-		base_sel_name = "EP CONFIG SPACE";
-		break;
-	default:
-		base_sel_name = "INVALID";
-		break;
-	}
-
-	pr_alert("%s\n", base_sel_name);
-
 	return count;
 }
 
-static const struct file_operations msm_pcie_base_sel_ops = {
-	.write = msm_pcie_set_base_sel,
+static const struct file_operations msm_pcie_debugfs_base_select_ops = {
+	.write = msm_pcie_debugfs_base_select,
 };
 
-static ssize_t msm_pcie_set_linkdown_panic(struct file *file,
+static ssize_t msm_pcie_debugfs_linkdown_panic(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
+	int i, ret;
 	u32 new_linkdown_panic = 0;
-	int i;
 
-	memset(str, 0, sizeof(str));
-	ret = copy_from_user(str, buf, sizeof(str));
+	ret = msm_pcie_debugfs_parse_input(buf, count, &new_linkdown_panic);
 	if (ret)
-		return -EFAULT;
+		return ret;
 
-	for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		new_linkdown_panic = (new_linkdown_panic * 10) + (str[i] - '0');
+	new_linkdown_panic = !!new_linkdown_panic;
 
-	if (new_linkdown_panic <= 1) {
-		for (i = 0; i < MAX_RC_NUM; i++) {
-			if (!rc_sel) {
-				msm_pcie_dev[0].linkdown_panic =
-					new_linkdown_panic;
-				PCIE_DBG_FS(&msm_pcie_dev[0],
-					"PCIe: RC0: linkdown_panic is now %d\n",
-					msm_pcie_dev[0].linkdown_panic);
-				break;
-			} else if (rc_sel & (1 << i)) {
-				msm_pcie_dev[i].linkdown_panic =
-					new_linkdown_panic;
-				PCIE_DBG_FS(&msm_pcie_dev[i],
-					"PCIe: RC%d: linkdown_panic is now %d\n",
-					i, msm_pcie_dev[i].linkdown_panic);
-			}
+	for (i = 0; i < MAX_RC_NUM; i++) {
+		if (rc_sel & BIT(i)) {
+			msm_pcie_dev[i].linkdown_panic =
+				new_linkdown_panic;
+			PCIE_DBG_FS(&msm_pcie_dev[i],
+				"PCIe: RC%d: linkdown_panic is now %d\n",
+				i, msm_pcie_dev[i].linkdown_panic);
 		}
-	} else {
-		pr_err("PCIe: Invalid input for linkdown_panic: %d. Please enter 0 or 1.\n",
-			new_linkdown_panic);
 	}
 
 	return count;
 }
 
-static const struct file_operations msm_pcie_linkdown_panic_ops = {
-	.write = msm_pcie_set_linkdown_panic,
+static const struct file_operations msm_pcie_debugfs_linkdown_panic_ops = {
+	.write = msm_pcie_debugfs_linkdown_panic,
 };
 
-static ssize_t msm_pcie_set_wr_offset(struct file *file,
+static ssize_t msm_pcie_debugfs_wr_offset(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
-	int i;
-	u32 size = sizeof(str) < count ? sizeof(str) : count;
-
-	memset(str, 0, size);
-	ret = copy_from_user(str, buf, size);
-	if (ret)
-		return -EFAULT;
+	int ret;
 
 	wr_offset = 0;
-	for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		wr_offset = (wr_offset * 10) + (str[i] - '0');
+
+	ret = msm_pcie_debugfs_parse_input(buf, count, &wr_offset);
+	if (ret)
+		return ret;
 
 	pr_alert("PCIe: wr_offset is now 0x%x\n", wr_offset);
 
 	return count;
 }
 
-static const struct file_operations msm_pcie_wr_offset_ops = {
-	.write = msm_pcie_set_wr_offset,
+static const struct file_operations msm_pcie_debugfs_wr_offset_ops = {
+	.write = msm_pcie_debugfs_wr_offset,
 };
 
-static ssize_t msm_pcie_set_wr_mask(struct file *file,
+static ssize_t msm_pcie_debugfs_wr_mask(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
-	int i;
-	u32 size = sizeof(str) < count ? sizeof(str) : count;
-
-	memset(str, 0, size);
-	ret = copy_from_user(str, buf, size);
-	if (ret)
-		return -EFAULT;
+	int ret;
 
 	wr_mask = 0;
-	for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		wr_mask = (wr_mask * 10) + (str[i] - '0');
+
+	ret = msm_pcie_debugfs_parse_input(buf, count, &wr_mask);
+	if (ret)
+		return ret;
 
 	pr_alert("PCIe: wr_mask is now 0x%x\n", wr_mask);
 
 	return count;
 }
 
-static const struct file_operations msm_pcie_wr_mask_ops = {
-	.write = msm_pcie_set_wr_mask,
+static const struct file_operations msm_pcie_debugfs_wr_mask_ops = {
+	.write = msm_pcie_debugfs_wr_mask,
 };
-static ssize_t msm_pcie_set_wr_value(struct file *file,
+static ssize_t msm_pcie_debugfs_wr_value(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
-	int i;
-	u32 size = sizeof(str) < count ? sizeof(str) : count;
-
-	memset(str, 0, size);
-	ret = copy_from_user(str, buf, size);
-	if (ret)
-		return -EFAULT;
+	int ret;
 
 	wr_value = 0;
-	for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		wr_value = (wr_value * 10) + (str[i] - '0');
+
+	ret = msm_pcie_debugfs_parse_input(buf, count, &wr_value);
+	if (ret)
+		return ret;
 
 	pr_alert("PCIe: wr_value is now 0x%x\n", wr_value);
 
 	return count;
 }
 
-static const struct file_operations msm_pcie_wr_value_ops = {
-	.write = msm_pcie_set_wr_value,
+static const struct file_operations msm_pcie_debugfs_wr_value_ops = {
+	.write = msm_pcie_debugfs_wr_value,
 };
 
-static ssize_t msm_pcie_set_boot_option(struct file *file,
+static ssize_t msm_pcie_debugfs_boot_option(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
+	int i, ret;
 	u32 new_boot_option = 0;
-	int i;
 
-	memset(str, 0, sizeof(str));
-	ret = copy_from_user(str, buf, sizeof(str));
+	ret = msm_pcie_debugfs_parse_input(buf, count, &new_boot_option);
 	if (ret)
-		return -EFAULT;
+		return ret;
 
-	for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		new_boot_option = (new_boot_option * 10) + (str[i] - '0');
-
-	if (new_boot_option <= 1) {
+	if (new_boot_option <= (BIT(0) | BIT(1))) {
 		for (i = 0; i < MAX_RC_NUM; i++) {
-			if (!rc_sel) {
-				msm_pcie_dev[0].boot_option = new_boot_option;
-				PCIE_DBG_FS(&msm_pcie_dev[0],
-					"PCIe: RC0: boot_option is now 0x%x\n",
-					msm_pcie_dev[0].boot_option);
-				break;
-			} else if (rc_sel & (1 << i)) {
+			if (rc_sel & BIT(i)) {
 				msm_pcie_dev[i].boot_option = new_boot_option;
 				PCIE_DBG_FS(&msm_pcie_dev[i],
 					"PCIe: RC%d: boot_option is now 0x%x\n",
@@ -2344,42 +2291,25 @@
 	return count;
 }
 
-static const struct file_operations msm_pcie_boot_option_ops = {
-	.write = msm_pcie_set_boot_option,
+static const struct file_operations msm_pcie_debugfs_boot_option_ops = {
+	.write = msm_pcie_debugfs_boot_option,
 };
 
-static ssize_t msm_pcie_set_aer_enable(struct file *file,
+static ssize_t msm_pcie_debugfs_aer_enable(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
+	int i, ret;
 	u32 new_aer_enable = 0;
-	u32 temp_rc_sel;
-	int i;
 
-	memset(str, 0, sizeof(str));
-	ret = copy_from_user(str, buf, sizeof(str));
+	ret = msm_pcie_debugfs_parse_input(buf, count, &new_aer_enable);
 	if (ret)
-		return -EFAULT;
+		return ret;
 
-	for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		new_aer_enable = (new_aer_enable * 10) + (str[i] - '0');
-
-	if (new_aer_enable > 1) {
-		pr_err(
-			"PCIe: Invalid input for aer_enable: %d. Please enter 0 or 1.\n",
-			new_aer_enable);
-		return count;
-	}
-
-	if (rc_sel)
-		temp_rc_sel = rc_sel;
-	else
-		temp_rc_sel = 0x1;
+	new_aer_enable = !!new_aer_enable;
 
 	for (i = 0; i < MAX_RC_NUM; i++) {
-		if (temp_rc_sel & (1 << i)) {
+		if (rc_sel & BIT(i)) {
 			msm_pcie_dev[i].aer_enable = new_aer_enable;
 			PCIE_DBG_FS(&msm_pcie_dev[i],
 				"PCIe: RC%d: aer_enable is now %d\n",
@@ -2400,35 +2330,29 @@
 	return count;
 }
 
-static const struct file_operations msm_pcie_aer_enable_ops = {
-	.write = msm_pcie_set_aer_enable,
+static const struct file_operations msm_pcie_debugfs_aer_enable_ops = {
+	.write = msm_pcie_debugfs_aer_enable,
 };
 
-static ssize_t msm_pcie_set_corr_counter_limit(struct file *file,
+static ssize_t msm_pcie_debugfs_corr_counter_limit(struct file *file,
 				const char __user *buf,
 				size_t count, loff_t *ppos)
 {
-	unsigned long ret;
-	char str[MAX_MSG_LEN];
-	int i;
-	u32 size = sizeof(str) < count ? sizeof(str) : count;
-
-	memset(str, 0, size);
-	ret = copy_from_user(str, buf, size);
-	if (ret)
-		return -EFAULT;
+	int ret;
 
 	corr_counter_limit = 0;
-	for (i = 0; i < size && (str[i] >= '0') && (str[i] <= '9'); ++i)
-		corr_counter_limit = (corr_counter_limit * 10) + (str[i] - '0');
 
-	pr_info("PCIe: corr_counter_limit is now %lu\n", corr_counter_limit);
+	ret = msm_pcie_debugfs_parse_input(buf, count, &corr_counter_limit);
+	if (ret)
+		return ret;
+
+	pr_info("PCIe: corr_counter_limit is now %u\n", corr_counter_limit);
 
 	return count;
 }
 
-static const struct file_operations msm_pcie_corr_counter_limit_ops = {
-	.write = msm_pcie_set_corr_counter_limit,
+static const struct file_operations msm_pcie_debugfs_corr_counter_limit_ops = {
+	.write = msm_pcie_debugfs_corr_counter_limit,
 };
 
 static void msm_pcie_debugfs_init(void)
@@ -2444,7 +2368,7 @@
 
 	dfile_rc_sel = debugfs_create_file("rc_sel", 0664,
 					dent_msm_pcie, NULL,
-					&msm_pcie_rc_sel_ops);
+					&msm_pcie_debugfs_rc_select_ops);
 	if (!dfile_rc_sel || IS_ERR(dfile_rc_sel)) {
 		pr_err("PCIe: fail to create the file for debug_fs rc_sel.\n");
 		goto rc_sel_error;
@@ -2452,7 +2376,7 @@
 
 	dfile_case = debugfs_create_file("case", 0664,
 					dent_msm_pcie, NULL,
-					&msm_pcie_cmd_debug_ops);
+					&msm_pcie_debugfs_case_ops);
 	if (!dfile_case || IS_ERR(dfile_case)) {
 		pr_err("PCIe: fail to create the file for debug_fs case.\n");
 		goto case_error;
@@ -2460,7 +2384,7 @@
 
 	dfile_base_sel = debugfs_create_file("base_sel", 0664,
 					dent_msm_pcie, NULL,
-					&msm_pcie_base_sel_ops);
+					&msm_pcie_debugfs_base_select_ops);
 	if (!dfile_base_sel || IS_ERR(dfile_base_sel)) {
 		pr_err("PCIe: fail to create the file for debug_fs base_sel.\n");
 		goto base_sel_error;
@@ -2468,7 +2392,7 @@
 
 	dfile_linkdown_panic = debugfs_create_file("linkdown_panic", 0644,
 					dent_msm_pcie, NULL,
-					&msm_pcie_linkdown_panic_ops);
+					&msm_pcie_debugfs_linkdown_panic_ops);
 	if (!dfile_linkdown_panic || IS_ERR(dfile_linkdown_panic)) {
 		pr_err("PCIe: fail to create the file for debug_fs linkdown_panic.\n");
 		goto linkdown_panic_error;
@@ -2476,7 +2400,7 @@
 
 	dfile_wr_offset = debugfs_create_file("wr_offset", 0664,
 					dent_msm_pcie, NULL,
-					&msm_pcie_wr_offset_ops);
+					&msm_pcie_debugfs_wr_offset_ops);
 	if (!dfile_wr_offset || IS_ERR(dfile_wr_offset)) {
 		pr_err("PCIe: fail to create the file for debug_fs wr_offset.\n");
 		goto wr_offset_error;
@@ -2484,7 +2408,7 @@
 
 	dfile_wr_mask = debugfs_create_file("wr_mask", 0664,
 					dent_msm_pcie, NULL,
-					&msm_pcie_wr_mask_ops);
+					&msm_pcie_debugfs_wr_mask_ops);
 	if (!dfile_wr_mask || IS_ERR(dfile_wr_mask)) {
 		pr_err("PCIe: fail to create the file for debug_fs wr_mask.\n");
 		goto wr_mask_error;
@@ -2492,7 +2416,7 @@
 
 	dfile_wr_value = debugfs_create_file("wr_value", 0664,
 					dent_msm_pcie, NULL,
-					&msm_pcie_wr_value_ops);
+					&msm_pcie_debugfs_wr_value_ops);
 	if (!dfile_wr_value || IS_ERR(dfile_wr_value)) {
 		pr_err("PCIe: fail to create the file for debug_fs wr_value.\n");
 		goto wr_value_error;
@@ -2500,7 +2424,7 @@
 
 	dfile_boot_option = debugfs_create_file("boot_option", 0664,
 					dent_msm_pcie, NULL,
-					&msm_pcie_boot_option_ops);
+					&msm_pcie_debugfs_boot_option_ops);
 	if (!dfile_boot_option || IS_ERR(dfile_boot_option)) {
 		pr_err("PCIe: fail to create the file for debug_fs boot_option.\n");
 		goto boot_option_error;
@@ -2508,15 +2432,15 @@
 
 	dfile_aer_enable = debugfs_create_file("aer_enable", 0664,
 					dent_msm_pcie, NULL,
-					&msm_pcie_aer_enable_ops);
+					&msm_pcie_debugfs_aer_enable_ops);
 	if (!dfile_aer_enable || IS_ERR(dfile_aer_enable)) {
 		pr_err("PCIe: fail to create the file for debug_fs aer_enable.\n");
 		goto aer_enable_error;
 	}
 
 	dfile_corr_counter_limit = debugfs_create_file("corr_counter_limit",
-					0664, dent_msm_pcie, NULL,
-					&msm_pcie_corr_counter_limit_ops);
+				0664, dent_msm_pcie, NULL,
+				&msm_pcie_debugfs_corr_counter_limit_ops);
 	if (!dfile_corr_counter_limit || IS_ERR(dfile_corr_counter_limit)) {
 		pr_err("PCIe: fail to create the file for debug_fs corr_counter_limit.\n");
 		goto corr_counter_limit_error;
@@ -2588,9 +2512,38 @@
 				unsigned long host_addr, u32 host_end,
 				unsigned long target_addr)
 {
-	void __iomem *pcie20 = dev->dm_core;
+	void __iomem *iatu_base = dev->iatu ? dev->iatu : dev->dm_core;
 
-	if (dev->shadow_en) {
+	u32 iatu_viewport_offset;
+	u32 iatu_ctrl1_offset;
+	u32 iatu_ctrl2_offset;
+	u32 iatu_lbar_offset;
+	u32 iatu_ubar_offset;
+	u32 iatu_lar_offset;
+	u32 iatu_ltar_offset;
+	u32 iatu_utar_offset;
+
+	if (dev->iatu) {
+		iatu_viewport_offset = 0;
+		iatu_ctrl1_offset = PCIE_IATU_CTRL1(nr);
+		iatu_ctrl2_offset = PCIE_IATU_CTRL2(nr);
+		iatu_lbar_offset = PCIE_IATU_LBAR(nr);
+		iatu_ubar_offset = PCIE_IATU_UBAR(nr);
+		iatu_lar_offset = PCIE_IATU_LAR(nr);
+		iatu_ltar_offset = PCIE_IATU_LTAR(nr);
+		iatu_utar_offset = PCIE_IATU_UTAR(nr);
+	} else {
+		iatu_viewport_offset = PCIE20_PLR_IATU_VIEWPORT;
+		iatu_ctrl1_offset = PCIE20_PLR_IATU_CTRL1;
+		iatu_ctrl2_offset = PCIE20_PLR_IATU_CTRL2;
+		iatu_lbar_offset = PCIE20_PLR_IATU_LBAR;
+		iatu_ubar_offset = PCIE20_PLR_IATU_UBAR;
+		iatu_lar_offset = PCIE20_PLR_IATU_LAR;
+		iatu_ltar_offset = PCIE20_PLR_IATU_LTAR;
+		iatu_utar_offset = PCIE20_PLR_IATU_UTAR;
+	}
+
+	if (dev->shadow_en && iatu_viewport_offset) {
 		dev->rc_shadow[PCIE20_PLR_IATU_VIEWPORT / 4] =
 			nr;
 		dev->rc_shadow[PCIE20_PLR_IATU_CTRL1 / 4] =
@@ -2610,28 +2563,30 @@
 	}
 
 	/* select region */
-	writel_relaxed(nr, pcie20 + PCIE20_PLR_IATU_VIEWPORT);
-	/* ensure that hardware locks it */
-	wmb();
+	if (iatu_viewport_offset) {
+		writel_relaxed(nr, iatu_base + iatu_viewport_offset);
+		/* ensure that hardware locks it */
+		wmb();
+	}
 
 	/* switch off region before changing it */
-	writel_relaxed(0, pcie20 + PCIE20_PLR_IATU_CTRL2);
+	writel_relaxed(0, iatu_base + iatu_ctrl2_offset);
 	/* and wait till it propagates to the hardware */
 	wmb();
 
-	writel_relaxed(type, pcie20 + PCIE20_PLR_IATU_CTRL1);
+	writel_relaxed(type, iatu_base + iatu_ctrl1_offset);
 	writel_relaxed(lower_32_bits(host_addr),
-		       pcie20 + PCIE20_PLR_IATU_LBAR);
+		       iatu_base + iatu_lbar_offset);
 	writel_relaxed(upper_32_bits(host_addr),
-		       pcie20 + PCIE20_PLR_IATU_UBAR);
-	writel_relaxed(host_end, pcie20 + PCIE20_PLR_IATU_LAR);
+		       iatu_base + iatu_ubar_offset);
+	writel_relaxed(host_end, iatu_base + iatu_lar_offset);
 	writel_relaxed(lower_32_bits(target_addr),
-		       pcie20 + PCIE20_PLR_IATU_LTAR);
+		       iatu_base + iatu_ltar_offset);
 	writel_relaxed(upper_32_bits(target_addr),
-		       pcie20 + PCIE20_PLR_IATU_UTAR);
+		       iatu_base + iatu_utar_offset);
 	/* ensure that changes propagated to the hardware */
 	wmb();
-	writel_relaxed(BIT(31), pcie20 + PCIE20_PLR_IATU_CTRL2);
+	writel_relaxed(BIT(31), iatu_base + iatu_ctrl2_offset);
 
 	/* ensure that changes propagated to the hardware */
 	wmb();
@@ -2641,22 +2596,24 @@
 			dev->pcidev_table[nr].bdf >> 24,
 			dev->pcidev_table[nr].bdf >> 19 & 0x1f,
 			dev->pcidev_table[nr].bdf >> 16 & 0x07);
-		PCIE_DBG2(dev, "PCIE20_PLR_IATU_VIEWPORT:0x%x\n",
-			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_VIEWPORT));
-		PCIE_DBG2(dev, "PCIE20_PLR_IATU_CTRL1:0x%x\n",
-			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL1));
-		PCIE_DBG2(dev, "PCIE20_PLR_IATU_LBAR:0x%x\n",
-			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LBAR));
-		PCIE_DBG2(dev, "PCIE20_PLR_IATU_UBAR:0x%x\n",
-			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UBAR));
-		PCIE_DBG2(dev, "PCIE20_PLR_IATU_LAR:0x%x\n",
-			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LAR));
-		PCIE_DBG2(dev, "PCIE20_PLR_IATU_LTAR:0x%x\n",
-			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_LTAR));
-		PCIE_DBG2(dev, "PCIE20_PLR_IATU_UTAR:0x%x\n",
-			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_UTAR));
-		PCIE_DBG2(dev, "PCIE20_PLR_IATU_CTRL2:0x%x\n\n",
-			readl_relaxed(dev->dm_core + PCIE20_PLR_IATU_CTRL2));
+		if (iatu_viewport_offset)
+			PCIE_DBG2(dev, "IATU_VIEWPORT:0x%x\n",
+				readl_relaxed(dev->dm_core +
+					PCIE20_PLR_IATU_VIEWPORT));
+		PCIE_DBG2(dev, "IATU_CTRL1:0x%x\n",
+			readl_relaxed(iatu_base + iatu_ctrl1_offset));
+		PCIE_DBG2(dev, "IATU_LBAR:0x%x\n",
+			readl_relaxed(iatu_base + iatu_lbar_offset));
+		PCIE_DBG2(dev, "IATU_UBAR:0x%x\n",
+			readl_relaxed(iatu_base + iatu_ubar_offset));
+		PCIE_DBG2(dev, "IATU_LAR:0x%x\n",
+			readl_relaxed(iatu_base + iatu_lar_offset));
+		PCIE_DBG2(dev, "IATU_LTAR:0x%x\n",
+			readl_relaxed(iatu_base + iatu_ltar_offset));
+		PCIE_DBG2(dev, "IATU_UTAR:0x%x\n",
+			readl_relaxed(iatu_base + iatu_utar_offset));
+		PCIE_DBG2(dev, "IATU_CTRL2:0x%x\n\n",
+			readl_relaxed(iatu_base + iatu_ctrl2_offset));
 	}
 }
 
@@ -3387,8 +3344,8 @@
 
 	PCIE_DBG(dev, "RC%d: entry\n", dev->rc_idx);
 
-	cnt = of_property_count_strings((&pdev->dev)->of_node,
-			"clock-names");
+	cnt = of_property_count_elems_of_size((&pdev->dev)->of_node,
+			"max-clock-frequency-hz", sizeof(u32));
 	if (cnt > 0) {
 		clkfreq = kzalloc((MSM_PCIE_MAX_CLK + MSM_PCIE_MAX_PIPE_CLK) *
 					sizeof(*clkfreq), GFP_KERNEL);
@@ -3706,6 +3663,7 @@
 	dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
 	dev->phy = dev->res[MSM_PCIE_RES_PHY].base;
 	dev->elbi = dev->res[MSM_PCIE_RES_ELBI].base;
+	dev->iatu = dev->res[MSM_PCIE_RES_IATU].base;
 	dev->dm_core = dev->res[MSM_PCIE_RES_DM_CORE].base;
 	dev->conf = dev->res[MSM_PCIE_RES_CONF].base;
 	dev->bars = dev->res[MSM_PCIE_RES_BARS].base;
@@ -3726,6 +3684,7 @@
 {
 	dev->parf = NULL;
 	dev->elbi = NULL;
+	dev->iatu = NULL;
 	dev->dm_core = NULL;
 	dev->conf = NULL;
 	dev->bars = NULL;
@@ -3771,6 +3730,7 @@
 	long int retries = 0;
 	int link_check_count = 0;
 	unsigned long ep_up_timeout = 0;
+	u32 link_check_max_count;
 
 	PCIE_DBG(dev, "RC%d: entry\n", dev->rc_idx);
 
@@ -3937,6 +3897,11 @@
 	if (dev->max_link_speed == GEN3_SPEED)
 		msm_pcie_setup_gen3(dev);
 
+	if (msm_pcie_force_gen1 & BIT(dev->rc_idx))
+		msm_pcie_write_reg_field(dev->dm_core,
+			PCIE20_CAP + PCI_EXP_LNKCTL2,
+			PCI_EXP_LNKCAP_SLS, GEN1_SPEED);
+
 	/* set max tlp read size */
 	msm_pcie_write_reg_field(dev->dm_core, PCIE20_DEVICE_CONTROL_STATUS,
 				0x7000, dev->tlp_rd_size);
@@ -3946,6 +3911,11 @@
 
 	PCIE_DBG(dev, "%s", "check if link is up\n");
 
+	if (msm_pcie_link_check_max_count & BIT(dev->rc_idx))
+		link_check_max_count = msm_pcie_link_check_max_count >> 4;
+	else
+		link_check_max_count = LINK_UP_CHECK_MAX_COUNT;
+
 	/* Wait for up to 100ms for the link to come up */
 	do {
 		usleep_range(LINK_UP_TIMEOUT_US_MIN, LINK_UP_TIMEOUT_US_MAX);
@@ -3954,7 +3924,7 @@
 			dev->rc_idx, (val >> 12) & 0x3f);
 	} while ((!(val & XMLH_LINK_UP) ||
 		!msm_pcie_confirm_linkup(dev, false, false, NULL))
-		&& (link_check_count++ < LINK_UP_CHECK_MAX_COUNT));
+		&& (link_check_count++ < link_check_max_count));
 
 	if ((val & XMLH_LINK_UP) &&
 		msm_pcie_confirm_linkup(dev, false, false, NULL)) {
@@ -4330,9 +4300,7 @@
 			}
 
 			bus = pci_create_root_bus(&dev->pdev->dev, 0,
-						&msm_pcie_ops,
-						msm_pcie_setup_sys_data(dev),
-						&res);
+						&msm_pcie_ops, dev, &res);
 			if (!bus) {
 				PCIE_ERR(dev,
 					"PCIe: failed to create root bus for RC%d\n",
@@ -4344,7 +4312,7 @@
 			scan_ret = pci_scan_child_bus(bus);
 			PCIE_DBG(dev,
 				"PCIe: RC%d: The max subordinate bus number discovered is %d\n",
-				dev->rc_idx, ret);
+				dev->rc_idx, scan_ret);
 
 			msm_pcie_fixup_irqs(dev);
 			pci_assign_unassigned_bus_resources(bus);
@@ -4529,7 +4497,6 @@
 	u32 ep_dev_ctrlstts_offset = 0;
 	int i, j, ep_src_bdf = 0;
 	void __iomem *ep_base = NULL;
-	unsigned long irqsave_flags;
 
 	PCIE_DBG2(dev,
 		"AER Interrupt handler fired for RC%d irq %d\nrc_corr_counter: %lu\nrc_non_fatal_counter: %lu\nrc_fatal_counter: %lu\nep_corr_counter: %lu\nep_non_fatal_counter: %lu\nep_fatal_counter: %lu\n",
@@ -4538,16 +4505,6 @@
 		dev->ep_corr_counter, dev->ep_non_fatal_counter,
 		dev->ep_fatal_counter);
 
-	spin_lock_irqsave(&dev->aer_lock, irqsave_flags);
-
-	if (dev->suspending) {
-		PCIE_DBG2(dev,
-			"PCIe: RC%d is currently suspending.\n",
-			dev->rc_idx);
-		spin_unlock_irqrestore(&dev->aer_lock, irqsave_flags);
-		return IRQ_HANDLED;
-	}
-
 	uncorr_val = readl_relaxed(dev->dm_core +
 				PCIE20_AER_UNCORR_ERR_STATUS_REG);
 	corr_val = readl_relaxed(dev->dm_core +
@@ -4661,7 +4618,6 @@
 			PCIE20_AER_ROOT_ERR_STATUS_REG,
 			0x7f, 0x7f);
 
-	spin_unlock_irqrestore(&dev->aer_lock, irqsave_flags);
 	return IRQ_HANDLED;
 }
 
@@ -4709,11 +4665,8 @@
 static irqreturn_t handle_linkdown_irq(int irq, void *data)
 {
 	struct msm_pcie_dev_t *dev = data;
-	unsigned long irqsave_flags;
 	int i;
 
-	spin_lock_irqsave(&dev->linkdown_lock, irqsave_flags);
-
 	dev->linkdown_counter++;
 
 	PCIE_DBG(dev,
@@ -4754,8 +4707,6 @@
 		}
 	}
 
-	spin_unlock_irqrestore(&dev->linkdown_lock, irqsave_flags);
-
 	return IRQ_HANDLED;
 }
 
@@ -4799,7 +4750,15 @@
 	unsigned long irqsave_flags;
 	u32 status = 0;
 
-	spin_lock_irqsave(&dev->global_irq_lock, irqsave_flags);
+	spin_lock_irqsave(&dev->irq_lock, irqsave_flags);
+
+	if (dev->suspending) {
+		PCIE_DBG2(dev,
+			"PCIe: RC%d is currently suspending.\n",
+			dev->rc_idx);
+		spin_unlock_irqrestore(&dev->irq_lock, irqsave_flags);
+		return IRQ_HANDLED;
+	}
 
 	status = readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_STATUS) &
 			readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK);
@@ -4838,13 +4797,14 @@
 		}
 	}
 
-	spin_unlock_irqrestore(&dev->global_irq_lock, irqsave_flags);
+	spin_unlock_irqrestore(&dev->irq_lock, irqsave_flags);
 
 	return IRQ_HANDLED;
 }
 
 static void msm_pcie_unmap_qgic_addr(struct msm_pcie_dev_t *dev,
-					struct pci_dev *pdev)
+					struct pci_dev *pdev,
+					struct msi_desc *entry)
 {
 	struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
 	int bypass_en = 0;
@@ -4858,30 +4818,20 @@
 
 	iommu_domain_get_attr(domain, DOMAIN_ATTR_S1_BYPASS, &bypass_en);
 	if (!bypass_en) {
-		int ret;
-		phys_addr_t pcie_base_addr =
-			dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
-		dma_addr_t iova = rounddown(pcie_base_addr, PAGE_SIZE);
+		dma_addr_t iova = entry->msg.address_lo;
 
-		ret = iommu_unmap(domain, iova, PAGE_SIZE);
-		if (ret != PAGE_SIZE)
-			PCIE_ERR(dev,
-				"PCIe: RC%d: failed to unmap QGIC address. ret = %d\n",
-				dev->rc_idx, ret);
+		PCIE_DBG(dev, "PCIe: RC%d: unmap QGIC MSI IOVA\n", dev->rc_idx);
+
+		dma_unmap_resource(&pdev->dev, iova, PAGE_SIZE,
+				DMA_BIDIRECTIONAL, 0);
 	}
 }
 
-static void msm_pcie_destroy_irq(unsigned int irq, struct pci_dev *pdev)
+static void msm_pcie_destroy_irq(struct msi_desc *entry, unsigned int irq)
 {
 	int pos;
-	struct msi_desc *entry = irq_get_msi_desc(irq);
-	struct msi_desc *firstentry;
 	struct msm_pcie_dev_t *dev;
-	u32 nvec;
-	int firstirq;
-
-	if (!pdev)
-		pdev = irq_get_chip_data(irq);
+	struct pci_dev *pdev = msi_desc_to_pci_dev(entry);
 
 	if (!pdev) {
 		pr_err("PCIe: pci device is null. IRQ:%d\n", irq);
@@ -4894,24 +4844,10 @@
 		return;
 	}
 
-	if (!entry) {
-		PCIE_ERR(dev, "PCIe: RC%d: msi desc is null. IRQ:%d\n",
-			dev->rc_idx, irq);
-		return;
-	}
-
-	firstentry = first_pci_msi_entry(pdev);
-	if (!firstentry) {
-		PCIE_ERR(dev,
-			"PCIe: RC%d: firstentry msi desc is null. IRQ:%d\n",
-			dev->rc_idx, irq);
-		return;
-	}
-
-	firstirq = firstentry->irq;
-	nvec = (1 << entry->msi_attrib.multiple);
-
 	if (dev->msi_gicm_addr) {
+		int firstirq = entry->irq;
+		u32 nvec = (1 << entry->msi_attrib.multiple);
+
 		PCIE_DBG(dev, "destroy QGIC based irq %d\n", irq);
 
 		if (irq < firstirq || irq > firstirq + nvec - 1) {
@@ -4921,7 +4857,7 @@
 			return;
 		}
 		if (irq == firstirq + nvec - 1)
-			msm_pcie_unmap_qgic_addr(dev, pdev);
+			msm_pcie_unmap_qgic_addr(dev, pdev, entry);
 		pos = irq - firstirq;
 	} else {
 		PCIE_DBG(dev, "destroy default MSI irq %d\n", irq);
@@ -4940,8 +4876,12 @@
 /* hookup to linux pci msi framework */
 void arch_teardown_msi_irq(unsigned int irq)
 {
+	struct msi_desc *entry = irq_get_msi_desc(irq);
+
 	PCIE_GEN_DBG("irq %d deallocated\n", irq);
-	msm_pcie_destroy_irq(irq, NULL);
+
+	if (entry)
+		msm_pcie_destroy_irq(entry, irq);
 }
 
 void arch_teardown_msi_irqs(struct pci_dev *dev)
@@ -4961,7 +4901,7 @@
 			continue;
 		nvec = 1 << entry->msi_attrib.multiple;
 		for (i = 0; i < nvec; i++)
-			msm_pcie_destroy_irq(entry->irq + i, dev);
+			msm_pcie_destroy_irq(entry, entry->irq + i);
 	}
 }
 
@@ -5075,9 +5015,8 @@
 					struct msi_msg *msg)
 {
 	struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
-	struct iommu_domain_geometry geometry;
-	int fastmap_en = 0, bypass_en = 0;
-	dma_addr_t iova, addr;
+	int bypass_en = 0;
+	dma_addr_t iova;
 
 	msg->address_hi = 0;
 	msg->address_lo = dev->msi_gicm_addr;
@@ -5099,35 +5038,15 @@
 	if (bypass_en)
 		return 0;
 
-	iommu_domain_get_attr(domain, DOMAIN_ATTR_FAST, &fastmap_en);
-	if (fastmap_en) {
-		iommu_domain_get_attr(domain, DOMAIN_ATTR_GEOMETRY, &geometry);
-		iova = geometry.aperture_start;
-		PCIE_DBG(dev,
-			"PCIe: RC%d: Use client's IOVA 0x%llx to map QGIC MSI address\n",
-			dev->rc_idx, iova);
-	} else {
-		phys_addr_t pcie_base_addr;
-
-		/*
-		 * Use PCIe DBI address as the IOVA since client cannot
-		 * use this address for their IOMMU mapping. This will
-		 * prevent any conflicts between PCIe host and
-		 * client's mapping.
-		 */
-		pcie_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
-		iova = rounddown(pcie_base_addr, PAGE_SIZE);
-	}
-
-	addr = dma_map_resource(&pdev->dev, dev->msi_gicm_addr, PAGE_SIZE,
+	iova = dma_map_resource(&pdev->dev, dev->msi_gicm_addr, PAGE_SIZE,
 				DMA_BIDIRECTIONAL, 0);
-	if (dma_mapping_error(&pdev->dev, addr)) {
+	if (dma_mapping_error(&pdev->dev, iova)) {
 		PCIE_ERR(dev, "PCIe: RC%d: failed to map QGIC address",
 			dev->rc_idx);
 		return -EIO;
 	}
 
-	msg->address_lo = iova + addr;
+	msg->address_lo = iova;
 
 	return 0;
 }
@@ -5415,6 +5334,22 @@
 	PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val);
 }
 
+static int msm_pcie_config_l0s_disable(struct pci_dev *pdev, void *dev)
+{
+	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+	msm_pcie_config_l0s(pcie_dev, pdev, false);
+	return 0;
+}
+
+static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev)
+{
+	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+	msm_pcie_config_l0s(pcie_dev, pdev, true);
+	return 0;
+}
+
 static void msm_pcie_config_l1(struct msm_pcie_dev_t *dev,
 				struct pci_dev *pdev, bool enable)
 {
@@ -5441,6 +5376,22 @@
 	PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val);
 }
 
+static int msm_pcie_config_l1_disable(struct pci_dev *pdev, void *dev)
+{
+	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+	msm_pcie_config_l1(pcie_dev, pdev, false);
+	return 0;
+}
+
+static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev)
+{
+	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+	msm_pcie_config_l1(pcie_dev, pdev, true);
+	return 0;
+}
+
 static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev,
 				struct pci_dev *pdev, bool enable)
 {
@@ -5510,6 +5461,22 @@
 		dev->rc_idx, val2);
 }
 
+static int msm_pcie_config_l1ss_disable(struct pci_dev *pdev, void *dev)
+{
+	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+	msm_pcie_config_l1ss(pcie_dev, pdev, false);
+	return 0;
+}
+
+static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev)
+{
+	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
+
+	msm_pcie_config_l1ss(pcie_dev, pdev, true);
+	return 0;
+}
+
 static void msm_pcie_config_clock_power_management(struct msm_pcie_dev_t *dev,
 				struct pci_dev *pdev)
 {
@@ -6193,10 +6160,8 @@
 		mutex_init(&msm_pcie_dev[i].enumerate_lock);
 		mutex_init(&msm_pcie_dev[i].setup_lock);
 		mutex_init(&msm_pcie_dev[i].recovery_lock);
-		spin_lock_init(&msm_pcie_dev[i].linkdown_lock);
 		spin_lock_init(&msm_pcie_dev[i].wakeup_lock);
-		spin_lock_init(&msm_pcie_dev[i].global_irq_lock);
-		spin_lock_init(&msm_pcie_dev[i].aer_lock);
+		spin_lock_init(&msm_pcie_dev[i].irq_lock);
 		msm_pcie_dev[i].drv_ready = false;
 	}
 	for (i = 0; i < MAX_RC_NUM * MAX_DEVICE_NUM; i++) {
@@ -6261,9 +6226,9 @@
 
 	PCIE_DBG(pcie_dev, "RC%d: entry\n", pcie_dev->rc_idx);
 
-	spin_lock_irqsave(&pcie_dev->aer_lock, irqsave_flags);
+	spin_lock_irqsave(&pcie_dev->irq_lock, irqsave_flags);
 	pcie_dev->suspending = true;
-	spin_unlock_irqrestore(&pcie_dev->aer_lock, irqsave_flags);
+	spin_unlock_irqrestore(&pcie_dev->irq_lock, irqsave_flags);
 
 	if (!pcie_dev->power_on) {
 		PCIE_DBG(pcie_dev,
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 6117d4d..4abd8f1 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -152,6 +152,14 @@
 	  numbers in the kernel log along with the PMIC option status. The PMIC
 	  type is mapped to a QTI chip part number and logged as well.
 
+config GPIO_USB_DETECT
+	tristate "GPIO-based USB VBUS Detection"
+	depends on POWER_SUPPLY
+	help
+	  This driver supports external USB VBUS detection circuitry whose
+	  output is connected to a GPIO. The driver in turn notifies the
+	  USB driver of VBUS presence/disconnection using the power_supply
+	  framework.
 
 config MSM_MHI_DEV
         tristate "Modem Device Interface Driver"
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index bee32c2..d0f0216f 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -7,6 +7,7 @@
 obj-$(CONFIG_SPS) += sps/
 obj-$(CONFIG_QPNP_COINCELL) += qpnp-coincell.o
 obj-$(CONFIG_QPNP_REVID) += qpnp-revid.o
+obj-$(CONFIG_GPIO_USB_DETECT) += gpio-usbdetect.o
 obj-$(CONFIG_EP_PCIE) += ep_pcie/
 obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/
 obj-$(CONFIG_USB_BAM) += usb_bam.o
diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c
new file mode 100644
index 0000000..6730d4a
--- /dev/null
+++ b/drivers/platform/msm/gpio-usbdetect.c
@@ -0,0 +1,266 @@
+/* Copyright (c) 2013-2015, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/extcon.h>
+#include <linux/regulator/consumer.h>
+
+struct gpio_usbdetect {
+	struct platform_device	*pdev;
+	struct regulator	*vin;
+	int			vbus_det_irq;
+	int			id_det_irq;
+	int			gpio;
+	struct extcon_dev	*extcon_dev;
+	int			vbus_state;
+	bool			id_state;
+};
+
+static const unsigned int gpio_usb_extcon_table[] = {
+	EXTCON_USB,
+	EXTCON_USB_HOST,
+	EXTCON_NONE,
+};
+
+static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data)
+{
+	struct gpio_usbdetect *usb = data;
+	union extcon_property_value val;
+
+	usb->vbus_state = gpio_get_value(usb->gpio);
+	if (usb->vbus_state) {
+		dev_dbg(&usb->pdev->dev, "setting vbus notification\n");
+		val.intval = true;
+		extcon_set_property(usb->extcon_dev, EXTCON_USB,
+					EXTCON_PROP_USB_SS, val);
+		extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 1);
+	} else {
+		dev_dbg(&usb->pdev->dev, "setting vbus removed notification\n");
+		extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 0);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t gpio_usbdetect_id_irq(int irq, void *data)
+{
+	struct gpio_usbdetect *usb = data;
+	int ret;
+
+	ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL,
+			&usb->id_state);
+	if (ret < 0) {
+		dev_err(&usb->pdev->dev, "unable to read ID IRQ LINE\n");
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data)
+{
+	struct gpio_usbdetect *usb = data;
+	bool curr_id_state;
+	static int prev_id_state = -EINVAL;
+	union extcon_property_value val;
+
+	curr_id_state = usb->id_state;
+	if (curr_id_state == prev_id_state) {
+		dev_dbg(&usb->pdev->dev, "no change in ID state\n");
+		return IRQ_HANDLED;
+	}
+
+	if (curr_id_state) {
+		dev_dbg(&usb->pdev->dev, "stopping usb host\n");
+		extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 0);
+		enable_irq(usb->vbus_det_irq);
+	} else {
+		dev_dbg(&usb->pdev->dev, "starting usb HOST\n");
+		disable_irq(usb->vbus_det_irq);
+		val.intval = true;
+		extcon_set_property(usb->extcon_dev, EXTCON_USB_HOST,
+					EXTCON_PROP_USB_SS, val);
+		extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1);
+	}
+
+	prev_id_state = curr_id_state;
+	return IRQ_HANDLED;
+}
+
+static const u32 gpio_usb_extcon_exclusive[] = {0x3, 0};
+
+static int gpio_usbdetect_probe(struct platform_device *pdev)
+{
+	struct gpio_usbdetect *usb;
+	int rc;
+
+	usb = devm_kzalloc(&pdev->dev, sizeof(*usb), GFP_KERNEL);
+	if (!usb)
+		return -ENOMEM;
+
+	usb->pdev = pdev;
+
+	usb->extcon_dev = devm_extcon_dev_allocate(&pdev->dev,
+			gpio_usb_extcon_table);
+	if (IS_ERR(usb->extcon_dev)) {
+		dev_err(&pdev->dev, "failed to allocate a extcon device\n");
+		return PTR_ERR(usb->extcon_dev);
+	}
+
+	usb->extcon_dev->mutually_exclusive = gpio_usb_extcon_exclusive;
+	rc = devm_extcon_dev_register(&pdev->dev, usb->extcon_dev);
+	if (rc) {
+		dev_err(&pdev->dev, "failed to register extcon device\n");
+		return rc;
+	}
+
+	rc = extcon_set_property_capability(usb->extcon_dev,
+			EXTCON_USB, EXTCON_PROP_USB_SS);
+	rc |= extcon_set_property_capability(usb->extcon_dev,
+			EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
+	if (rc) {
+		dev_err(&pdev->dev, "failed to register extcon props rc=%d\n",
+						rc);
+		return rc;
+	}
+
+	if (of_get_property(pdev->dev.of_node, "vin-supply", NULL)) {
+		usb->vin = devm_regulator_get(&pdev->dev, "vin");
+		if (IS_ERR(usb->vin)) {
+			dev_err(&pdev->dev, "Failed to get VIN regulator: %ld\n",
+				PTR_ERR(usb->vin));
+			return PTR_ERR(usb->vin);
+		}
+	}
+
+	if (usb->vin) {
+		rc = regulator_enable(usb->vin);
+		if (rc) {
+			dev_err(&pdev->dev, "Failed to enable VIN regulator: %d\n",
+				rc);
+			return rc;
+		}
+	}
+
+	usb->gpio = of_get_named_gpio(pdev->dev.of_node,
+				"qcom,vbus-det-gpio", 0);
+	if (usb->gpio < 0) {
+		dev_err(&pdev->dev, "Failed to get gpio: %d\n", usb->gpio);
+		rc = usb->gpio;
+		goto error;
+	}
+
+	rc = gpio_request(usb->gpio, "vbus-det-gpio");
+	if (rc < 0) {
+		dev_err(&pdev->dev, "Failed to request gpio: %d\n", rc);
+		goto error;
+	}
+
+	usb->vbus_det_irq = gpio_to_irq(usb->gpio);
+	if (usb->vbus_det_irq < 0) {
+		dev_err(&pdev->dev, "get vbus_det_irq failed\n");
+		rc = usb->vbus_det_irq;
+		goto error;
+	}
+
+	rc = devm_request_threaded_irq(&pdev->dev, usb->vbus_det_irq,
+				NULL, gpio_usbdetect_vbus_irq,
+			      IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+			      IRQF_ONESHOT, "vbus_det_irq", usb);
+	if (rc) {
+		dev_err(&pdev->dev, "request for vbus_det_irq failed: %d\n",
+			rc);
+		goto error;
+	}
+
+	usb->id_det_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
+	if (usb->id_det_irq < 0) {
+		dev_err(&pdev->dev, "get id_det_irq failed\n");
+		rc = usb->id_det_irq;
+		goto error;
+	}
+
+	rc = devm_request_threaded_irq(&pdev->dev, usb->id_det_irq,
+				gpio_usbdetect_id_irq,
+				gpio_usbdetect_id_irq_thread,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
+				IRQF_ONESHOT, "id_det_irq", usb);
+	if (rc) {
+		dev_err(&pdev->dev, "request for id_det_irq failed: %d\n", rc);
+		goto error;
+	}
+
+	enable_irq_wake(usb->vbus_det_irq);
+	enable_irq_wake(usb->id_det_irq);
+	dev_set_drvdata(&pdev->dev, usb);
+
+	if (usb->id_det_irq) {
+		gpio_usbdetect_id_irq(usb->id_det_irq, usb);
+		if (!usb->id_state) {
+			gpio_usbdetect_id_irq_thread(usb->id_det_irq, usb);
+			return 0;
+		}
+	}
+
+	/* Read and report initial VBUS state */
+	gpio_usbdetect_vbus_irq(usb->vbus_det_irq, usb);
+
+	return 0;
+
+error:
+	if (usb->vin)
+		regulator_disable(usb->vin);
+	return rc;
+}
+
+static int gpio_usbdetect_remove(struct platform_device *pdev)
+{
+	struct gpio_usbdetect *usb = dev_get_drvdata(&pdev->dev);
+
+	disable_irq_wake(usb->vbus_det_irq);
+	disable_irq(usb->vbus_det_irq);
+	disable_irq_wake(usb->id_det_irq);
+	disable_irq(usb->id_det_irq);
+	if (usb->vin)
+		regulator_disable(usb->vin);
+
+	return 0;
+}
+
+static const struct of_device_id of_match_table[] = {
+	{ .compatible = "qcom,gpio-usbdetect", },
+	{}
+};
+
+static struct platform_driver gpio_usbdetect_driver = {
+	.driver		= {
+		.name	= "qcom,gpio-usbdetect",
+		.of_match_table = of_match_table,
+	},
+	.probe		= gpio_usbdetect_probe,
+	.remove		= gpio_usbdetect_remove,
+};
+
+module_driver(gpio_usbdetect_driver, platform_driver_register,
+		platform_driver_unregister);
+
+MODULE_DESCRIPTION("GPIO USB VBUS Detection driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index d274490..1335c45 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-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
@@ -741,10 +741,6 @@
 		&ipa3_usb_ctx->ttype_ctx[ttype];
 	int result;
 
-	/* create PM resources for the first tethering protocol only */
-	if (ipa3_usb_ctx->num_init_prot > 0)
-		return 0;
-
 	memset(&ttype_ctx->pm_ctx.reg_params, 0,
 		sizeof(ttype_ctx->pm_ctx.reg_params));
 	ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
@@ -1024,11 +1020,11 @@
 	return 0;
 
 teth_prot_init_fail:
-	if ((IPA3_USB_IS_TTYPE_DPL(ttype))
-		|| (ipa3_usb_ctx->num_init_prot == 0)) {
-		if (ipa_pm_is_used()) {
-			ipa3_usb_deregister_pm(ttype);
-		} else {
+	if (ipa_pm_is_used()) {
+		ipa3_usb_deregister_pm(ttype);
+	} else {
+		if ((IPA3_USB_IS_TTYPE_DPL(ttype))
+			|| (ipa3_usb_ctx->num_init_prot == 0)) {
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
 				false;
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
@@ -1332,6 +1328,10 @@
 	chan_params.chan_scratch.xdci.outstanding_threshold =
 		((params->teth_prot == IPA_USB_MBIM) ? 1 : 2) *
 		chan_params.chan_params.re_size;
+
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+		chan_params.chan_scratch.xdci.outstanding_threshold = 0;
+
 	/* max_outstanding_tre is set in ipa3_request_gsi_channel() */
 	result = ipa3_request_gsi_channel(&chan_params, out_params);
 	if (result) {
@@ -2462,13 +2462,14 @@
 		goto bad_params;
 	}
 
-	if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
-		(ipa3_usb_ctx->num_init_prot == 0)) {
-		if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
-			IPA_USB_ERR("failed to change state to invalid\n");
-		if (ipa_pm_is_used()) {
-			ipa3_usb_deregister_pm(ttype);
-		} else {
+	if (ipa_pm_is_used()) {
+		ipa3_usb_deregister_pm(ttype);
+	} else {
+		if (IPA3_USB_IS_TTYPE_DPL(ttype) ||
+			(ipa3_usb_ctx->num_init_prot == 0)) {
+			if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
+				IPA_USB_ERR(
+					"failed to change state to invalid\n");
 			ipa_rm_delete_resource(
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
 			ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 8872c24..901b51b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -714,6 +714,10 @@
 		sizeof(union __packed gsi_channel_scratch));
 	ep->chan_scratch.xdci.max_outstanding_tre =
 		params->chan_params.re_size * gsi_ep_cfg_ptr->ipa_if_tlv;
+
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
+		ep->chan_scratch.xdci.max_outstanding_tre = 0;
+
 	gsi_res = gsi_write_channel_scratch(ep->gsi_chan_hdl,
 		params->chan_scratch);
 	if (gsi_res != GSI_STATUS_SUCCESS) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 3aaae8d..f105c36 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -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
@@ -236,6 +236,8 @@
 		return;
 	}
 	sys->len_pending_xfer = 0;
+	/* make sure TAG process is sent before clocks are gated */
+	ipa3_ctx->tag_process_before_gating = true;
 
 }
 
@@ -419,6 +421,9 @@
 		hrtimer_start(&sys->db_timer, time, HRTIMER_MODE_REL);
 	}
 
+	/* make sure TAG process is sent before clocks are gated */
+	ipa3_ctx->tag_process_before_gating = true;
+
 	return 0;
 
 failure_dma_map:
@@ -3679,6 +3684,12 @@
 	ch_scratch.gpi.max_outstanding_tre = gsi_ep_info->ipa_if_tlv *
 		GSI_CHAN_RE_SIZE_16B;
 	ch_scratch.gpi.outstanding_threshold = 2 * GSI_CHAN_RE_SIZE_16B;
+
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		ch_scratch.gpi.max_outstanding_tre = 0;
+		ch_scratch.gpi.outstanding_threshold = 0;
+	}
+
 	result = gsi_write_channel_scratch(ep->gsi_chan_hdl, ch_scratch);
 	if (result != GSI_STATUS_SUCCESS) {
 		IPAERR("failed to write scratch %d\n", result);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index cb970ba..82cd8187 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.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
@@ -302,6 +302,10 @@
 		ep_cfg->ipa_if_tlv * ch_props.re_size;
 	ch_scratch.mhi.outstanding_threshold =
 		min(ep_cfg->ipa_if_tlv / 2, 8) * ch_props.re_size;
+	if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
+		ch_scratch.mhi.max_outstanding_tre = 0;
+		ch_scratch.mhi.outstanding_threshold = 0;
+	}
 	ch_scratch.mhi.oob_mod_threshold = 4;
 	if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT ||
 		params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
index bafc3ca..80a39b5 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.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
@@ -240,7 +240,7 @@
 	struct ipa_pm_client *client;
 
 	/* Create a basic array to hold throughputs*/
-	for (i = 0, n = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+	for (i = 1, n = 0; i < IPA_PM_MAX_CLIENTS; i++) {
 		client = ipa_pm_ctx->clients[i];
 		if (client != NULL && IPA_PM_STATE_ACTIVE(client->state)) {
 			/* default case */
@@ -414,7 +414,6 @@
 	complete_all(&client->complete);
 
 	if (dec_clk) {
-		ipa_set_tag_process_before_gating(true);
 		if (!client->skip_clk_vote)
 			IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
 
@@ -465,7 +464,6 @@
 		client->state = IPA_PM_DEACTIVATED;
 		IPA_PM_DBG_STATE(client->hdl, client->name, client->state);
 		spin_unlock_irqrestore(&client->state_lock, flags);
-		ipa_set_tag_process_before_gating(true);
 		if (!client->skip_clk_vote)
 			IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
 
@@ -489,7 +487,8 @@
 
 	n = -ENOBUFS;
 
-	for (i = IPA_PM_MAX_CLIENTS - 1; i >= 0; i--) {
+	/* 0 is not a valid handle */
+	for (i = IPA_PM_MAX_CLIENTS - 1; i >= 1; i--) {
 		if (ipa_pm_ctx->clients[i] == NULL) {
 			n = i;
 			continue;
@@ -1043,7 +1042,7 @@
 		return -EINVAL;
 	}
 
-	for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+	for (i = 1; i < IPA_PM_MAX_CLIENTS; i++) {
 		client = ipa_pm_ctx->clients[i];
 
 		if (client == NULL)
@@ -1073,7 +1072,6 @@
 			IPA_PM_DBG_STATE(client->hdl, client->name,
 				client->state);
 			spin_unlock_irqrestore(&client->state_lock, flags);
-			ipa_set_tag_process_before_gating(true);
 			if (!client->skip_clk_vote)
 				IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
 			deactivate_client(client->hdl);
@@ -1126,7 +1124,6 @@
 	spin_unlock_irqrestore(&client->state_lock, flags);
 
 	/* else case (Deactivates all Activated cases)*/
-	ipa_set_tag_process_before_gating(true);
 	if (!client->skip_clk_vote)
 		IPA_ACTIVE_CLIENTS_DEC_SPECIAL(client->name);
 
@@ -1280,7 +1277,7 @@
 	cnt += result;
 
 
-	for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+	for (i = 1; i < IPA_PM_MAX_CLIENTS; i++) {
 		client = ipa_pm_ctx->clients[i];
 
 		if (client == NULL)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
index b2f203a..205e7a5 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
@@ -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,7 +16,7 @@
 #include <linux/msm_ipa.h>
 
 /* internal to ipa */
-#define IPA_PM_MAX_CLIENTS 10
+#define IPA_PM_MAX_CLIENTS 11 /* actual max is value -1 since we start from 1*/
 #define IPA_PM_MAX_EX_CL 64
 #define IPA_PM_THRESHOLD_MAX 5
 #define IPA_PM_EXCEPTION_MAX 2
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index de3711e..1782fdc 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3993,6 +3993,7 @@
 	}
 	kfree(tag_desc);
 	tag_desc = NULL;
+	ipa3_ctx->tag_process_before_gating = false;
 
 	IPADBG("waiting for TAG response\n");
 	res = wait_for_completion_timeout(&comp->comp, timeout);
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
index 246f32e..929242a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.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
@@ -253,7 +253,7 @@
 			(struct wan_ioctl_set_data_quota *)param);
 		if (rc != 0) {
 			IPAWANERR("WAN_IOC_SET_DATA_QUOTA failed\n");
-			if (retval == -ENODEV)
+			if (rc == -ENODEV)
 				retval = -ENODEV;
 			else
 				retval = -EFAULT;
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index 0be35b3..9fc5a4a 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -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
@@ -50,6 +50,8 @@
 #define ATTW_MAX_MS			32
 
 #define LCDB_BST_OUTPUT_VOLTAGE_REG	0x41
+#define PM660_BST_OUTPUT_VOLTAGE_MASK	GENMASK(4, 0)
+#define BST_OUTPUT_VOLTAGE_MASK		GENMASK(5, 0)
 
 #define LCDB_MODULE_RDY_REG		0x45
 #define MODULE_RDY_BIT			BIT(7)
@@ -71,7 +73,8 @@
 
 #define LCDB_PS_CTL_REG			0x50
 #define EN_PS_BIT			BIT(7)
-#define PS_THRESHOLD_MASK		GENMASK(1, 0)
+#define PM660_PS_THRESH_MASK		GENMASK(1, 0)
+#define PS_THRESH_MASK			GENMASK(2, 0)
 #define MIN_BST_PS_MA			50
 #define MAX_BST_PS_MA			80
 
@@ -83,6 +86,20 @@
 #define LCDB_BST_VREG_OK_CTL_REG	0x55
 #define BST_VREG_OK_DEB_MASK		GENMASK(1, 0)
 
+#define LCDB_BST_SS_CTL_REG		0x5B
+#define BST_SS_TIME_MASK		GENMASK(1, 0)
+#define BST_PRECHG_SHORT_ALARM_SHIFT	2
+#define BST_PRECHARGE_DONE_DEB_BIT	BIT(4)
+#define BST_SS_TIME_OVERRIDE_SHIFT	5
+
+#define BST_SS_TIME_OVERRIDE_0MS	0
+#define BST_SS_TIME_OVERRIDE_0P5_MS	1
+#define BST_SS_TIME_OVERRIDE_1MS	2
+#define BST_SS_TIME_OVERRIDE_2MS	3
+
+#define EN_BST_PRECHG_SHORT_ALARM	0
+#define DIS_BST_PRECHG_SHORT_ALARM	1
+
 #define LCDB_SOFT_START_CTL_REG		0x5F
 
 #define LCDB_MISC_CTL_REG		0x60
@@ -147,7 +164,8 @@
 #define MIN_SOFT_START_US		0
 #define MAX_SOFT_START_US		2000
 
-#define BST_HEADROOM_DEFAULT_MV		200
+#define PM660_BST_HEADROOM_DEFAULT_MV	200
+#define BST_HEADROOM_DEFAULT_MV		150
 
 struct ldo_regulator {
 	struct regulator_desc		rdesc;
@@ -222,6 +240,7 @@
 	u16	address;
 	u8	value;
 	bool	sec_access;
+	bool	valid;
 };
 
 enum lcdb_module {
@@ -262,6 +281,8 @@
 	LCDB_LDO_SOFT_START_CTL,
 	LCDB_NCP_PD_CTL,
 	LCDB_NCP_SOFT_START_CTL,
+	LCDB_BST_SS_CTL,
+	LCDB_LDO_VREG_OK_CTL,
 	LCDB_SETTING_MAX,
 };
 
@@ -286,10 +307,11 @@
 	810,
 };
 
-#define SETTING(_id, _sec_access)		\
+#define SETTING(_id, _sec_access, _valid)	\
 	[_id] = {				\
 		.address = _id##_REG,		\
 		.sec_access = _sec_access,	\
+		.valid = _valid			\
 	}					\
 
 static bool is_between(int value, int min, int max)
@@ -334,12 +356,16 @@
 {
 	int rc;
 	u8 val = SECURE_UNLOCK_VALUE;
+	u8 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 
 	mutex_lock(&lcdb->read_write_mutex);
-	rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG, val);
-	if (rc < 0) {
-		pr_err("Failed to unlock register rc=%d\n", rc);
-		goto fail_write;
+	if (pmic_subtype == PM660L_SUBTYPE) {
+		rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG,
+				  val);
+		if (rc < 0) {
+			pr_err("Failed to unlock register rc=%d\n", rc);
+			goto fail_write;
+		}
 	}
 	rc = regmap_write(lcdb->regmap, addr, value);
 	if (rc < 0)
@@ -397,61 +423,174 @@
 	return rc;
 }
 
+static struct settings lcdb_settings_pm660l[] = {
+	SETTING(LCDB_BST_PD_CTL, false, true),
+	SETTING(LCDB_RDSON_MGMNT, false, true),
+	SETTING(LCDB_MISC_CTL, false, true),
+	SETTING(LCDB_SOFT_START_CTL, false, true),
+	SETTING(LCDB_PFM_CTL, false, true),
+	SETTING(LCDB_PWRUP_PWRDN_CTL, true, true),
+	SETTING(LCDB_LDO_PD_CTL, false, true),
+	SETTING(LCDB_LDO_SOFT_START_CTL, false, true),
+	SETTING(LCDB_NCP_PD_CTL, false, true),
+	SETTING(LCDB_NCP_SOFT_START_CTL, false, true),
+	SETTING(LCDB_BST_SS_CTL, false, false),
+	SETTING(LCDB_LDO_VREG_OK_CTL, false, false),
+};
+
+/* For PMICs like pmi632/pm855L */
 static struct settings lcdb_settings[] = {
-	SETTING(LCDB_BST_PD_CTL, false),
-	SETTING(LCDB_RDSON_MGMNT, false),
-	SETTING(LCDB_MISC_CTL, false),
-	SETTING(LCDB_SOFT_START_CTL, false),
-	SETTING(LCDB_PFM_CTL, false),
-	SETTING(LCDB_PWRUP_PWRDN_CTL, true),
-	SETTING(LCDB_LDO_PD_CTL, false),
-	SETTING(LCDB_LDO_SOFT_START_CTL, false),
-	SETTING(LCDB_NCP_PD_CTL, false),
-	SETTING(LCDB_NCP_SOFT_START_CTL, false),
+	SETTING(LCDB_BST_PD_CTL, false, true),
+	SETTING(LCDB_RDSON_MGMNT, false, false),
+	SETTING(LCDB_MISC_CTL, false, false),
+	SETTING(LCDB_SOFT_START_CTL, false, false),
+	SETTING(LCDB_PFM_CTL, false, false),
+	SETTING(LCDB_PWRUP_PWRDN_CTL, false, true),
+	SETTING(LCDB_LDO_PD_CTL, false, true),
+	SETTING(LCDB_LDO_SOFT_START_CTL, false, true),
+	SETTING(LCDB_NCP_PD_CTL, false, true),
+	SETTING(LCDB_NCP_SOFT_START_CTL, false, true),
+	SETTING(LCDB_BST_SS_CTL, false, true),
+	SETTING(LCDB_LDO_VREG_OK_CTL, false, true),
 };
 
 static int qpnp_lcdb_save_settings(struct qpnp_lcdb *lcdb)
 {
-	int i, rc = 0;
+	int i, size, rc = 0;
+	struct settings *setting;
+	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 
-	for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) {
-		rc = qpnp_lcdb_read(lcdb, lcdb->base +
-				lcdb_settings[i].address,
-				&lcdb_settings[i].value, 1);
-		if (rc < 0) {
-			pr_err("Failed to read lcdb register address=%x\n",
-						lcdb_settings[i].address);
-			return rc;
+	if (pmic_subtype == PM660L_SUBTYPE) {
+		setting = lcdb_settings_pm660l;
+		size = ARRAY_SIZE(lcdb_settings_pm660l);
+	} else {
+		setting = lcdb_settings;
+		size = ARRAY_SIZE(lcdb_settings);
+	}
+
+	for (i = 0; i < size; i++) {
+		if (setting[i].valid) {
+			rc = qpnp_lcdb_read(lcdb, lcdb->base +
+					    setting[i].address,
+					    &setting[i].value, 1);
+			if (rc < 0) {
+				pr_err("Failed to read lcdb register address=%x\n",
+					setting[i].address);
+				return rc;
+			}
 		}
 	}
 
-	return rc;
+	return 0;
 }
 
 static int qpnp_lcdb_restore_settings(struct qpnp_lcdb *lcdb)
 {
-	int i, rc = 0;
+	int i, size, rc = 0;
+	struct settings *setting;
+	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 
-	for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) {
-		if (lcdb_settings[i].sec_access)
-			rc = qpnp_lcdb_secure_write(lcdb, lcdb->base +
-					lcdb_settings[i].address,
-					lcdb_settings[i].value);
-		else
-			rc = qpnp_lcdb_write(lcdb, lcdb->base +
-					lcdb_settings[i].address,
-					&lcdb_settings[i].value, 1);
-		if (rc < 0) {
-			pr_err("Failed to write register address=%x\n",
-						lcdb_settings[i].address);
-			return rc;
+	if (pmic_subtype == PM660L_SUBTYPE) {
+		setting = lcdb_settings_pm660l;
+		size = ARRAY_SIZE(lcdb_settings_pm660l);
+	} else {
+		setting = lcdb_settings;
+		size = ARRAY_SIZE(lcdb_settings);
+	}
+
+	for (i = 0; i < size; i++) {
+		if (setting[i].valid) {
+			if (setting[i].sec_access)
+				rc = qpnp_lcdb_secure_write(lcdb, lcdb->base +
+							    setting[i].address,
+							    setting[i].value);
+			else
+				rc = qpnp_lcdb_write(lcdb, lcdb->base +
+						     setting[i].address,
+						     &setting[i].value, 1);
+			if (rc < 0) {
+				pr_err("Failed to write register address=%x\n",
+					     setting[i].address);
+				return rc;
+			}
 		}
 	}
 
+	return 0;
+}
+
+static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb)
+{
+	int rc;
+	u8 val;
+
+	if (!lcdb->settings_saved) {
+		rc = qpnp_lcdb_save_settings(lcdb);
+		if (rc < 0) {
+			pr_err("Failed to save LCDB settings rc=%d\n", rc);
+			return rc;
+		}
+		lcdb->settings_saved = true;
+	}
+
+	val = HWEN_RDY_BIT;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+			     &val, 1);
+	if (rc < 0) {
+		pr_err("Failed to hw_enable lcdb rc= %d\n", rc);
+		return rc;
+	}
+
+	val = (BST_SS_TIME_OVERRIDE_1MS << BST_SS_TIME_OVERRIDE_SHIFT) |
+	      (DIS_BST_PRECHG_SHORT_ALARM << BST_PRECHG_SHORT_ALARM_SHIFT);
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_SS_CTL_REG, &val, 1);
+	if (rc < 0)
+		return rc;
+
+	val = 0;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_SOFT_START_CTL_REG,
+			     &val, 1);
+	if (rc < 0)
+		return rc;
+
+	val = 0;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_SOFT_START_CTL_REG,
+			     &val, 1);
+	if (rc < 0)
+		return rc;
+
+	val = BOOST_DIS_PULLDOWN_BIT | BOOST_PD_STRENGTH_BIT;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_PD_CTL_REG,
+			     &val, 1);
+	if (rc < 0)
+		return rc;
+
+	val = LDO_DIS_PULLDOWN_BIT | LDO_PD_STRENGTH_BIT;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_PD_CTL_REG,
+							&val, 1);
+	if (rc < 0)
+		return rc;
+
+	val = NCP_DIS_PULLDOWN_BIT | NCP_PD_STRENGTH_BIT;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_PD_CTL_REG,
+			     &val, 1);
+	if (rc < 0)
+		return rc;
+
+	val = 0;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_PWRUP_PWRDN_CTL_REG,
+			     &val, 1);
+	if (rc < 0)
+		return rc;
+
+	val = 0;
+	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_VREG_OK_CTL_REG,
+			     &val, 1);
+
 	return rc;
 }
 
-static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb)
+static int qpnp_lcdb_ttw_enter_pm660l(struct qpnp_lcdb *lcdb)
 {
 	int rc;
 	u8 val;
@@ -491,7 +630,7 @@
 
 	val = 0;
 	rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_SOFT_START_CTL_REG,
-							&val, 1);
+						&val, 1);
 	if (rc < 0) {
 		pr_err("Failed to set LCDB_SOFT_START rc=%d\n", rc);
 		return rc;
@@ -715,12 +854,17 @@
 {
 	int rc = 0;
 	u8 val;
+	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 
 	if (!lcdb->lcdb_enabled)
 		return 0;
 
 	if (lcdb->ttw_enable) {
-		rc = qpnp_lcdb_ttw_enter(lcdb);
+		if (pmic_subtype == PM660L_SUBTYPE)
+			rc = qpnp_lcdb_ttw_enter_pm660l(lcdb);
+		else
+			rc = qpnp_lcdb_ttw_enter(lcdb);
+
 		if (rc < 0) {
 			pr_err("Failed to enable TTW mode rc=%d\n", rc);
 			return rc;
@@ -859,8 +1003,9 @@
 					int voltage_mv, u8 type)
 {
 	int rc = 0;
-	u8 val = 0;
+	u8 val, mask = 0;
 	int bst_voltage_mv;
+	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 	struct ldo_regulator *ldo = &lcdb->ldo;
 	struct ncp_regulator *ncp = &lcdb->ncp;
 	struct bst_params *bst = &lcdb->bst;
@@ -877,10 +1022,11 @@
 	if (bst_voltage_mv != bst->voltage_mv) {
 		val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV,
 						VOLTAGE_STEP_50_MV);
-
+		mask = (pmic_subtype == PM660L_SUBTYPE) ?
+			PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
 		rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
 					LCDB_BST_OUTPUT_VOLTAGE_REG,
-					SET_OUTPUT_VOLTAGE_MASK, val);
+					mask, val);
 		if (rc < 0) {
 			pr_err("Failed to set boost voltage %d mv rc=%d\n",
 				bst_voltage_mv, rc);
@@ -898,7 +1044,8 @@
 					int *voltage_mv)
 {
 	int rc;
-	u8 val = 0;
+	u8 val, mask = 0;
+	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 
 	rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG,
 						&val, 1);
@@ -907,7 +1054,9 @@
 		return rc;
 	}
 
-	val &= SET_OUTPUT_VOLTAGE_MASK;
+	mask = (pmic_subtype == PM660L_SUBTYPE) ?
+		PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK;
+	val &= mask;
 	*voltage_mv = (val * VOLTAGE_STEP_50_MV) + MIN_BST_VOLTAGE_MV;
 
 	return 0;
@@ -1369,6 +1518,8 @@
 {
 	int rc = 0;
 	struct device_node *node = lcdb->bst.node;
+	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
+	u16 default_headroom_mv;
 
 	/* Boost PD  configuration */
 	lcdb->bst.pd = -EINVAL;
@@ -1402,11 +1553,14 @@
 		return -EINVAL;
 	}
 
+	default_headroom_mv = (pmic_subtype == PM660L_SUBTYPE) ?
+			       PM660_BST_HEADROOM_DEFAULT_MV :
+			       BST_HEADROOM_DEFAULT_MV;
 	/* Boost head room configuration */
 	of_property_read_u16(node, "qcom,bst-headroom-mv",
 					&lcdb->bst.headroom_mv);
-	if (lcdb->bst.headroom_mv < BST_HEADROOM_DEFAULT_MV)
-		lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
+	if (lcdb->bst.headroom_mv < default_headroom_mv)
+		lcdb->bst.headroom_mv = default_headroom_mv;
 
 	return 0;
 }
@@ -1624,7 +1778,8 @@
 static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb)
 {
 	int rc = 0;
-	u8 val = 0;
+	u8 val, mask = 0;
+	u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype;
 
 	/* configure parameters only if LCDB is disabled */
 	if (!is_lcdb_enabled(lcdb)) {
@@ -1677,13 +1832,13 @@
 		}
 
 		if (lcdb->bst.ps_threshold != -EINVAL) {
+			mask = (pmic_subtype == PM660L_SUBTYPE) ?
+					PM660_PS_THRESH_MASK : PS_THRESH_MASK;
 			val = (lcdb->bst.ps_threshold - MIN_BST_PS_MA) / 10;
-			val = (lcdb->bst.ps_threshold & PS_THRESHOLD_MASK) |
-								EN_PS_BIT;
+			val = (lcdb->bst.ps_threshold & mask) | EN_PS_BIT;
 			rc = qpnp_lcdb_masked_write(lcdb, lcdb->base +
 						LCDB_PS_CTL_REG,
-						PS_THRESHOLD_MASK | EN_PS_BIT,
-						val);
+						mask | EN_PS_BIT, val);
 			if (rc < 0) {
 				pr_err("Failed to configure BST PS threshold rc=%d",
 								rc);
@@ -1706,16 +1861,24 @@
 	}
 	lcdb->bst.vreg_ok_dbc_us = dbc_us[val & VREG_OK_DEB_MASK];
 
-	rc = qpnp_lcdb_read(lcdb, lcdb->base +
-			LCDB_SOFT_START_CTL_REG, &val, 1);
-	if (rc < 0) {
-		pr_err("Failed to read ncp_soft_start_ctl rc=%d\n", rc);
-		return rc;
+	if (pmic_subtype == PM660L_SUBTYPE) {
+		rc = qpnp_lcdb_read(lcdb, lcdb->base +
+				    LCDB_SOFT_START_CTL_REG, &val, 1);
+		if (rc < 0) {
+			pr_err("Failed to read lcdb_soft_start_ctl rc=%d\n",
+									rc);
+			return rc;
+		}
+		lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200;
+	} else {
+		rc = qpnp_lcdb_read(lcdb, lcdb->base +
+				    LCDB_BST_SS_CTL_REG, &val, 1);
+		if (rc < 0) {
+			pr_err("Failed to read bst_soft_start_ctl rc=%d\n", rc);
+			return rc;
+		}
+		lcdb->bst.soft_start_us = soft_start_us[val & SOFT_START_MASK];
 	}
-	lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200	+ 200;
-
-	if (!lcdb->bst.headroom_mv)
-		lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV;
 
 	return 0;
 }
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index f34b714..87d1aac 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -75,6 +75,7 @@
        obj-y += subsystem_notif.o
        obj-y += subsystem_restart.o
        obj-y += ramdump.o
+       obj-y += microdump_collector.o
 endif
 obj-$(CONFIG_MSM_JTAGV8) += jtagv8.o jtagv8-etm.o
 obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c
index dd436da..614b53a 100644
--- a/drivers/soc/qcom/glink_ssr.c
+++ b/drivers/soc/qcom/glink_ssr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -596,25 +596,6 @@
 		strlcpy(do_cleanup_data->name, ss_info->edge,
 				do_cleanup_data->name_len + 1);
 
-		ret = glink_queue_rx_intent(handle, do_cleanup_data,
-				sizeof(struct cleanup_done_msg));
-		if (ret) {
-			GLINK_SSR_ERR(
-				"%s %s: %s, ret[%d], resp. remaining[%d]\n",
-				"<SSR>", __func__,
-				"queue_rx_intent failed", ret,
-				atomic_read(&responses_remaining));
-			kfree(do_cleanup_data);
-
-			if (!strcmp(ss_leaf_entry->ssr_name, "rpm"))
-				panic("%s: Could not queue intent for RPM!\n",
-						__func__);
-			atomic_dec(&responses_remaining);
-			kref_put(&ss_leaf_entry->cb_data->cb_kref,
-							cb_data_release);
-			continue;
-		}
-
 		if (strcmp(ss_leaf_entry->ssr_name, "rpm"))
 			ret = glink_tx(handle, do_cleanup_data,
 					do_cleanup_data,
@@ -640,6 +621,24 @@
 							cb_data_release);
 			continue;
 		}
+		ret = glink_queue_rx_intent(handle, do_cleanup_data,
+				sizeof(struct cleanup_done_msg));
+		if (ret) {
+			GLINK_SSR_ERR(
+				"%s %s: %s, ret[%d], resp. remaining[%d]\n",
+				"<SSR>", __func__,
+				"queue_rx_intent failed", ret,
+				atomic_read(&responses_remaining));
+			kfree(do_cleanup_data);
+
+			if (!strcmp(ss_leaf_entry->ssr_name, "rpm"))
+				panic("%s: Could not queue intent for RPM!\n",
+						__func__);
+			atomic_dec(&responses_remaining);
+			kref_put(&ss_leaf_entry->cb_data->cb_kref,
+							cb_data_release);
+			continue;
+		}
 		sequence_number++;
 		kref_put(&ss_leaf_entry->cb_data->cb_kref, cb_data_release);
 	}
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 95004a1..a28644d 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -1111,6 +1111,9 @@
 	if (test_bit(HW_ALWAYS_ON, &quirks))
 		return 0;
 
+	if (test_bit(ICNSS_FW_DOWN, &priv->state))
+		return 0;
+
 	icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state);
 
 	spin_lock(&priv->on_off_lock);
diff --git a/drivers/soc/qcom/microdump_collector.c b/drivers/soc/qcom/microdump_collector.c
new file mode 100644
index 0000000..47f3336
--- /dev/null
+++ b/drivers/soc/qcom/microdump_collector.c
@@ -0,0 +1,159 @@
+/* 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/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/ramdump.h>
+#include <soc/qcom/smem.h>
+
+/*
+ * This program collects the data from SMEM regions whenever the modem crashes
+ * and stores it in /dev/ramdump_microdump_modem so as to expose it to
+ * user space.
+ */
+
+struct microdump_data {
+	struct ramdump_device *microdump_dev;
+	void *microdump_modem_notify_handler;
+	struct notifier_block microdump_modem_ssr_nb;
+};
+
+static struct microdump_data *drv;
+
+static int microdump_modem_notifier_nb(struct notifier_block *nb,
+		unsigned long code, void *data)
+{
+	int ret = 0;
+	unsigned int size_reason = 0, size_data = 0;
+	char *crash_reason = NULL;
+	char *crash_data = NULL;
+	unsigned int smem_id = 611;
+	struct ramdump_segment segment[2];
+
+	if (code == SUBSYS_RAMDUMP_NOTIFICATION) {
+
+		memset(segment, 0, sizeof(segment));
+
+		crash_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size_reason
+				, 0, SMEM_ANY_HOST_FLAG);
+		if (IS_ERR_OR_NULL(crash_reason)) {
+			pr_err("%s: Error in getting SMEM_reason pointer\n",
+				__func__);
+			return -ENODEV;
+		}
+
+		segment[0].v_address = crash_reason;
+		segment[0].size = size_reason;
+
+		crash_data = smem_get_entry(smem_id, &size_data, SMEM_MODEM, 0);
+		if (IS_ERR_OR_NULL(crash_data)) {
+			pr_err("%s: Error in getting SMEM_data pointer\n",
+				__func__);
+			return -ENODEV;
+		}
+
+		segment[1].v_address = crash_data;
+		segment[1].size = size_data;
+
+		ret = do_ramdump(drv->microdump_dev, segment, 2);
+		if (ret)
+			pr_err("%s: do_ramdump() failed\n", __func__);
+	}
+
+	return ret;
+}
+
+static int microdump_modem_ssr_register_notifier(struct microdump_data *drv)
+{
+	int ret = 0;
+
+	drv->microdump_modem_ssr_nb.notifier_call = microdump_modem_notifier_nb;
+
+	drv->microdump_modem_notify_handler =
+		subsys_notif_register_notifier("modem",
+			&drv->microdump_modem_ssr_nb);
+
+	if (IS_ERR(drv->microdump_modem_notify_handler)) {
+		pr_err("Modem register notifier failed: %ld\n",
+			PTR_ERR(drv->microdump_modem_notify_handler));
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void microdump_modem_ssr_unregister_notifier(struct microdump_data *drv)
+{
+	subsys_notif_unregister_notifier(drv->microdump_modem_notify_handler,
+					&drv->microdump_modem_ssr_nb);
+	drv->microdump_modem_notify_handler = NULL;
+}
+
+/*
+ * microdump_init() - Registers kernel module for microdump collector
+ *
+ * Creates device file /dev/ramdump_microdump_modem and registers handler for
+ * modem SSR events.
+ *
+ * Returns 0 on success and negative error code in case of errors
+ */
+static int __init microdump_init(void)
+{
+	int ret = -ENOMEM;
+
+	drv = kzalloc(sizeof(struct microdump_data), GFP_KERNEL);
+	if (!drv)
+		goto out;
+
+	drv->microdump_dev = create_ramdump_device("microdump_modem", NULL);
+	if (!drv->microdump_dev) {
+		pr_err("%s: Unable to create a microdump_modem ramdump device\n"
+			, __func__);
+		ret = -ENODEV;
+		goto out_kfree;
+	}
+
+	ret = microdump_modem_ssr_register_notifier(drv);
+	if (ret) {
+		destroy_ramdump_device(drv->microdump_dev);
+		goto out_kfree;
+	}
+	return ret;
+out_kfree:
+	pr_err("%s: Failed to register microdump collector\n", __func__);
+	kfree(drv);
+	drv = NULL;
+out:
+	return ret;
+}
+
+static void __exit microdump_exit(void)
+{
+	if (!drv)
+		return;
+
+	if (!IS_ERR(drv->microdump_modem_notify_handler))
+		microdump_modem_ssr_unregister_notifier(drv);
+
+	if (drv->microdump_dev)
+		destroy_ramdump_device(drv->microdump_dev);
+
+	kfree(drv);
+}
+
+module_init(microdump_init);
+module_exit(microdump_exit);
+
+MODULE_DESCRIPTION("Microdump Collector");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 5a110bb..c00749c 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -550,9 +550,9 @@
 	struct tcs_cmd *cmdlist_sleep = NULL;
 	struct rpmh_client *cur_mbox = NULL;
 	struct list_head *cur_bcm_clist = NULL;
-	int *n_active = NULL;
-	int *n_wake = NULL;
-	int *n_sleep = NULL;
+	int n_active[VCD_MAX_CNT];
+	int n_wake[VCD_MAX_CNT];
+	int n_sleep[VCD_MAX_CNT];
 	int cnt_vcd = 0;
 	int cnt_active = 0;
 	int cnt_wake = 0;
@@ -573,8 +573,15 @@
 
 	cur_mbox = cur_rsc->rscdev->mbox;
 	cur_bcm_clist = cur_rsc->rscdev->bcm_clist;
+	cmdlist_active = cur_rsc->rscdev->cmdlist_active;
+	cmdlist_wake = cur_rsc->rscdev->cmdlist_wake;
+	cmdlist_sleep = cur_rsc->rscdev->cmdlist_sleep;
 
 	for (i = 0; i < VCD_MAX_CNT; i++) {
+		n_active[i] = 0;
+		n_wake[i] = 0;
+		n_sleep[i] = 0;
+
 		if (list_empty(&cur_bcm_clist[i]))
 			continue;
 		list_for_each_entry(cur_bcm, &cur_bcm_clist[i], link) {
@@ -600,27 +607,6 @@
 	if (!cnt_active)
 		goto exit_msm_bus_commit_data;
 
-	n_active = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
-	if (!n_active)
-		return -ENOMEM;
-
-	n_wake = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
-	if (!n_wake)
-		return -ENOMEM;
-
-	n_sleep = kcalloc(cnt_vcd+1, sizeof(int), GFP_KERNEL);
-	if (!n_sleep)
-		return -ENOMEM;
-
-	if (cnt_active)
-		cmdlist_active = kcalloc(cnt_active, sizeof(struct tcs_cmd),
-								GFP_KERNEL);
-	if (cnt_sleep && cnt_wake) {
-		cmdlist_wake = kcalloc(cnt_wake, sizeof(struct tcs_cmd),
-								GFP_KERNEL);
-		cmdlist_sleep = kcalloc(cnt_sleep, sizeof(struct tcs_cmd),
-								GFP_KERNEL);
-	}
 	bcm_cnt = tcs_cmd_list_gen(n_active, n_wake, n_sleep, cmdlist_active,
 				cmdlist_wake, cmdlist_sleep, cur_bcm_clist);
 
@@ -654,8 +640,6 @@
 		if (ret)
 			MSM_BUS_ERR("%s: error sending wake sets: %d\n",
 							__func__, ret);
-		kfree(n_wake);
-		kfree(cmdlist_wake);
 	}
 	if (cnt_sleep) {
 		ret = rpmh_write_batch(cur_mbox, RPMH_SLEEP_STATE,
@@ -663,14 +647,8 @@
 		if (ret)
 			MSM_BUS_ERR("%s: error sending sleep sets: %d\n",
 							__func__, ret);
-		kfree(n_sleep);
-		kfree(cmdlist_sleep);
 	}
 
-	kfree(cmdlist_active);
-	kfree(n_active);
-
-
 	list_for_each_entry_safe(node, node_tmp, clist, link) {
 		if (unlikely(node->node_info->defer_qos))
 			msm_bus_dev_init_qos(&node->dev, NULL);
@@ -1168,6 +1146,41 @@
 	return ret;
 }
 
+static int msm_bus_postcon_setup(struct device *bus_dev, void *data)
+{
+	struct msm_bus_node_device_type *bus_node = NULL;
+	struct msm_bus_rsc_device_type *rscdev;
+
+	bus_node = to_msm_bus_node(bus_dev);
+	if (!bus_node) {
+		MSM_BUS_ERR("%s: Can't get device info", __func__);
+		return -ENODEV;
+	}
+
+	if (bus_node->node_info->is_rsc_dev) {
+		rscdev = bus_node->rscdev;
+		rscdev->cmdlist_active = devm_kcalloc(bus_dev,
+					rscdev->num_bcm_devs,
+					sizeof(struct tcs_cmd), GFP_KERNEL);
+		if (!rscdev->cmdlist_active)
+			return -ENOMEM;
+
+		rscdev->cmdlist_wake = devm_kcalloc(bus_dev,
+					rscdev->num_bcm_devs,
+					sizeof(struct tcs_cmd), GFP_KERNEL);
+		if (!rscdev->cmdlist_wake)
+			return -ENOMEM;
+
+		rscdev->cmdlist_sleep = devm_kcalloc(bus_dev,
+					rscdev->num_bcm_devs,
+					sizeof(struct tcs_cmd),	GFP_KERNEL);
+		if (!rscdev->cmdlist_sleep)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
 static int msm_bus_init_clk(struct device *bus_dev,
 				struct msm_bus_node_device_type *pdata)
 {
@@ -1641,6 +1654,7 @@
 			goto exit_setup_dev_conn;
 		}
 		rsc_node = to_msm_bus_node(bus_node->node_info->rsc_devs[j]);
+		rsc_node->rscdev->num_bcm_devs++;
 	}
 
 exit_setup_dev_conn:
@@ -1771,6 +1785,13 @@
 		goto exit_device_probe;
 	}
 
+	ret = bus_for_each_dev(&msm_bus_type, NULL, NULL,
+						msm_bus_postcon_setup);
+	if (ret) {
+		MSM_BUS_ERR("%s: Error post connection setup", __func__);
+		goto exit_device_probe;
+	}
+
 	/*
 	 * Setup the QoS for the nodes, don't check the error codes as we
 	 * defer QoS programming to the first transaction in cases of failure
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
index 8929959..b023f72 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -88,6 +88,10 @@
 	int req_state;
 	uint32_t acv[NUM_CTX];
 	uint32_t query_acv[NUM_CTX];
+	struct tcs_cmd *cmdlist_active;
+	struct tcs_cmd *cmdlist_wake;
+	struct tcs_cmd *cmdlist_sleep;
+	int num_bcm_devs;
 };
 
 struct msm_bus_bcm_device_type {
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index e0f912d..ee6c4cd 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -411,7 +411,7 @@
 	/* In case of any failure where reclaiming MBA and DP memory
 	 * could not happen, free the memory here
 	 */
-	if (drv->q6->mba_dp_virt) {
+	if (drv->q6->mba_dp_virt && !drv->mba_mem_dev_fixed) {
 		if (pil->subsys_vmid > 0)
 			pil_assign_mem_to_linux(pil, drv->q6->mba_dp_phys,
 						drv->q6->mba_dp_size);
@@ -648,7 +648,7 @@
 {
 	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
 	struct modem_data *md = dev_get_drvdata(pil->dev);
-	const struct firmware *fw, *dp_fw = NULL;
+	const struct firmware *fw = NULL, *dp_fw = NULL;
 	char fw_name_legacy[10] = "mba.b00";
 	char fw_name[10] = "mba.mbn";
 	char *dp_name = "msadp";
@@ -660,6 +660,8 @@
 	struct device *dma_dev = md->mba_mem_dev_fixed ?: &md->mba_mem_dev;
 
 	trace_pil_func(__func__);
+	if (drv->mba_dp_virt && md->mba_mem_dev_fixed)
+		goto mss_reset;
 	fw_name_p = drv->non_elf_image ? fw_name_legacy : fw_name;
 	ret = request_firmware(&fw, fw_name_p, pil->dev);
 	if (ret) {
@@ -749,17 +751,19 @@
 			goto err_mba_data;
 		}
 	}
+	if (dp_fw)
+		release_firmware(dp_fw);
+	release_firmware(fw);
+	dp_fw = NULL;
+	fw = NULL;
 
+mss_reset:
 	ret = pil_mss_reset(pil);
 	if (ret) {
 		dev_err(pil->dev, "MBA boot failed(rc:%d)\n", ret);
 		goto err_mss_reset;
 	}
 
-	if (dp_fw)
-		release_firmware(dp_fw);
-	release_firmware(fw);
-
 	return 0;
 
 err_mss_reset:
@@ -772,7 +776,8 @@
 err_invalid_fw:
 	if (dp_fw)
 		release_firmware(dp_fw);
-	release_firmware(fw);
+	if (fw)
+		release_firmware(fw);
 	drv->mba_dp_virt = NULL;
 	return ret;
 }
@@ -851,10 +856,12 @@
 		if (pil->subsys_vmid > 0)
 			pil_assign_mem_to_linux(pil, drv->q6->mba_dp_phys,
 						drv->q6->mba_dp_size);
-		dma_free_attrs(dma_dev, drv->q6->mba_dp_size,
+		if (drv->q6->mba_dp_virt && !drv->mba_mem_dev_fixed) {
+			dma_free_attrs(dma_dev, drv->q6->mba_dp_size,
 				drv->q6->mba_dp_virt, drv->q6->mba_dp_phys,
 				drv->attrs_dma);
-		drv->q6->mba_dp_virt = NULL;
+			drv->q6->mba_dp_virt = NULL;
+		}
 
 	}
 	return ret;
@@ -921,7 +928,7 @@
 	}
 
 	if (drv->q6) {
-		if (drv->q6->mba_dp_virt) {
+		if (drv->q6->mba_dp_virt && !drv->mba_mem_dev_fixed) {
 			/* Reclaim MBA and DP (if allocated) memory. */
 			if (pil->subsys_vmid > 0)
 				pil_assign_mem_to_linux(pil,
diff --git a/drivers/soc/qcom/qmp-debugfs-client.c b/drivers/soc/qcom/qmp-debugfs-client.c
index 578e7f0..d7a473e 100644
--- a/drivers/soc/qcom/qmp-debugfs-client.c
+++ b/drivers/soc/qcom/qmp-debugfs-client.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
@@ -20,37 +20,55 @@
 #include <linux/platform_device.h>
 #include <linux/mailbox/qmp.h>
 #include <linux/uaccess.h>
+#include <linux/mailbox_controller.h>
 
 #define MAX_MSG_SIZE 96 /* Imposed by the remote*/
 
+struct qmp_debugfs_data {
+	struct qmp_pkt pkt;
+	char buf[MAX_MSG_SIZE + 1];
+};
+
+static struct qmp_debugfs_data data_pkt[MBOX_TX_QUEUE_LEN];
 static struct mbox_chan *chan;
 static struct mbox_client *cl;
 
+static DEFINE_MUTEX(qmp_debugfs_mutex);
+
 static ssize_t aop_msg_write(struct file *file, const char __user *userstr,
 		size_t len, loff_t *pos)
 {
-	char buf[MAX_MSG_SIZE + 1] = {0};
-	struct qmp_pkt pkt;
+	static int count;
 	int rc;
 
 	if (!len || (len > MAX_MSG_SIZE))
 		return len;
 
-	rc  = copy_from_user(buf, userstr, len);
+	mutex_lock(&qmp_debugfs_mutex);
+
+	if (count >= MBOX_TX_QUEUE_LEN)
+		count = 0;
+
+	memset(&(data_pkt[count]), 0, sizeof(data_pkt[count]));
+	rc  = copy_from_user(data_pkt[count].buf, userstr, len);
 	if (rc) {
 		pr_err("%s copy from user failed, rc=%d\n", __func__, rc);
+		mutex_unlock(&qmp_debugfs_mutex);
 		return len;
 	}
 
 	/*
 	 * Controller expects a 4 byte aligned buffer
 	 */
-	pkt.size = (len + 0x3) & ~0x3;
-	pkt.data = buf;
+	data_pkt[count].pkt.size = (len + 0x3) & ~0x3;
+	data_pkt[count].pkt.data = data_pkt[count].buf;
 
-	if (mbox_send_message(chan, &pkt) < 0)
+	if (mbox_send_message(chan, &(data_pkt[count].pkt)) < 0)
 		pr_err("Failed to send qmp request\n");
+	else
+		count++;
 
+	mutex_unlock(&qmp_debugfs_mutex);
 	return len;
 }
 
@@ -68,7 +86,7 @@
 
 	cl->dev = &pdev->dev;
 	cl->tx_block = true;
-	cl->tx_tout = 100;
+	cl->tx_tout = 1000;
 	cl->knows_txdone = false;
 
 	chan = mbox_request_channel(cl, 0);
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index 492b68c..cab7178 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -666,7 +666,7 @@
 	if (unlikely(!is_scm_armv8()))
 		return -ENODEV;
 
-	ret = allocate_extra_arg_buffer(desc, GFP_KERNEL);
+	ret = allocate_extra_arg_buffer(desc, GFP_NOIO);
 	if (ret)
 		return ret;
 
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 82dea32..556882c 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -652,6 +652,55 @@
 	return "UNKNOWN SOC TYPE";
 }
 
+const char * __init arch_read_machine_name(void)
+{
+	static char msm_machine_name[256] = "Qualcomm Technologies, Inc. ";
+	static bool string_generated;
+	u32 len = 0;
+	const char *name;
+
+	if (string_generated)
+		return msm_machine_name;
+
+	len = strlen(msm_machine_name);
+	name = of_get_flat_dt_prop(of_get_flat_dt_root(),
+				"qcom,msm-name", NULL);
+	if (name)
+		len += snprintf(msm_machine_name + len,
+					sizeof(msm_machine_name) - len,
+					"%s", name);
+	else
+		goto no_prop_path;
+
+	name = of_get_flat_dt_prop(of_get_flat_dt_root(),
+				"qcom,pmic-name", NULL);
+	if (name) {
+		len += snprintf(msm_machine_name + len,
+					sizeof(msm_machine_name) - len,
+					"%s", " ");
+		len += snprintf(msm_machine_name + len,
+					sizeof(msm_machine_name) - len,
+					"%s", name);
+	} else
+		goto no_prop_path;
+
+	name = of_flat_dt_get_machine_name();
+	if (name) {
+		len += snprintf(msm_machine_name + len,
+					sizeof(msm_machine_name) - len,
+					"%s", " ");
+		len += snprintf(msm_machine_name + len,
+					sizeof(msm_machine_name) - len,
+					"%s", name);
+	} else
+		goto no_prop_path;
+
+	string_generated = true;
+	return msm_machine_name;
+no_prop_path:
+	return of_flat_dt_get_machine_name();
+}
+
 uint32_t socinfo_get_raw_id(void)
 {
 	return socinfo ?
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 58a9308..e796526 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -726,7 +726,6 @@
 		memset(mas->gsi, 0,
 				(sizeof(struct spi_geni_gsi) * NUM_SPI_XFER));
 		geni_se_select_mode(mas->base, GSI_DMA);
-		dmaengine_resume(mas->tx);
 		ret = spi_geni_map_buf(mas, spi_msg);
 	} else {
 		dev_err(mas->dev, "%s: Couldn't select mode %d", __func__,
@@ -743,10 +742,8 @@
 
 	mas->cur_speed_hz = 0;
 	mas->cur_word_len = 0;
-	if (mas->cur_xfer_mode == GSI_DMA) {
-		dmaengine_pause(mas->tx);
+	if (mas->cur_xfer_mode == GSI_DMA)
 		spi_geni_unmap_buf(mas, spi_msg);
-	}
 	return 0;
 }
 
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 80c3f91..f8a9a2f 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -2591,11 +2591,9 @@
 	case PM_POST_SUSPEND:
 		atomic_set(&in_suspend, 0);
 		list_for_each_entry(tz, &thermal_tz_list, node) {
-			mutex_lock(&tz->lock);
 			thermal_zone_device_reset(tz);
-			mod_delayed_work(system_freezable_power_efficient_wq,
-						&tz->poll_queue, 0);
-			mutex_unlock(&tz->lock);
+			thermal_zone_device_update(tz,
+						   THERMAL_EVENT_UNSPECIFIED);
 		}
 		break;
 	default:
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 8718af8..80fdfad 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -90,6 +90,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 	d_instantiate(dentry, inode);
+	dentry->d_flags |= DCACHE_RCUACCESS;
 	dentry->d_fsdata = (void *)ns->ops;
 	d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
 	if (d) {
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 3e060d9..9a079a6 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -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
@@ -338,6 +338,7 @@
  * %CHAN_PATH_SCALING5: ratio of {1, 8}
  * %CHAN_PATH_SCALING6: ratio of {10, 81} The actual ratio is (1/8.1).
  * %CHAN_PATH_SCALING7: ratio of {1, 10}
+ * %CHAN_PATH_SCALING8: ratio of {1, 16}
  * %CHAN_PATH_NONE: Do not use this pre-scaling ratio type.
  *
  * The pre-scaling is applied for signals to be within the voltage range
@@ -352,6 +353,7 @@
 	PATH_SCALING5,
 	PATH_SCALING6,
 	PATH_SCALING7,
+	PATH_SCALING8,
 	PATH_SCALING_NONE,
 };
 
@@ -380,6 +382,12 @@
  * %SCALE_QRD_SKUT1_BATT_THERM: Conversion to temperature(decidegC) based on
  *          btm parameters for SKUT1
  * %SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
+ * %SCALE_BATT_THERM_TEMP: Conversion to temperature(decidegC) based on btm
+ *			parameters.
+ * %SCALE_CHRG_TEMP: Conversion for charger temp.
+ * %SCALE_DIE_TEMP: Conversion for die temp.
+ * %SCALE_I_DEFAULT: Default scaling to convert raw adc code to current (uA).
+ * %SCALE_USBIN_I: Conversion for USB input current.
  * %SCALE_NONE: Do not use this scaling type.
  */
 enum qpnp_adc_scale_fn_type {
@@ -397,6 +405,11 @@
 	SCALE_NCP_03WF683_THERM,
 	SCALE_QRD_SKUT1_BATT_THERM,
 	SCALE_PMI_CHG_TEMP = 16,
+	SCALE_BATT_THERM_TEMP,
+	SCALE_CHRG_TEMP,
+	SCALE_DIE_TEMP,
+	SCALE_I_DEFAULT,
+	SCALE_USBIN_I,
 	SCALE_NONE,
 };
 
@@ -1125,7 +1138,8 @@
 	{1, 20},
 	{1, 8},
 	{10, 81},
-	{1, 10}
+	{1, 10},
+	{1, 16}
 };
 
 /**
@@ -1347,6 +1361,23 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_iadc_scale_default() - Scales the pre-calibrated digital output
+ *		of current ADC to the ADC reference and compensates for the
+ *		gain and offset.
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital output of the ADC.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	Physical result to be stored.
+ */
+int32_t qpnp_iadc_scale_default(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
  * qpnp_adc_scale_pmic_therm() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
  *		gain and offset. Performs the AMUX out as 2mV/K and returns
@@ -1384,6 +1415,23 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_adc_batt_therm() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. Returns the temperature in decidegC.
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital output of the ADC.
+ * @adc_prop:	adc properties of the pm8xxx adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	physical result to be stored.
+ */
+int32_t qpnp_adc_batt_therm(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
  * qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
  *		gain and offset. Returns the temperature in decidegC.
@@ -1401,6 +1449,61 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt);
 /**
+ * qpnp_adc_scale_chrg_temp() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. The voltage measured by HKADC is related to
+ *		the junction temperature according to
+ *		Tj = 377.5 degC - (V_adc / 0.004)
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital output of the ADC.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_chrg_temp(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_die_temp() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset. The voltage measured by HKADC is related to
+ *		the junction temperature according to
+ *		Tj = -273.15 degC + (V_adc / 0.002)
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital output of the ADC.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_die_temp(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
+ * qpnp_adc_scale_usbin_curr() - Scales the pre-calibrated digital output
+ *		of an ADC to the ADC reference and compensates for the
+ *		gain and offset.
+ * @dev:	Structure device for qpnp vadc
+ * @adc_code:	pre-calibrated digital output of the ADC.
+ * @adc_prop:	adc properties of the qpnp adc such as bit resolution,
+ *		reference voltage.
+ * @chan_prop:	Individual channel properties to compensate the i/p scaling,
+ *		slope and offset.
+ * @chan_rslt:	Physical result to be stored.
+ */
+int32_t qpnp_adc_scale_usbin_curr(struct qpnp_vadc_chip *dev,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt);
+/**
  * qpnp_adc_scale_qrd_batt_therm() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
  *		gain and offset. Returns the temperature in decidegC.
@@ -1906,6 +2009,12 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt)
 { return -ENXIO; }
+static inline int32_t qpnp_iadc_scale_default(struct qpnp_vadc_chip *vadc,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
 static inline int32_t qpnp_adc_scale_pmic_therm(struct qpnp_vadc_chip *vadc,
 			int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
@@ -1918,12 +2027,36 @@
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt)
 { return -ENXIO; }
+static inline int32_t qpnp_adc_batt_therm(struct qpnp_vadc_chip *vadc,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
 static inline int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *vadc,
 			int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
 			const struct qpnp_vadc_chan_properties *chan_prop,
 			struct qpnp_vadc_result *chan_rslt)
 { return -ENXIO; }
+static inline int32_t qpnp_adc_scale_chrg_temp(struct qpnp_vadc_chip *vadc,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_die_temp(struct qpnp_vadc_chip *vadc,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_usbin_curr(struct qpnp_vadc_chip *vadc,
+			int32_t adc_code,
+			const struct qpnp_adc_properties *adc_prop,
+			const struct qpnp_vadc_chan_properties *chan_prop,
+			struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
 static inline int32_t qpnp_adc_scale_qrd_batt_therm(
 			struct qpnp_vadc_chip *vadc, int32_t adc_code,
 			const struct qpnp_adc_properties *adc_prop,
diff --git a/include/net/cnss2.h b/include/net/cnss2.h
new file mode 100644
index 0000000..ca2de60
--- /dev/null
+++ b/include/net/cnss2.h
@@ -0,0 +1,193 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _NET_CNSS2_H
+#define _NET_CNSS2_H
+
+#include <linux/pci.h>
+
+#define CNSS_MAX_FILE_NAME		20
+#define CNSS_MAX_TIMESTAMP_LEN		32
+
+/*
+ * Temporary change for compilation, will be removed
+ * after WLAN host driver switched to use new APIs
+ */
+#define CNSS_API_WITH_DEV
+
+enum cnss_bus_width_type {
+	CNSS_BUS_WIDTH_NONE,
+	CNSS_BUS_WIDTH_LOW,
+	CNSS_BUS_WIDTH_MEDIUM,
+	CNSS_BUS_WIDTH_HIGH
+};
+
+enum cnss_platform_cap_flag {
+	CNSS_HAS_EXTERNAL_SWREG = 0x01,
+	CNSS_HAS_UART_ACCESS = 0x02,
+};
+
+struct cnss_platform_cap {
+	u32 cap_flag;
+};
+
+struct cnss_fw_files {
+	char image_file[CNSS_MAX_FILE_NAME];
+	char board_data[CNSS_MAX_FILE_NAME];
+	char otp_data[CNSS_MAX_FILE_NAME];
+	char utf_file[CNSS_MAX_FILE_NAME];
+	char utf_board_data[CNSS_MAX_FILE_NAME];
+	char epping_file[CNSS_MAX_FILE_NAME];
+	char evicted_data[CNSS_MAX_FILE_NAME];
+};
+
+struct cnss_soc_info {
+	void __iomem *va;
+	phys_addr_t pa;
+	uint32_t chip_id;
+	uint32_t chip_family;
+	uint32_t board_id;
+	uint32_t soc_id;
+	uint32_t fw_version;
+	char fw_build_timestamp[CNSS_MAX_TIMESTAMP_LEN + 1];
+};
+
+struct cnss_wlan_runtime_ops {
+	int (*runtime_suspend)(struct pci_dev *pdev);
+	int (*runtime_resume)(struct pci_dev *pdev);
+};
+
+struct cnss_wlan_driver {
+	char *name;
+	int  (*probe)(struct pci_dev *pdev, const struct pci_device_id *id);
+	void (*remove)(struct pci_dev *pdev);
+	int  (*reinit)(struct pci_dev *pdev, const struct pci_device_id *id);
+	void (*shutdown)(struct pci_dev *pdev);
+	void (*crash_shutdown)(struct pci_dev *pdev);
+	int  (*suspend)(struct pci_dev *pdev, pm_message_t state);
+	int  (*resume)(struct pci_dev *pdev);
+	int  (*suspend_noirq)(struct pci_dev *pdev);
+	int  (*resume_noirq)(struct pci_dev *pdev);
+	void (*modem_status)(struct pci_dev *, int state);
+	void (*update_status)(struct pci_dev *pdev, uint32_t status);
+	struct cnss_wlan_runtime_ops *runtime_ops;
+	const struct pci_device_id *id_table;
+};
+
+enum cnss_driver_status {
+	CNSS_UNINITIALIZED,
+	CNSS_INITIALIZED,
+	CNSS_LOAD_UNLOAD,
+	CNSS_RECOVERY,
+};
+
+struct cnss_ce_tgt_pipe_cfg {
+	u32 pipe_num;
+	u32 pipe_dir;
+	u32 nentries;
+	u32 nbytes_max;
+	u32 flags;
+	u32 reserved;
+};
+
+struct cnss_ce_svc_pipe_cfg {
+	u32 service_id;
+	u32 pipe_dir;
+	u32 pipe_num;
+};
+
+struct cnss_shadow_reg_cfg {
+	u16 ce_id;
+	u16 reg_offset;
+};
+
+struct cnss_shadow_reg_v2_cfg {
+	u32 addr;
+};
+
+struct cnss_wlan_enable_cfg {
+	u32 num_ce_tgt_cfg;
+	struct cnss_ce_tgt_pipe_cfg *ce_tgt_cfg;
+	u32 num_ce_svc_pipe_cfg;
+	struct cnss_ce_svc_pipe_cfg *ce_svc_cfg;
+	u32 num_shadow_reg_cfg;
+	struct cnss_shadow_reg_cfg *shadow_reg_cfg;
+	u32 num_shadow_reg_v2_cfg;
+	struct cnss_shadow_reg_v2_cfg *shadow_reg_v2_cfg;
+};
+
+enum cnss_driver_mode {
+	CNSS_MISSION,
+	CNSS_FTM,
+	CNSS_EPPING,
+	CNSS_WALTEST,
+	CNSS_OFF,
+	CNSS_CCPM,
+	CNSS_QVIT,
+	CNSS_CALIBRATION,
+};
+
+enum cnss_recovery_reason {
+	CNSS_REASON_DEFAULT,
+	CNSS_REASON_LINK_DOWN,
+	CNSS_REASON_RDDM,
+	CNSS_REASON_TIMEOUT,
+};
+
+extern int cnss_wlan_register_driver(struct cnss_wlan_driver *driver);
+extern void cnss_wlan_unregister_driver(struct cnss_wlan_driver *driver);
+extern void cnss_device_crashed(struct device *dev);
+extern int cnss_pci_link_down(struct device *dev);
+extern void cnss_schedule_recovery(struct device *dev,
+				   enum cnss_recovery_reason reason);
+extern int cnss_self_recovery(struct device *dev,
+			      enum cnss_recovery_reason reason);
+extern int cnss_force_fw_assert(struct device *dev);
+extern void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size);
+extern int cnss_get_fw_files_for_target(struct device *dev,
+					struct cnss_fw_files *pfw_files,
+					u32 target_type, u32 target_version);
+extern int cnss_get_platform_cap(struct device *dev,
+				 struct cnss_platform_cap *cap);
+extern int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info);
+extern int cnss_request_bus_bandwidth(struct device *dev, int bandwidth);
+extern int cnss_power_up(struct device *dev);
+extern int cnss_power_down(struct device *dev);
+extern void cnss_request_pm_qos(struct device *dev, u32 qos_val);
+extern void cnss_remove_pm_qos(struct device *dev);
+extern void cnss_lock_pm_sem(struct device *dev);
+extern void cnss_release_pm_sem(struct device *dev);
+extern int cnss_wlan_pm_control(struct device *dev, bool vote);
+extern int cnss_auto_suspend(struct device *dev);
+extern int cnss_auto_resume(struct device *dev);
+extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name,
+					int *num_vectors,
+					uint32_t *user_base_data,
+					uint32_t *base_vector);
+extern int cnss_get_msi_irq(struct device *dev, unsigned int vector);
+extern void cnss_get_msi_address(struct device *dev, uint32_t *msi_addr_low,
+				 uint32_t *msi_addr_high);
+extern int cnss_wlan_enable(struct device *dev,
+			    struct cnss_wlan_enable_cfg *config,
+			    enum cnss_driver_mode mode,
+			    const char *host_version);
+extern int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode);
+extern unsigned int cnss_get_qmi_timeout(void);
+extern int cnss_athdiag_read(struct device *dev, uint32_t offset,
+			     uint32_t mem_type, uint32_t data_len,
+			     uint8_t *output);
+extern int cnss_athdiag_write(struct device *dev, uint32_t offset,
+			      uint32_t mem_type, uint32_t data_len,
+			      uint8_t *input);
+extern int cnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode);
+
+#endif /* _NET_CNSS2_H */
diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h
index 87f25b0..f5af604 100644
--- a/include/uapi/media/cam_sensor.h
+++ b/include/uapi/media/cam_sensor.h
@@ -119,20 +119,20 @@
  *
  * @slave_addr            :    OIS i2c slave address
  * @i2c_freq_mode         :    i2c frequency mode
+ * @cmd_type              :    Explains type of command
  * @ois_fw_flag           :    indicates if fw is present or not
  * @is_ois_calib          :    indicates the calibration data is available
  * @ois_name              :    OIS name
  * @opcode                :    opcode
- * @cmd_type              :    Explains type of command
  */
 struct cam_cmd_ois_info {
 	uint16_t              slave_addr;
 	uint8_t               i2c_freq_mode;
+	uint8_t               cmd_type;
 	uint8_t               ois_fw_flag;
 	uint8_t               is_ois_calib;
 	char                  ois_name[MAX_OIS_NAME_SIZE];
 	struct cam_ois_opcode opcode;
-	uint8_t               cmd_type;
 } __attribute__((packed));
 
 /**
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index b263bf3..5edfe66 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -230,7 +230,7 @@
 
 	if ((unsigned int)end > IPV6_MAXPLEN) {
 		pr_debug("offset is too large.\n");
-		return -1;
+		return -EINVAL;
 	}
 
 	ecn = ip6_frag_ecn(ipv6_hdr(skb));
@@ -263,7 +263,7 @@
 			 * this case. -DaveM
 			 */
 			pr_debug("end of fragment not rounded to 8 bytes.\n");
-			return -1;
+			return -EPROTO;
 		}
 		if (end > fq->q.len) {
 			/* Some bits beyond end -> corruption. */
@@ -357,7 +357,7 @@
 discard_fq:
 	inet_frag_kill(&fq->q, &nf_frags);
 err:
-	return -1;
+	return -EINVAL;
 }
 
 /*
@@ -566,6 +566,7 @@
 
 int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
 {
+	u16 savethdr = skb->transport_header;
 	struct net_device *dev = skb->dev;
 	int fhoff, nhoff, ret;
 	struct frag_hdr *fhdr;
@@ -599,8 +600,12 @@
 
 	spin_lock_bh(&fq->q.lock);
 
-	if (nf_ct_frag6_queue(fq, skb, fhdr, nhoff) < 0) {
-		ret = -EINVAL;
+	ret = nf_ct_frag6_queue(fq, skb, fhdr, nhoff);
+	if (ret < 0) {
+		if (ret == -EPROTO) {
+			skb->transport_header = savethdr;
+			ret = 0;
+		}
 		goto out_unlock;
 	}