Merge "ARM: dts: msm: Update GPU PM QoS Vote for SDM845"
diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt
index eaa7146b..654f26e 100644
--- a/Documentation/devicetree/bindings/arm/msm/imem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/imem.txt
@@ -67,6 +67,11 @@
 Memory region used to store USB PID and serial numbers to be used by
 bootloader in download mode.
 
+SSR Minidump Offset
+-------------------
+-Compatible: "qcom,msm-imem-minidump"
+-reg: start address and size of ssr imem region
+
 Required properties:
 -compatible: "qcom,msm-imem-diag-dload"
 -reg: start address and size of USB Diag download mode region in imem
@@ -115,4 +120,9 @@
 			compatible = "qcom,msm-imem-emergency_download_mode";
 			reg = <0xfe0 12>;
 		};
+
+		ss_mdump@b88 {
+			compatible = "qcom,msm-imem-minidump";
+			reg = <0xb88 28>;
+		};
 	};
diff --git a/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt b/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt
new file mode 100644
index 0000000..8f57d0a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/jtag-mm.txt
@@ -0,0 +1,32 @@
+* JTAG-MM
+
+The jtag-mm entry specifies the memory mapped addresses for the debug and ETM
+registers. The jtag-mm driver uses these to save and restore the registers
+using memory mapped access during power collapse so as to retain their state
+across power collapse. This is necessary in case cp14 access to the registers
+is not permitted.
+
+Required Properties:
+compatible: component name used for driver matching, should be:
+	"qcom,jtag-mm"		- for jtag-mm device
+	"qcom,jtagv8-mm"	- for jtagv8-mm device supporting ARMv8 targets
+
+	reg: physical base address and length of the register set
+	reg-names: should be "etm-base" for etm register set and "debug-base"
+		   for debug register set.
+	qcom,coresight-jtagmm-cpu: specifies phandle for the cpu associated
+				   with the jtag-mm device
+	qcom,si-enable : boolean, indicating etm save and restore is
+			 supported via system instructions
+	qcom,save-restore-disable : boolean, to disable etm save and restore
+				    functionality
+
+Example:
+jtag_mm: jtagmm@fc332000 {
+	compatible = "qcom,jtag-mm";
+	reg = <0xfc332000 0x1000>,
+		<0xfc333000 0x1000>;
+	reg-names = "etm-base","debug-base";
+
+	qcom,coresight-jtagmm-cpu = <&CPU0>;
+};
diff --git a/Documentation/devicetree/bindings/clock/qcom,camcc.txt b/Documentation/devicetree/bindings/clock/qcom,camcc.txt
index 313e50f..daf8a539 100644
--- a/Documentation/devicetree/bindings/clock/qcom,camcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,camcc.txt
@@ -2,7 +2,8 @@
 ----------------------------------------------------
 
 Required properties :
-- compatible : shall contain "qcom,cam_cc-sdm845" or "qcom,cam_cc-sdm845-v2"
+- compatible : shall contain "qcom,cam_cc-sdm845", "qcom,cam_cc-sdm845-v2" or
+	       "qcom,cam_cc-sdm670"
 - reg : shall contain base register location and length
 - reg-names: names of registers listed in the same order as in
 	     the reg property.
diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
index 87af0f6..d169c31 100644
--- a/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,dispcc.txt
@@ -2,7 +2,8 @@
 ----------------------------------------------------
 
 Required properties :
-- compatible : shall contain "qcom,dispcc-sdm845" or "qcom,dispcc-sdm845-v2".
+- compatible : shall contain "qcom,dispcc-sdm845", "qcom,dispcc-sdm845-v2" or
+	       "qcom,dispcc-sdm670".
 - reg : shall contain base register location and length.
 - reg-names: names of registers listed in the same order as in
 	     the reg property.
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index c280b92..538fb6d 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -18,6 +18,7 @@
 			"qcom,gcc-mdm9615"
 			"qcom,gcc-sdm845"
 			"qcom,gcc-sdm845-v2"
+			"qcom,gcc-sdm670"
 			"qcom,debugcc-sdm845"
 
 - reg : shall contain base register location and length
diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
index 12676b7..aa90bc4 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
@@ -7,6 +7,8 @@
 		"qcom,gpucc-sdm845-v2",
 		"qcom,gfxcc-sdm845",
 		"qcom,gfxcc-sdm845-v2"
+		"qcom,gpucc-sdm670",
+		"qcom,gfxcc-sdm670"
 
 - reg : shall contain base register offset and size.
 - #clock-cells : shall contain 1.
diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt
index c81a454..9ad7263 100644
--- a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt
@@ -2,7 +2,8 @@
 -------------------------------------------------------
 
 Required properties :
-- compatible : must be "qcom,rpmh-clk-sdm845"
+- compatible : shall contain "qcom,rpmh-clk-sdm845" or "qcom,rpmh-clk-sdm670"
+
 - #clock-cells : must contain 1
 - mboxes : list of RPMh mailbox phandle and channel identifier tuples.
 - mbox-names : list of names to identify the RPMh mailboxes used.
diff --git a/Documentation/devicetree/bindings/clock/qcom,videocc.txt b/Documentation/devicetree/bindings/clock/qcom,videocc.txt
index 6bd0f0b..9b53c65 100644
--- a/Documentation/devicetree/bindings/clock/qcom,videocc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,videocc.txt
@@ -2,8 +2,8 @@
 ----------------------------------------------------
 
 Required properties :
-- compatible : shall contain "qcom,video_cc-sdm845" or
-	       "qcom,video_cc-sdm845-v2".
+- compatible : shall contain "qcom,video_cc-sdm845", "qcom,video_cc-sdm845-v2"
+	       or "qcom,video_cc-sdm670".
 - reg : shall contain base register location and length.
 - reg-names: names of registers listed in the same order as in
 	     the reg property.
diff --git a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt
index 3e5b979..8682ab6 100644
--- a/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt
+++ b/Documentation/devicetree/bindings/input/tps65218-pwrbutton.txt
@@ -8,8 +8,9 @@
 Required properties:
 - compatible: should be "ti,tps65217-pwrbutton" or "ti,tps65218-pwrbutton"
 
-Required properties for TPS65218:
+Required properties:
 - interrupts: should be one of the following
+   - <2>: For controllers compatible with tps65217
    - <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218
 
 Examples:
@@ -17,6 +18,7 @@
 &tps {
 	tps65217-pwrbutton {
 		compatible = "ti,tps65217-pwrbutton";
+		interrupts = <2>;
 	};
 };
 
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index a014dac..0f8dc27 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -96,11 +96,6 @@
 		  retention. No cache invalidation operations involving asid
 		  may be used.
 
-- qcom,actlr:
-		  An array of <sid mask actlr-setting>.
-		  Any sid X for which X&~mask==sid will be programmed with the
-		  given actlr-setting.
-
 - qcom,deferred-regulator-disable-delay : The time delay for deferred regulator
                   disable in ms. In case of unmap call, regulator is
                   enabled/disabled. This may introduce additional delay. For
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt
new file mode 100644
index 0000000..cf551f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt
@@ -0,0 +1,149 @@
+* Qualcomm Technologies, Inc. MSM Camera FD
+
+The MSM camera Face Detection device provides dependency definitions
+for enabling Camera FD HW. MSM camera FD is implemented in multiple
+device nodes. The root FD device node has properties defined to hint
+the driver about the FD HW nodes available during the probe sequence.
+Each node has multiple properties defined for interrupts, clocks and
+regulators.
+
+=======================
+Required Node Structure
+=======================
+FD root interface node takes care of the handling Face Detection high level
+driver handling and controls underlying FD hardware present.
+
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,cam-fd".
+
+- compat-hw-name
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,fd".
+
+- num-fd
+  Usage: required
+  Value type: <u32>
+  Definition: Number of supported FD HW blocks.
+
+Example:
+	qcom,cam-fd {
+		compatible = "qcom,cam-fd";
+		compat-hw-name = "qcom,fd";
+		num-fd = <1>;
+	};
+
+=======================
+Required Node Structure
+=======================
+FD Node provides interface for Face Detection hardware driver
+about the device register map, interrupt map, clocks, regulators.
+
+- cell-index
+  Usage: required
+  Value type: <u32>
+  Definition: Node instance number.
+
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,fd41".
+
+- reg-names
+  Usage: optional
+  Value type: <string>
+  Definition: Name of the register resources.
+
+- reg
+  Usage: optional
+  Value type: <u32>
+  Definition: Register values.
+
+- reg-cam-base
+  Usage: optional
+  Value type: <u32>
+  Definition: Offset of the register space compared to
+              to Camera base register space.
+
+- interrupt-names
+  Usage: optional
+  Value type: <string>
+  Definition: Name of the interrupt.
+
+- interrupts
+  Usage: optional
+  Value type: <u32>
+  Definition: Interrupt line associated with FD HW.
+
+- regulator-names
+  Usage: required
+  Value type: <string>
+  Definition: Name of the regulator resources for FD HW.
+
+- camss-vdd-supply
+  Usage: required
+  Value type: <phandle>
+  Definition: Regulator reference corresponding to the names listed
+              in "regulator-names".
+
+- clock-names
+  Usage: required
+  Value type: <string>
+  Definition: List of clock names required for FD HW.
+
+- clocks
+  Usage: required
+  Value type: <phandle>
+  Definition: List of clocks required for FD HW.
+
+- clock-rates
+  Usage: required
+  Value type: <u32>
+  Definition: List of clocks rates.
+
+- src-clock-name
+  Usage: required
+  Value type: <string>
+  Definition: Source clock name.
+
+- clock-cntl-level
+  Usage: required
+  Value type: <string>
+  Definition: List of strings corresponds clock-rates levels.
+  Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo.
+
+Examples:
+	cam_fd: qcom,fd@ac5a000 {
+		cell-index = <0>;
+		compatible = "qcom,fd41";
+		reg-names = "fd_core", "fd_wrapper";
+		reg = <0xac5a000 0x1000>,
+			<0xac5b000 0x400>;
+		reg-cam-base = <0x5a000 0x5b000>;
+		interrupt-names = "fd";
+		interrupts = <0 462 0>;
+		regulator-names = "camss-vdd";
+		camss-vdd-supply = <&titan_top_gdsc>;
+		clock-names = "gcc_ahb_clk",
+			"gcc_axi_clk",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"camnoc_axi_clk",
+			"fd_core_clk_src",
+			"fd_core_clk",
+			"fd_core_uar_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_FD_CORE_CLK_SRC>,
+			<&clock_camcc CAM_CC_FD_CORE_CLK>,
+			<&clock_camcc CAM_CC_FD_CORE_UAR_CLK>;
+		src-clock-name = "fd_core_clk_src";
+		clock-cntl-level = "svs";
+		clock-rates = <0 0 0 0 0 400000000 0 0>;
+	};
+
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
index 0c63c7e..36dad1a 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
@@ -105,6 +105,11 @@
   Value type: <string>
   Definition: List of clock names required for CDM HW.
 
+- src-clock-name
+  Usage: required
+  Value type: <string>
+  Definition: Source clock name.
+
 - clocks
   Usage: required
   Value type: <phandle>
@@ -114,7 +119,7 @@
   Usage: required
   Value type: <string>
   Definition: List of strings corresponds clock-rates levels.
-  Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo.
+  Supported strings: lowsvs, svs, svs_l1, nominal, turbo.
 
 - clock-rates
   Usage: required
@@ -176,14 +181,20 @@
 		"ipe_0_axi_clk",
 		"ipe_0_clk",
 		"ipe_0_clk_src";
+	src-clock-name = "ipe_0_clk_src";
 	clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>,
 			<&clock_camcc CAM_CC_IPE_0_AREG_CLK>,
 			<&clock_camcc CAM_CC_IPE_0_AXI_CLK>,
 			<&clock_camcc CAM_CC_IPE_0_CLK>,
 			<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
 
-	clock-rates = <80000000 400000000 0 0 600000000>;
-	clock-cntl-level = "turbo";
+	clock-rates = <0 0 0 0 240000000>,
+		<0 0 0 0 404000000>,
+		<0 0 0 0 480000000>,
+		<0 0 0 0 538000000>,
+		<0 0 0 0 600000000>;
+	clock-cntl-level = "lowsvs", "svs",
+		"svs_l1", "nominal", "turbo";
 };
 
 qcom,ipe1 {
@@ -196,14 +207,20 @@
 		"ipe_1_axi_clk",
 		"ipe_1_clk",
 		"ipe_1_clk_src";
+	src-clock-name = "ipe_1_clk_src";
 	clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>,
 			<&clock_camcc CAM_CC_IPE_1_AREG_CLK>,
 			<&clock_camcc CAM_CC_IPE_1_AXI_CLK>,
 			<&clock_camcc CAM_CC_IPE_1_CLK>,
 			<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
 
-	clock-rates = <80000000 400000000 0 0 600000000>;
-	clock-cntl-level = "turbo";
+	clock-rates = <0 0 0 0 240000000>,
+		<0 0 0 0 404000000>,
+		<0 0 0 0 480000000>,
+		<0 0 0 0 538000000>,
+		<0 0 0 0 600000000>;
+	clock-cntl-level = "lowsvs", "svs",
+		"svs_l1", "nominal", "turbo";
 };
 
 bps: qcom,bps {
@@ -216,13 +233,19 @@
 		"bps_axi_clk",
 		"bps_clk",
 		"bps_clk_src";
+	src-clock-name = "bps_clk_src";
 	clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>,
 			<&clock_camcc CAM_CC_BPS_AREG_CLK>,
 			<&clock_camcc CAM_CC_BPS_AXI_CLK>,
 			<&clock_camcc CAM_CC_BPS_CLK>,
 			<&clock_camcc CAM_CC_BPS_CLK_SRC>;
 
-	clock-rates = <80000000 400000000 0 0 600000000>;
-	clock-cntl-level = "turbo";
+	clock-rates = <0 0 0 0 200000000>,
+		<0 0 0 0 404000000>,
+		<0 0 0 0 480000000>,
+		<0 0 0 0 600000000>,
+		<0 0 0 0 600000000>;
+	clock-cntl-level = "lowsvs", "svs",
+		"svs_l1", "nominal", "turbo";
 };
 
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index bc844de..271703f 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -90,6 +90,7 @@
 		    wordline clamp, and compiler memory clamp during MSS restart.
 - qcom,qdsp6v56-1-10: Boolean- Present if the qdsp version is v56 1.10
 - qcom,override-acc-1: Override the default ACC settings with this value if present.
+- qcom,minidump-id: Unique id for each subsystem
 
 One child node to represent the MBA image may be specified, when the MBA image
 needs to be loaded in a specifically carved out memory region.
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
index 92ef23c..fd2729f 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
@@ -43,6 +43,13 @@
   Definition: Boolean flag which indicates that the charger should not draw
 	      current from any of its input sources (USB, DC).
 
+- qcom,use-extcon
+  Usage:      optional
+  Value type: <empty>
+  Definition: Boolean flag which specify that smb138x will act as main charger
+	      to do extcon USB calls. If not defined, other charger driver can
+	      act as main charger to do extcon USB calls.
+
 - qcom,fcc-max-ua
   Usage:      optional
   Value type: <u32>
diff --git a/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt b/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt
index 98d131a..a11072c 100644
--- a/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/tps65217_charger.txt
@@ -2,11 +2,16 @@
 
 Required Properties:
 -compatible: "ti,tps65217-charger"
+-interrupts: TPS65217 interrupt numbers for the AC and USB charger input change.
+             Should be <0> for the USB charger and <1> for the AC adapter.
+-interrupt-names: Should be "USB" and "AC"
 
 This node is a subnode of the tps65217 PMIC.
 
 Example:
 
 	tps65217-charger {
-		compatible = "ti,tps65090-charger";
+		compatible = "ti,tps65217-charger";
+		interrupts = <0>, <1>;
+		interrupt-names = "USB", "AC";
 	};
diff --git a/Makefile b/Makefile
index 5894331..3849d63 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 40
+SUBLEVEL = 41
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c
index f39142a..be131b2 100644
--- a/arch/arc/kernel/mcip.c
+++ b/arch/arc/kernel/mcip.c
@@ -10,6 +10,7 @@
 
 #include <linux/smp.h>
 #include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/spinlock.h>
 #include <asm/irqflags-arcv2.h>
 #include <asm/mcip.h>
@@ -221,10 +222,13 @@
 static void idu_cascade_isr(struct irq_desc *desc)
 {
 	struct irq_domain *idu_domain = irq_desc_get_handler_data(desc);
+	struct irq_chip *core_chip = irq_desc_get_chip(desc);
 	irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc));
 	irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq;
 
+	chained_irq_enter(core_chip, desc);
 	generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq));
+	chained_irq_exit(core_chip, desc);
 }
 
 static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq)
diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi
index 03cec62..db858ff 100644
--- a/arch/arm/boot/dts/am57xx-idk-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi
@@ -294,7 +294,7 @@
 };
 
 &usb2 {
-	dr_mode = "otg";
+	dr_mode = "peripheral";
 };
 
 &mmc2 {
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 87ca50b..4d448f1 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -734,6 +734,8 @@
 	vmmc_aux-supply = <&vsim>;
 	bus-width = <8>;
 	non-removable;
+	no-sdio;
+	no-sd;
 };
 
 &mmc3 {
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index bc4bfe0..60d3fec 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -86,9 +86,9 @@
 CONFIG_NETFILTER=y
 CONFIG_NF_CONNTRACK=m
 CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
 CONFIG_NF_CONNTRACK_AMANDA=m
 CONFIG_NF_CONNTRACK_FTP=m
 CONFIG_NF_CONNTRACK_H323=m
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 1052b29..b5c1714 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -790,14 +790,14 @@
 	int ret = 0;
 	char name[MOD_CLK_MAX_NAME_LEN];
 	struct clk *clk;
+	static const char modck[] = "_mod_ck";
 
-	/* +7 magic comes from '_mod_ck' suffix */
-	if (strlen(oh->name) + 7 > MOD_CLK_MAX_NAME_LEN)
+	if (strlen(oh->name) >= MOD_CLK_MAX_NAME_LEN - strlen(modck))
 		pr_warn("%s: warning: cropping name for %s\n", __func__,
 			oh->name);
 
-	strncpy(name, oh->name, MOD_CLK_MAX_NAME_LEN - 7);
-	strcat(name, "_mod_ck");
+	strlcpy(name, oh->name, MOD_CLK_MAX_NAME_LEN - strlen(modck));
+	strlcat(name, modck, MOD_CLK_MAX_NAME_LEN);
 
 	clk = clk_get(NULL, name);
 	if (!IS_ERR(clk)) {
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 52af31c..f2cf941 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -68,14 +68,22 @@
 ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
 	dtbo-$(CONFIG_ARCH_SDM670) += \
 		sdm670-cdp-overlay.dtbo \
-		sdm670-mtp-overlay.dtbo
+		sdm670-mtp-overlay.dtbo \
+		sdm670-rumi-overlay.dtbo \
+		sdm670-pm660a-cdp-overlay.dtbo \
+		sdm670-pm660a-mtp-overlay.dtbo
 
 sdm670-cdp-overlay.dtbo-base := sdm670.dtb
 sdm670-mtp-overlay.dtbo-base := sdm670.dtb
+sdm670-rumi-overlay.dtbo-base := sdm670.dtb
+sdm670-pm660a-cdp-overlay.dtbo-base := sdm670.dtb
+sdm670-pm660a-mtp-overlay.dtbo-base := sdm670.dtb
 else
 dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
 	sdm670-mtp.dtb \
-	sdm670-cdp.dtb
+	sdm670-cdp.dtb \
+	sdm670-pm660a-mtp.dtb \
+	sdm670-pm660a-cdp.dtb
 endif
 
 always		:= $(dtb-y)
diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi
index 8075b9e..48d68a7 100644
--- a/arch/arm64/boot/dts/qcom/pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660.dtsi
@@ -14,7 +14,7 @@
 #include <dt-bindings/interrupt-controller/irq.h>
 
 &spmi_bus {
-	qcom,pm660@0 {
+	pm660_0: qcom,pm660@0 {
 		compatible ="qcom,spmi-pmic";
 		reg = <0x0 SPMI_USID>;
 		#address-cells = <2>;
@@ -245,149 +245,10 @@
 			};
 		};
 
-		pm660_charger: qcom,qpnp-smb2 {
-			compatible = "qcom,qpnp-smb2";
-			#address-cells = <1>;
-			#size-cells = <1>;
-
-			qcom,pmic-revid = <&pm660_revid>;
-
-			io-channels = <&pm660_rradc 8>,
-				      <&pm660_rradc 10>,
-				      <&pm660_rradc 3>,
-				      <&pm660_rradc 4>;
-			io-channel-names = "charger_temp",
-					   "charger_temp_max",
-					   "usbin_i",
-					   "usbin_v";
-
-			qcom,wipower-max-uw = <5000000>;
-
-			/* Enable after the qusb_phy0 device node is added */
-			/* dpdm-supply = <&qusb_phy0>; */
-
-			qcom,thermal-mitigation
-					= <3000000 2500000 2000000 1500000
-						1000000 500000>;
-
-			qcom,chgr@1000 {
-				reg = <0x1000 0x100>;
-				interrupts =
-					<0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
-
-				interrupt-names = "chg-error",
-						  "chg-state-change",
-						  "step-chg-state-change",
-						  "step-chg-soc-update-fail",
-						  "step-chg-soc-update-request";
-			};
-
-			qcom,otg@1100 {
-				reg = <0x1100 0x100>;
-				interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
-
-				interrupt-names = "otg-fail",
-						  "otg-overcurrent",
-						  "otg-oc-dis-sw-sts",
-						  "testmode-change-detect";
-			};
-
-			qcom,bat-if@1200 {
-				reg = <0x1200 0x100>;
-				interrupts =
-					<0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
-
-				interrupt-names = "bat-temp",
-						  "bat-ocp",
-						  "bat-ov",
-						  "bat-low",
-						  "bat-therm-or-id-missing",
-						  "bat-terminal-missing";
-			};
-
-			qcom,usb-chgpth@1300 {
-				reg = <0x1300 0x100>;
-				interrupts =
-					<0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
-
-				interrupt-names = "usbin-collapse",
-						  "usbin-lt-3p6v",
-						  "usbin-uv",
-						  "usbin-ov",
-						  "usbin-plugin",
-						  "usbin-src-change",
-						  "usbin-icl-change",
-						  "type-c-change";
-			};
-
-			qcom,dc-chgpth@1400 {
-				reg = <0x1400 0x100>;
-				interrupts =
-					<0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
-
-				interrupt-names = "dcin-collapse",
-						  "dcin-lt-3p6v",
-						  "dcin-uv",
-						  "dcin-ov",
-						  "dcin-plugin",
-						  "div2-en-dg",
-						  "dcin-icl-change";
-			};
-
-			qcom,chgr-misc@1600 {
-				reg = <0x1600 0x100>;
-				interrupts =
-					<0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
-					<0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
-					<0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
-					<0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
-
-				interrupt-names = "wdog-snarl",
-						  "wdog-bark",
-						  "aicl-fail",
-						  "aicl-done",
-						  "high-duty-cycle",
-						  "input-current-limiting",
-						  "temperature-change",
-						  "switcher-power-ok";
-			};
-		};
-
 		pm660_pdphy: qcom,usb-pdphy@1700 {
 			compatible = "qcom,qpnp-pdphy";
 			reg = <0x1700 0x100>;
 			vdd-pdphy-supply = <&pm660l_l7>;
-			vbus-supply = <&smb2_vbus>;
-			vconn-supply = <&smb2_vconn>;
 			interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
 				     <0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
 				     <0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
@@ -497,73 +358,6 @@
 			qcom,pmic-revid = <&pm660_revid>;
 		};
 
-		pm660_fg: qpnp,fg {
-			compatible = "qcom,fg-gen3";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			qcom,pmic-revid = <&pm660_revid>;
-			io-channels = <&pm660_rradc 0>,
-				      <&pm660_rradc 7>;
-			io-channel-names = "rradc_batt_id",
-					   "rradc_die_temp";
-			qcom,rradc-base = <0x4500>;
-			qcom,fg-esr-timer-awake = <96 96>;
-			qcom,fg-esr-timer-asleep = <256 256>;
-			qcom,fg-esr-timer-charging = <0 96>;
-			qcom,cycle-counter-en;
-			status = "okay";
-
-			qcom,fg-batt-soc@4000 {
-				status = "okay";
-				reg = <0x4000 0x100>;
-				interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x40 0x2
-							IRQ_TYPE_EDGE_RISING>,
-					     <0x0 0x40 0x3
-							IRQ_TYPE_EDGE_RISING>,
-					     <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x40 0x5
-							IRQ_TYPE_EDGE_RISING>,
-					     <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
-				interrupt-names = "soc-update",
-						  "soc-ready",
-						  "bsoc-delta",
-						  "msoc-delta",
-						  "msoc-low",
-						  "msoc-empty",
-						  "msoc-high",
-						  "msoc-full";
-			};
-
-			qcom,fg-batt-info@4100 {
-				status = "okay";
-				reg = <0x4100 0x100>;
-				interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
-				interrupt-names = "vbatt-pred-delta",
-						  "vbatt-low",
-						  "esr-delta",
-						  "batt-missing",
-						  "batt-temp-delta";
-			};
-
-			qcom,fg-memif@4400 {
-				status = "okay";
-				reg = <0x4400 0x100>;
-				interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
-					     <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
-				interrupt-names = "ima-rdy",
-						  "mem-xcp",
-						  "dma-grant";
-			};
-		};
-
 		bcl@4200 {
 			compatible = "qcom,msm-bcl-lmh";
 			reg = <0x4200 0xff>,
@@ -579,32 +373,11 @@
 		};
 	};
 
-	qcom,pm660@1 {
+	pm660_1: qcom,pm660@1 {
 		compatible ="qcom,spmi-pmic";
 		reg = <0x1 SPMI_USID>;
 		#address-cells = <2>;
 		#size-cells = <0>;
-
-		pm660_haptics: qcom,haptics@c000 {
-			compatible = "qcom,qpnp-haptics";
-			reg = <0xc000 0x100>;
-			interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
-				     <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
-			interrupt-names = "hap-sc-irq", "hap-play-irq";
-			qcom,pmic-revid = <&pm660_revid>;
-			qcom,pmic-misc = <&pm660_misc>;
-			qcom,misc-clk-trim-error-reg = <0xf3>;
-			qcom,actuator-type = <0>;
-			qcom,play-mode = "direct";
-			qcom,vmax-mv = <3200>;
-			qcom,ilim-ma = <800>;
-			qcom,sc-dbc-cycles = <8>;
-			qcom,wave-play-rate-us = <6667>;
-			qcom,en-brake;
-			qcom,lra-high-z = "opt0";
-			qcom,lra-auto-res-mode = "qwd";
-			qcom,lra-res-cal-period = <4>;
-		};
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/pm660l.dtsi b/arch/arm64/boot/dts/qcom/pm660l.dtsi
index 11101ffe..771154a 100644
--- a/arch/arm64/boot/dts/qcom/pm660l.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm660l.dtsi
@@ -185,35 +185,6 @@
 			};
 		};
 
-		pm660l_wled: qcom,leds@d800 {
-			compatible = "qcom,qpnp-wled";
-			reg = <0xd800 0x100>,
-				<0xd900 0x100>;
-			reg-names = "qpnp-wled-ctrl-base",
-					"qpnp-wled-sink-base";
-			interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
-			interrupt-names = "ovp-irq";
-			linux,name = "wled";
-			linux,default-trigger = "bkl-trigger";
-			qcom,fdbk-output = "auto";
-			qcom,vref-uv = <127500>;
-			qcom,switch-freq-khz = <800>;
-			qcom,ovp-mv = <29600>;
-			qcom,ilim-ma = <970>;
-			qcom,boost-duty-ns = <26>;
-			qcom,mod-freq-khz = <9600>;
-			qcom,dim-mode = "hybrid";
-			qcom,hyb-thres = <625>;
-			qcom,sync-dly-us = <800>;
-			qcom,fs-curr-ua = <25000>;
-			qcom,cons-sync-write-delay-us = <1000>;
-			qcom,led-strings-list = [00 01 02];
-			qcom,loop-auto-gm-en;
-			qcom,pmic-revid = <&pm660l_revid>;
-			qcom,auto-calibration-enable;
-			status = "ok";
-		};
-
 		flash_led: qcom,leds@d300 {
 			compatible = "qcom,qpnp-flash-led-v2";
 			reg = <0xd300 0x100>;
@@ -322,89 +293,5 @@
 				qcom,default-led-trigger = "switch1_trigger";
 			};
 		};
-
-		pm660l_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 = <&pm660l_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>;
-			};
-		};
-
-		pm660a_oledb: qpnp-oledb@e000 {
-		       compatible = "qcom,qpnp-oledb-regulator";
-		       #address-cells = <1>;
-		       #size-cells = <1>;
-		       qcom,pmic-revid = <&pm660l_revid>;
-		       reg = <0xe000 0x100>;
-		       qcom,pbs-client = <&pm660l_pbs>;
-
-		       label = "oledb";
-		       regulator-name = "regulator-oledb";
-		       regulator-min-microvolt = <5000000>;
-		       regulator-max-microvolt = <8100000>;
-
-		       qcom,swire-control;
-		       qcom,ext-pin-control;
-		       status = "disabled";
-		};
-
-		pm660a_labibb: qpnp-labibb-regulator {
-			compatible = "qcom,qpnp-labibb-regulator";
-			#address-cells = <1>;
-			#size-cells = <1>;
-			qcom,pmic-revid = <&pm660l_revid>;
-			qcom,swire-control;
-			status = "disabled";
-
-			ibb_regulator: qcom,ibb@dc00 {
-				reg = <0xdc00 0x100>;
-				reg-names = "ibb_reg";
-				regulator-name = "ibb_reg";
-
-				regulator-min-microvolt = <4000000>;
-				regulator-max-microvolt = <6300000>;
-
-				qcom,qpnp-ibb-min-voltage = <1400000>;
-				qcom,qpnp-ibb-step-size = <100000>;
-				qcom,qpnp-ibb-slew-rate = <2000000>;
-				qcom,qpnp-ibb-init-voltage = <4000000>;
-				qcom,qpnp-ibb-init-amoled-voltage = <4000000>;
-			};
-
-			lab_regulator: qcom,lab@de00 {
-				reg = <0xde00 0x100>;
-				reg-names = "lab";
-				regulator-name = "lab_reg";
-
-				regulator-min-microvolt = <4600000>;
-				regulator-max-microvolt = <6100000>;
-
-				qcom,qpnp-lab-min-voltage = <4600000>;
-				qcom,qpnp-lab-step-size = <100000>;
-				qcom,qpnp-lab-slew-rate = <5000>;
-				qcom,qpnp-lab-init-voltage = <4600000>;
-				qcom,qpnp-lab-init-amoled-voltage = <4600000>;
-
-				qcom,notify-lab-vreg-ok-sts;
-			};
-		};
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
index f0c820f..9feb5b4 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
@@ -22,9 +22,12 @@
 #include "sdm670-cdp.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. SDM670 CDP";
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L CDP";
 	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
 	qcom,msm-id = <336 0x0>;
 	qcom,board-id = <1 0>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
index 7e5947b..27882dd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
@@ -17,7 +17,10 @@
 #include "sdm670-cdp.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. SDM670 CDP";
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L CDP";
 	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
 	qcom,board-id = <1 0>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index 0cf48a3..4f40678 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+#include "sdm670-pmic-overlay.dtsi"
+
 &qupv3_se9_2uart {
 	status = "disabled";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
new file mode 100644
index 0000000..d13aa15
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-gpu.dtsi
@@ -0,0 +1,310 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+
+	pil_gpu: qcom,kgsl-hyp {
+		compatible = "qcom,pil-tz-generic";
+		qcom,pas-id = <13>;
+		qcom,firmware-name = "a615_zap";
+	};
+
+	msm_bus: qcom,kgsl-busmon{
+		label = "kgsl-busmon";
+		compatible = "qcom,kgsl-busmon";
+	};
+
+	gpubw: qcom,gpubw {
+		compatible = "qcom,devbw";
+		governor = "bw_vbif";
+		qcom,src-dst-ports = <26 512>;
+		qcom,bw-tbl =
+			<     0 /*  off     */ >,
+			<   381 /*  100  MHz */ >,
+			<   762 /*  200  MHz */ >,
+			<  1144 /*  300  MHz */ >,
+			<  1720 /*  451  MHz */ >,
+			<  2086 /*  547  MHz */ >,
+			<  2597 /*  681  MHz */ >,
+			<  3147 /*  825  MHz */ >,
+			<  3879 /*  1017 MHz */ >,
+			<  5161 /*  1353 MHz */ >,
+			<  5931 /*  1555 MHz */ >,
+			<  6881 /*  1804 MHz */ >;
+	};
+
+	msm_gpu: qcom,kgsl-3d0@5000000 {
+		label = "kgsl-3d0";
+		compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+		status = "ok";
+		reg = <0x5000000 0x40000>;
+		reg-names = "kgsl_3d0_reg_memory";
+		interrupts = <0 300 0>;
+		interrupt-names = "kgsl_3d0_irq";
+		qcom,id = <0>;
+
+		qcom,chipid = <0x06010500>;
+
+		qcom,initial-pwrlevel = <3>;
+
+		qcom,gpu-quirk-hfi-use-reg;
+
+		/* <HZ/12> */
+		qcom,idle-timeout = <80>;
+		qcom,no-nap;
+
+		qcom,highest-bank-bit = <14>;
+
+		qcom,min-access-length = <64>;
+
+		qcom,ubwc-mode = <2>;
+
+		/* size in bytes */
+		qcom,snapshot-size = <1048576>;
+
+		/* base addr, size */
+		qcom,gpu-qdss-stm = <0x161c0000 0x40000>;
+
+		clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
+			<&clock_gpucc GPU_CC_CXO_CLK>,
+			<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+			<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+			<&clock_gpucc GPU_CC_CX_GMU_CLK>,
+			<&clock_gpucc GPU_CC_AHB_CLK>;
+
+		clock-names = "core_clk", "rbbmtimer_clk", "mem_clk",
+				"mem_iface_clk", "gmu_clk", "ahb_clk";
+
+		/* Bus Scale Settings */
+		qcom,gpubw-dev = <&gpubw>;
+		qcom,bus-control;
+		qcom,msm-bus,name = "grp3d";
+		qcom,bus-width = <32>;
+		qcom,msm-bus,num-cases = <12>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<26 512 0 0>,
+				<26 512 0 400000>,     /*  1 bus=100  */
+				<26 512 0 800000>,     /*  2 bus=200  */
+				<26 512 0 1200000>,    /*  3 bus=300  */
+				<26 512 0 1804000>,    /*  4 bus=451  */
+				<26 512 0 2188000>,    /*  5 bus=547  */
+				<26 512 0 2724000>,    /*  6 bus=681  */
+				<26 512 0 3300000>,    /*  7 bus=825  */
+				<26 512 0 4068000>,    /*  8 bus=1017 */
+				<26 512 0 5412000>,    /*  9 bus=1353 */
+				<26 512 0 6220000>,    /* 10 bus=1555 */
+				<26 512 0 7216000>;    /* 11 bus=1804 */
+
+		/* GDSC regulator names */
+		regulator-names = "vddcx", "vdd";
+		/* GDSC oxili regulators */
+		vddcx-supply = <&gpu_cx_gdsc>;
+		vdd-supply = <&gpu_gx_gdsc>;
+
+		/* GPU related llc slices */
+		cache-slice-names = "gpu", "gpuhtw";
+		cache-slices = <&llcc 12>, <&llcc 11>;
+
+		/* CPU latency parameter */
+		qcom,pm-qos-active-latency = <660>;
+		qcom,pm-qos-wakeup-latency = <460>;
+
+		/* Enable context aware freq. scaling */
+		qcom,enable-ca-jump;
+		/* Context aware jump busy penalty in us */
+		qcom,ca-busy-penalty = <12000>;
+		/* Context aware jump target power level */
+		qcom,ca-target-pwrlevel = <1>;
+
+		/* GPU Mempools */
+		qcom,gpu-mempools {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "qcom,gpu-mempools";
+
+			/* 4K Page Pool configuration */
+			qcom,gpu-mempool@0 {
+				reg = <0>;
+				qcom,mempool-page-size = <4096>;
+				qcom,mempool-allocate;
+			};
+			/* 8K Page Pool configuration */
+			qcom,gpu-mempool@1 {
+				reg = <1>;
+				qcom,mempool-page-size = <8192>;
+				qcom,mempool-allocate;
+			};
+			/* 64K Page Pool configuration */
+			qcom,gpu-mempool@2 {
+				reg = <2>;
+				qcom,mempool-page-size = <65536>;
+				qcom,mempool-reserved = <256>;
+			};
+			/* 1M Page Pool configuration */
+			qcom,gpu-mempool@3 {
+				reg = <3>;
+				qcom,mempool-page-size = <1048576>;
+				qcom,mempool-reserved = <32>;
+			};
+		};
+
+		/* Power levels */
+		qcom,gpu-pwrlevels {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,gpu-pwrlevels";
+
+			/* SVS_L1 */
+			qcom,gpu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gpu-freq = <430000000>;
+				qcom,bus-freq = <11>;
+				qcom,bus-min = <10>;
+				qcom,bus-max = <11>;
+			};
+
+			/* SVS */
+			qcom,gpu-pwrlevel@1 {
+				reg = <1>;
+				qcom,gpu-freq = <355000000>;
+				qcom,bus-freq = <9>;
+				qcom,bus-min = <8>;
+				qcom,bus-max = <10>;
+			};
+
+			/* LOW SVS */
+			qcom,gpu-pwrlevel@2 {
+				reg = <2>;
+				qcom,gpu-freq = <267000000>;
+				qcom,bus-freq = <6>;
+				qcom,bus-min = <4>;
+				qcom,bus-max = <8>;
+			};
+
+			/* MIN SVS */
+			qcom,gpu-pwrlevel@3 {
+				reg = <3>;
+				qcom,gpu-freq = <180000000>;
+				qcom,bus-freq = <4>;
+				qcom,bus-min = <3>;
+				qcom,bus-max = <5>;
+			};
+
+			/* XO */
+			qcom,gpu-pwrlevel@4 {
+				reg = <4>;
+				qcom,gpu-freq = <0>;
+				qcom,bus-freq = <0>;
+				qcom,bus-min = <0>;
+				qcom,bus-max = <0>;
+			};
+		};
+
+	};
+
+	kgsl_msm_iommu: qcom,kgsl-iommu {
+		compatible = "qcom,kgsl-smmu-v2";
+
+		reg = <0x05040000 0x10000>;
+		qcom,protect = <0x40000 0x10000>;
+		qcom,micro-mmu-control = <0x6000>;
+
+		clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+			<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+			<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+
+		clock-names = "iface_clk", "mem_clk", "mem_iface_clk";
+
+		qcom,secure_align_mask = <0xfff>;
+		qcom,retention;
+		qcom,hyp_secure_alloc;
+
+		gfx3d_user: gfx3d_user {
+			compatible = "qcom,smmu-kgsl-cb";
+			label = "gfx3d_user";
+			iommus = <&kgsl_smmu 0>;
+			qcom,gpu-offset = <0x48000>;
+		};
+
+		gfx3d_secure: gfx3d_secure {
+			compatible = "qcom,smmu-kgsl-cb";
+			iommus = <&kgsl_smmu 2>;
+		};
+	};
+
+	gmu: qcom,gmu {
+		label = "kgsl-gmu";
+		compatible = "qcom,gpu-gmu";
+
+		reg =
+			<0x506a000 0x31000>,
+			<0xb200000 0x300000>,
+			<0xc200000 0x10000>;
+		reg-names =
+			"kgsl_gmu_reg",
+			"kgsl_gmu_pdc_reg",
+			"kgsl_gmu_cpr_reg";
+
+		interrupts = <0 304 0>, <0 305 0>;
+		interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq";
+
+		qcom,msm-bus,name = "cnoc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<26 10036 0 0>,      /* CNOC off */
+			<26 10036 0 100>;    /* CNOC on  */
+
+		regulator-names = "vddcx", "vdd";
+		vddcx-supply = <&gpu_cx_gdsc>;
+		vdd-supply = <&gpu_gx_gdsc>;
+
+
+		clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>,
+				<&clock_gpucc GPU_CC_CXO_CLK>,
+				<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+				<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+				<&clock_gpucc GPU_CC_AHB_CLK>;
+
+		clock-names = "gmu_clk", "cxo_clk", "axi_clk",
+				"memnoc_clk", "ahb_clk";
+
+		qcom,gmu-pwrlevels {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			compatible = "qcom,gmu-pwrlevels";
+
+			qcom,gmu-pwrlevel@0 {
+				reg = <0>;
+				qcom,gmu-freq = <200000000>;
+			};
+
+			qcom,gmu-pwrlevel@1 {
+				reg = <1>;
+				qcom,gmu-freq = <0>;
+			};
+		};
+
+		gmu_user: gmu_user {
+			compatible = "qcom,smmu-gmu-user-cb";
+			iommus = <&kgsl_smmu 4>;
+		};
+
+		gmu_kernel: gmu_kernel {
+			compatible = "qcom,smmu-gmu-kernel-cb";
+			iommus = <&kgsl_smmu 5>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
index c8537bc..65c16c1 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
@@ -22,8 +22,11 @@
 #include "sdm670-mtp.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. SDM670 MTP";
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L MTP";
 	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
 	qcom,msm-id = <336 0x0>;
 	qcom,board-id = <8 0>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
index 1de40b7..38a9fae 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
@@ -17,7 +17,10 @@
 #include "sdm670-mtp.dtsi"
 
 / {
-	model = "Qualcomm Technologies, Inc. SDM670 MTP";
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L MTP";
 	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
 	qcom,board-id = <8 0>;
+	qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+		       <0x0001001b 0x0102001a 0x0 0x0>,
+		       <0x0001001b 0x0201011a 0x0 0x0>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index 0cf48a3..4f40678 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+#include "sdm670-pmic-overlay.dtsi"
+
 &qupv3_se9_2uart {
 	status = "disabled";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts
new file mode 100644
index 0000000..b3d2357
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <1 0>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts
new file mode 100644
index 0000000..5cf3513
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-cdp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A CDP";
+	compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
+	qcom,board-id = <1 0>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts
new file mode 100644
index 0000000..ff3270d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts
@@ -0,0 +1,33 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A MTP";
+	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <8 0>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts
new file mode 100644
index 0000000..febd5d9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm670.dtsi"
+#include "sdm670-mtp.dtsi"
+#include "pm660a.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A MTP";
+	compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
+	qcom,board-id = <8 0>;
+	qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>,
+		       <0x0001001b 0x0002001a 0x0 0x0>,
+		       <0x0001001b 0x0202001a 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
new file mode 100644
index 0000000..cd8bfba
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -0,0 +1,367 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&pm660_0{
+	pm660_charger: qcom,qpnp-smb2 {
+		compatible = "qcom,qpnp-smb2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		qcom,pmic-revid = <&pm660_revid>;
+
+		io-channels = <&pm660_rradc 8>,
+			      <&pm660_rradc 10>,
+			      <&pm660_rradc 3>,
+			      <&pm660_rradc 4>;
+		io-channel-names = "charger_temp",
+				   "charger_temp_max",
+				   "usbin_i",
+				   "usbin_v";
+
+		qcom,wipower-max-uw = <5000000>;
+
+		/* Enable after the qusb_phy0 device node is added */
+		/* dpdm-supply = <&qusb_phy0>; */
+
+		qcom,thermal-mitigation
+				= <3000000 2500000 2000000 1500000
+					1000000 500000>;
+
+		qcom,chgr@1000 {
+			reg = <0x1000 0x100>;
+			interrupts =
+				<0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "chg-error",
+					  "chg-state-change",
+					  "step-chg-state-change",
+					  "step-chg-soc-update-fail",
+					  "step-chg-soc-update-request";
+		};
+
+		qcom,otg@1100 {
+			reg = <0x1100 0x100>;
+			interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "otg-fail",
+					  "otg-overcurrent",
+					  "otg-oc-dis-sw-sts",
+					  "testmode-change-detect";
+		};
+
+		qcom,bat-if@1200 {
+			reg = <0x1200 0x100>;
+			interrupts =
+				<0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "bat-temp",
+					  "bat-ocp",
+					  "bat-ov",
+					  "bat-low",
+					  "bat-therm-or-id-missing",
+					  "bat-terminal-missing";
+		};
+
+		qcom,usb-chgpth@1300 {
+			reg = <0x1300 0x100>;
+			interrupts =
+				<0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "usbin-collapse",
+					  "usbin-lt-3p6v",
+					  "usbin-uv",
+					  "usbin-ov",
+					  "usbin-plugin",
+					  "usbin-src-change",
+					  "usbin-icl-change",
+					  "type-c-change";
+		};
+
+		qcom,dc-chgpth@1400 {
+			reg = <0x1400 0x100>;
+			interrupts =
+				<0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names = "dcin-collapse",
+					  "dcin-lt-3p6v",
+					  "dcin-uv",
+					  "dcin-ov",
+					  "dcin-plugin",
+					  "div2-en-dg",
+					  "dcin-icl-change";
+		};
+
+		qcom,chgr-misc@1600 {
+			reg = <0x1600 0x100>;
+			interrupts =
+				<0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+				<0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>,
+				<0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>,
+				<0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>;
+
+			interrupt-names = "wdog-snarl",
+					  "wdog-bark",
+					  "aicl-fail",
+					  "aicl-done",
+					  "high-duty-cycle",
+					  "input-current-limiting",
+					  "temperature-change",
+					  "switcher-power-ok";
+		};
+		smb2_vbus: qcom,smb2-vbus {
+			regulator-name = "smb2-vbus";
+		};
+
+		smb2_vconn: qcom,smb2-vconn {
+			regulator-name = "smb2-vconn";
+		};
+	};
+
+	pm660_fg: qpnp,fg {
+		compatible = "qcom,fg-gen3";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		qcom,pmic-revid = <&pm660_revid>;
+		io-channels = <&pm660_rradc 0>,
+			      <&pm660_rradc 7>;
+		io-channel-names = "rradc_batt_id",
+				   "rradc_die_temp";
+		qcom,rradc-base = <0x4500>;
+		qcom,fg-esr-timer-awake = <96 96>;
+		qcom,fg-esr-timer-asleep = <256 256>;
+		qcom,fg-esr-timer-charging = <0 96>;
+		qcom,cycle-counter-en;
+		status = "okay";
+
+		qcom,fg-batt-soc@4000 {
+			status = "okay";
+			reg = <0x4000 0x100>;
+			interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x2
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x3
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x5
+						IRQ_TYPE_EDGE_RISING>,
+				     <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "soc-update",
+					  "soc-ready",
+					  "bsoc-delta",
+					  "msoc-delta",
+					  "msoc-low",
+					  "msoc-empty",
+					  "msoc-high",
+					  "msoc-full";
+		};
+
+		qcom,fg-batt-info@4100 {
+			status = "okay";
+			reg = <0x4100 0x100>;
+			interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "vbatt-pred-delta",
+					  "vbatt-low",
+					  "esr-delta",
+					  "batt-missing",
+					  "batt-temp-delta";
+		};
+
+		qcom,fg-memif@4400 {
+			status = "okay";
+			reg = <0x4400 0x100>;
+			interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+				     <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+			interrupt-names = "ima-rdy",
+					  "mem-xcp",
+					  "dma-grant";
+		};
+	};
+};
+
+&pm660_1 {
+	pm660_haptics: qcom,haptics@c000 {
+		compatible = "qcom,qpnp-haptics";
+		reg = <0xc000 0x100>;
+		interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+			     <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+		interrupt-names = "hap-sc-irq", "hap-play-irq";
+		qcom,pmic-revid = <&pm660_revid>;
+		qcom,pmic-misc = <&pm660_misc>;
+		qcom,misc-clk-trim-error-reg = <0xf3>;
+		qcom,actuator-type = <0>;
+		qcom,play-mode = "direct";
+		qcom,vmax-mv = <3200>;
+		qcom,ilim-ma = <800>;
+		qcom,sc-dbc-cycles = <8>;
+		qcom,wave-play-rate-us = <6667>;
+		qcom,en-brake;
+		qcom,lra-high-z = "opt0";
+		qcom,lra-auto-res-mode = "qwd";
+		qcom,lra-res-cal-period = <4>;
+	};
+};
+
+&pm660l_3 {
+	pm660l_wled: qcom,leds@d800 {
+		compatible = "qcom,qpnp-wled";
+		reg = <0xd800 0x100>,
+			<0xd900 0x100>;
+		reg-names = "qpnp-wled-ctrl-base",
+				"qpnp-wled-sink-base";
+		interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "ovp-irq";
+		linux,name = "wled";
+		linux,default-trigger = "bkl-trigger";
+		qcom,fdbk-output = "auto";
+		qcom,vref-uv = <127500>;
+		qcom,switch-freq-khz = <800>;
+		qcom,ovp-mv = <29600>;
+		qcom,ilim-ma = <970>;
+		qcom,boost-duty-ns = <26>;
+		qcom,mod-freq-khz = <9600>;
+		qcom,dim-mode = "hybrid";
+		qcom,hyb-thres = <625>;
+		qcom,sync-dly-us = <800>;
+		qcom,fs-curr-ua = <25000>;
+		qcom,cons-sync-write-delay-us = <1000>;
+		qcom,led-strings-list = [00 01 02];
+		qcom,loop-auto-gm-en;
+		qcom,pmic-revid = <&pm660l_revid>;
+		qcom,auto-calibration-enable;
+		status = "ok";
+	};
+
+	pm660l_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 = <&pm660l_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>;
+		};
+	};
+
+	pm660a_oledb: qpnp-oledb@e000 {
+	       compatible = "qcom,qpnp-oledb-regulator";
+	       #address-cells = <1>;
+	       #size-cells = <1>;
+	       qcom,pmic-revid = <&pm660l_revid>;
+	       reg = <0xe000 0x100>;
+	       qcom,pbs-client = <&pm660l_pbs>;
+
+	       label = "oledb";
+	       regulator-name = "regulator-oledb";
+	       regulator-min-microvolt = <5000000>;
+	       regulator-max-microvolt = <8100000>;
+
+	       qcom,swire-control;
+	       qcom,ext-pin-control;
+	       status = "disabled";
+	};
+
+	pm660a_labibb: qpnp-labibb-regulator {
+		compatible = "qcom,qpnp-labibb-regulator";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		qcom,pmic-revid = <&pm660l_revid>;
+		qcom,swire-control;
+		status = "disabled";
+
+		ibb_regulator: qcom,ibb@dc00 {
+			reg = <0xdc00 0x100>;
+			reg-names = "ibb_reg";
+			regulator-name = "ibb_reg";
+
+			regulator-min-microvolt = <4000000>;
+			regulator-max-microvolt = <6300000>;
+
+			qcom,qpnp-ibb-min-voltage = <1400000>;
+			qcom,qpnp-ibb-step-size = <100000>;
+			qcom,qpnp-ibb-slew-rate = <2000000>;
+			qcom,qpnp-ibb-init-voltage = <4000000>;
+			qcom,qpnp-ibb-init-amoled-voltage = <4000000>;
+		};
+
+		lab_regulator: qcom,lab@de00 {
+			reg = <0xde00 0x100>;
+			reg-names = "lab";
+			regulator-name = "lab_reg";
+
+			regulator-min-microvolt = <4600000>;
+			regulator-max-microvolt = <6100000>;
+
+			qcom,qpnp-lab-min-voltage = <4600000>;
+			qcom,qpnp-lab-step-size = <100000>;
+			qcom,qpnp-lab-slew-rate = <5000>;
+			qcom,qpnp-lab-init-voltage = <4600000>;
+			qcom,qpnp-lab-init-amoled-voltage = <4600000>;
+
+			qcom,notify-lab-vreg-ok-sts;
+		};
+	};
+};
+
+&pm660_pdphy {
+	vbus-supply = <&smb2_vbus>;
+	vconn-supply = <&smb2_vconn>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 0a8c49f..1f76288 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -628,13 +628,3 @@
 		};
 	};
 };
-
-&pm660_charger {
-	smb2_vbus: qcom,smb2-vbus {
-		regulator-name = "smb2-vbus";
-	};
-
-	smb2_vconn: qcom,smb2-vconn {
-		regulator-name = "smb2-vconn";
-	};
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts
new file mode 100644
index 0000000..4a24d87
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi-overlay.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "sdm670-rumi.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. SDM670 RUMI";
+	compatible = "qcom,sdm670-rumi", "qcom,sdm670", "qcom,rumi";
+	qcom,msm-id = <336 0x0>;
+	qcom,board-id = <15 0>;
+};
+
+&soc {
+	wdog: qcom,wdt@17980000{
+		status = "disabled";
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
index 4eb6dca..ca9d8c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dtsi
@@ -10,17 +10,7 @@
  * GNU General Public License for more details.
  */
 
-/{
-	aliases {
-		serial0 = &qupv3_se10_2uart;
-		serial1 = &qupv3_se9_2uart;
-		spi0 = &qupv3_se8_spi;
-		i2c0 = &qupv3_se10_i2c;
-		i2c1 = &qupv3_se3_i2c;
-		hsuart0 = &qupv3_se6_4uart;
-	};
-
-};
+#include "sdm670-pmic-overlay.dtsi"
 
 &soc {
 	/* Delete all regulators */
@@ -158,3 +148,38 @@
 
 	status = "ok";
 };
+
+&usb0 {
+	/delete-property/ qcom,usb-dbm;
+	/delete-property/ extcon;
+	qcom,charging-disabled;
+	dwc3@a600000 {
+		maximum-speed = "high-speed";
+		usb-phy = <&qusb_phy0>, <&usb_nop_phy>;
+	};
+};
+
+&qusb_phy0 {
+	reg = <0x088e2000 0x4>,
+		<0x0a720000 0x9500>;
+	reg-names = "qusb_phy_base",
+		"emu_phy_base";
+	qcom,emulation;
+	qcom,emu-init-seq = <0x19 0x1404
+				0x20 0x1414
+				0x79 0x1410
+				0x00 0x1418
+				0x99 0x1404
+				0x04 0x1408
+				0xd9 0x1404>;
+
+	qcom,emu-dcm-reset-seq = <0x5 0x14      /* 0x1 0x14 for E1.2 */
+				0x100000 0x20
+				0x0 0x20
+				0x1a0 0x20    /* 0x220 0x20 for E1.2 */
+				0x80 0x28>;
+};
+
+&usb_qmp_dp_phy {
+	status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
new file mode 100644
index 0000000..bd35cf2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-usb.dtsi
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm845-usb.dtsi"
+
+&soc {
+	/delete-node/ ssusb@a800000;
+	/delete-node/ qusb@88e3000;
+	/delete-node/ ssphy@88eb000;
+};
+
+&usb0 {
+	extcon = <&pm660_pdphy>, <&pm660_pdphy>, <0> /* <&eud> */;
+};
+
+&qusb_phy0 {
+	vdd-supply = <&pm660l_l1>;
+	vdda18-supply = <&pm660_l10>;
+	vdda33-supply = <&pm660l_l7>;
+};
+
+&usb_qmp_dp_phy {
+	vdd-supply = <&pm660_l1>;
+	core-supply = <&pm660l_l1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 42c2aed..6e987f1 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -33,9 +33,6 @@
 		ufshc1 = &ufshc_mem; /* Embedded UFS slot */
 		sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
 		sdhc2 = &sdhc_2; /* SDC2 SD Card slot */
-	};
-
-	aliases {
 		serial0 = &qupv3_se12_2uart;
 		spi0 = &qupv3_se8_spi;
 		i2c0 = &qupv3_se10_i2c;
@@ -75,6 +72,9 @@
 				compatible = "arm,arch-cache";
 				qcom,dump-size = <0x9000>;
 			};
+			L1_TLB_0: l1-tlb {
+				qcom,dump-size = <0x3000>;
+			};
 		};
 
 		CPU1: cpu@100 {
@@ -100,6 +100,9 @@
 				compatible = "arm,arch-cache";
 				qcom,dump-size = <0x9000>;
 			};
+			L1_TLB_100: l1-tlb {
+				qcom,dump-size = <0x3000>;
+			};
 		};
 
 		CPU2: cpu@200 {
@@ -125,6 +128,9 @@
 				compatible = "arm,arch-cache";
 				qcom,dump-size = <0x9000>;
 			};
+			L1_TLB_200: l1-tlb {
+				qcom,dump-size = <0x3000>;
+			};
 		};
 
 		CPU3: cpu@300 {
@@ -150,6 +156,9 @@
 				compatible = "arm,arch-cache";
 				qcom,dump-size = <0x9000>;
 			};
+			L1_TLB_300: l1-tlb {
+				qcom,dump-size = <0x3000>;
+			};
 		};
 
 		CPU4: cpu@400 {
@@ -175,6 +184,9 @@
 				compatible = "arm,arch-cache";
 				qcom,dump-size = <0x9000>;
 			};
+			L1_TLB_400: l1-tlb {
+				qcom,dump-size = <0x3000>;
+			};
 		};
 
 		CPU5: cpu@500 {
@@ -200,6 +212,9 @@
 				compatible = "arm,arch-cache";
 				qcom,dump-size = <0x9000>;
 			};
+			L1_TLB_500: l1-tlb {
+				qcom,dump-size = <0x3000>;
+			};
 		};
 
 		CPU6: cpu@600 {
@@ -225,6 +240,9 @@
 				compatible = "arm,arch-cache";
 				qcom,dump-size = <0x12000>;
 			};
+			L1_TLB_600: l1-tlb {
+				qcom,dump-size = <0x3c000>;
+			};
 		};
 
 		CPU7: cpu@700 {
@@ -250,6 +268,9 @@
 				compatible = "arm,arch-cache";
 				qcom,dump-size = <0x12000>;
 			};
+			L1_TLB_700: l1-tlb {
+				qcom,dump-size = <0x3c000>;
+			};
 		};
 
 		cpu-map {
@@ -1027,31 +1048,31 @@
 			qcom,dump-node = <&L1_I_0>;
 			qcom,dump-id = <0x60>;
 		};
-		qcom,l1_i_cache1 {
+		qcom,l1_i_cache100 {
 			qcom,dump-node = <&L1_I_100>;
 			qcom,dump-id = <0x61>;
 		};
-		qcom,l1_i_cache2 {
+		qcom,l1_i_cache200 {
 			qcom,dump-node = <&L1_I_200>;
 			qcom,dump-id = <0x62>;
 		};
-		qcom,l1_i_cache3 {
+		qcom,l1_i_cache300 {
 			qcom,dump-node = <&L1_I_300>;
 			qcom,dump-id = <0x63>;
 		};
-		qcom,l1_i_cache100 {
+		qcom,l1_i_cache400 {
 			qcom,dump-node = <&L1_I_400>;
 			qcom,dump-id = <0x64>;
 		};
-		qcom,l1_i_cache101 {
+		qcom,l1_i_cache500 {
 			qcom,dump-node = <&L1_I_500>;
 			qcom,dump-id = <0x65>;
 		};
-		qcom,l1_i_cache102 {
+		qcom,l1_i_cache600 {
 			qcom,dump-node = <&L1_I_600>;
 			qcom,dump-id = <0x66>;
 		};
-		qcom,l1_i_cache103 {
+		qcom,l1_i_cache700 {
 			qcom,dump-node = <&L1_I_700>;
 			qcom,dump-id = <0x67>;
 		};
@@ -1059,31 +1080,31 @@
 			qcom,dump-node = <&L1_D_0>;
 			qcom,dump-id = <0x80>;
 		};
-		qcom,l1_d_cache1 {
+		qcom,l1_d_cache100 {
 			qcom,dump-node = <&L1_D_100>;
 			qcom,dump-id = <0x81>;
 		};
-		qcom,l1_d_cache2 {
+		qcom,l1_d_cache200 {
 			qcom,dump-node = <&L1_D_200>;
 			qcom,dump-id = <0x82>;
 		};
-		qcom,l1_d_cache3 {
+		qcom,l1_d_cache300 {
 			qcom,dump-node = <&L1_D_300>;
 			qcom,dump-id = <0x83>;
 		};
-		qcom,l1_d_cache100 {
+		qcom,l1_d_cache400 {
 			qcom,dump-node = <&L1_D_400>;
 			qcom,dump-id = <0x84>;
 		};
-		qcom,l1_d_cache101 {
+		qcom,l1_d_cache500 {
 			qcom,dump-node = <&L1_D_500>;
 			qcom,dump-id = <0x85>;
 		};
-		qcom,l1_d_cache102 {
+		qcom,l1_d_cache600 {
 			qcom,dump-node = <&L1_D_600>;
 			qcom,dump-id = <0x86>;
 		};
-		qcom,l1_d_cache103 {
+		qcom,l1_d_cache700 {
 			qcom,dump-node = <&L1_D_700>;
 			qcom,dump-id = <0x87>;
 		};
@@ -1095,6 +1116,38 @@
 			qcom,dump-node = <&LLCC_2>;
 			qcom,dump-id = <0x141>;
 		};
+		qcom,l1_tlb_dump0 {
+			qcom,dump-node = <&L1_TLB_0>;
+			qcom,dump-id = <0x20>;
+		};
+		qcom,l1_tlb_dump100 {
+			qcom,dump-node = <&L1_TLB_100>;
+			qcom,dump-id = <0x21>;
+		};
+		qcom,l1_tlb_dump200 {
+			qcom,dump-node = <&L1_TLB_200>;
+			qcom,dump-id = <0x22>;
+		};
+		qcom,l1_tlb_dump300 {
+			qcom,dump-node = <&L1_TLB_300>;
+			qcom,dump-id = <0x23>;
+		};
+		qcom,l1_tlb_dump400 {
+			qcom,dump-node = <&L1_TLB_400>;
+			qcom,dump-id = <0x24>;
+		};
+		qcom,l1_tlb_dump500 {
+			qcom,dump-node = <&L1_TLB_500>;
+			qcom,dump-id = <0x25>;
+		};
+		qcom,l1_tlb_dump600 {
+			qcom,dump-node = <&L1_TLB_600>;
+			qcom,dump-id = <0x26>;
+		};
+		qcom,l1_tlb_dump700 {
+			qcom,dump-node = <&L1_TLB_700>;
+			qcom,dump-id = <0x27>;
+		};
 	};
 
 	kryo3xx-erp {
@@ -2049,3 +2102,5 @@
 #include "pm660l.dtsi"
 #include "sdm670-regulator.dtsi"
 #include "sdm670-audio.dtsi"
+#include "sdm670-usb.dtsi"
+#include "sdm670-gpu.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index f54cbdc..8df879a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -338,6 +338,22 @@
 				};
 			};
 		};
+
+		msm_cam_smmu_fd {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x1070 0x0>;
+			label = "fd";
+			fd_iova_mem_map: iova-mem-map {
+				iova-mem-region-io {
+					/* IO region is approximately 3.4 GB */
+					iova-region-name = "io";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0xd8c00000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
 	};
 
 	qcom,cam-cpas@ac40000 {
@@ -840,14 +856,20 @@
 			"ipe_0_axi_clk",
 			"ipe_0_clk",
 			"ipe_0_clk_src";
+		src-clock-name = "ipe_0_clk_src";
 		clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>,
 				<&clock_camcc CAM_CC_IPE_0_AREG_CLK>,
 				<&clock_camcc CAM_CC_IPE_0_AXI_CLK>,
 				<&clock_camcc CAM_CC_IPE_0_CLK>,
 				<&clock_camcc CAM_CC_IPE_0_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 600000000>;
-		clock-cntl-level = "turbo";
+		clock-rates = <0 0 0 0 240000000>,
+			<0 0 0 0 404000000>,
+			<0 0 0 0 480000000>,
+			<0 0 0 0 538000000>,
+			<0 0 0 0 600000000>;
+		clock-cntl-level = "lowsvs", "svs",
+			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
 
@@ -861,14 +883,20 @@
 			"ipe_1_axi_clk",
 			"ipe_1_clk",
 			"ipe_1_clk_src";
+		src-clock-name = "ipe_1_clk_src";
 		clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_AREG_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_AXI_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_CLK>,
 				<&clock_camcc CAM_CC_IPE_1_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 600000000>;
-		clock-cntl-level = "turbo";
+		clock-rates = <0 0 0 0 240000000>,
+			<0 0 0 0 404000000>,
+			<0 0 0 0 480000000>,
+			<0 0 0 0 538000000>,
+			<0 0 0 0 600000000>;
+		clock-cntl-level = "lowsvs", "svs",
+			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
 
@@ -882,14 +910,20 @@
 			"bps_axi_clk",
 			"bps_clk",
 			"bps_clk_src";
+		src-clock-name = "bps_clk_src";
 		clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>,
 				<&clock_camcc CAM_CC_BPS_AREG_CLK>,
 				<&clock_camcc CAM_CC_BPS_AXI_CLK>,
 				<&clock_camcc CAM_CC_BPS_CLK>,
 				<&clock_camcc CAM_CC_BPS_CLK_SRC>;
 
-		clock-rates = <0 0 0 0 600000000>;
-		clock-cntl-level = "turbo";
+		clock-rates = <0 0 0 0 200000000>,
+			<0 0 0 0 404000000>,
+			<0 0 0 0 480000000>,
+			<0 0 0 0 600000000>,
+			<0 0 0 0 600000000>;
+		clock-cntl-level = "lowsvs", "svs",
+			"svs_l1", "nominal", "turbo";
 		status = "ok";
 	};
 
@@ -964,4 +998,43 @@
 		status = "ok";
 	};
 
+	qcom,cam-fd {
+		compatible = "qcom,cam-fd";
+		compat-hw-name = "qcom,fd";
+		num-fd = <1>;
+		status = "ok";
+	};
+
+	cam_fd: qcom,fd@ac5a000 {
+		cell-index = <0>;
+		compatible = "qcom,fd41";
+		reg-names = "fd_core", "fd_wrapper";
+		reg = <0xac5a000 0x1000>,
+			<0xac5b000 0x400>;
+		reg-cam-base = <0x5a000 0x5b000>;
+		interrupt-names = "fd";
+		interrupts = <0 462 0>;
+		regulator-names = "camss-vdd";
+		camss-vdd-supply = <&titan_top_gdsc>;
+		clock-names = "gcc_ahb_clk",
+			"gcc_axi_clk",
+			"soc_ahb_clk",
+			"cpas_ahb_clk",
+			"camnoc_axi_clk",
+			"fd_core_clk_src",
+			"fd_core_clk",
+			"fd_core_uar_clk";
+		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
+			<&clock_gcc GCC_CAMERA_AXI_CLK>,
+			<&clock_camcc CAM_CC_SOC_AHB_CLK>,
+			<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
+			<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
+			<&clock_camcc CAM_CC_FD_CORE_CLK_SRC>,
+			<&clock_camcc CAM_CC_FD_CORE_CLK>,
+			<&clock_camcc CAM_CC_FD_CORE_UAR_CLK>;
+		src-clock-name = "fd_core_clk_src";
+		clock-cntl-level = "svs";
+		clock-rates = <0 0 0 0 0 400000000 0 0>;
+		status = "ok";
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index c1fcb62..3cfcddb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -1430,6 +1430,15 @@
 						<&tpda_spss_out_funnel_spss>;
 				};
 			};
+
+			port@2 {
+				reg = <1>;
+				funnel_spss_in_spss_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&spss_etm0_out_funnel_spss>;
+				};
+			};
 		};
 	};
 
@@ -1931,6 +1940,20 @@
 		};
 	};
 
+	spss_etm0 {
+		compatible = "qcom,coresight-dummy";
+
+		coresight-name = "coresight-spss-etm0";
+
+		qcom,dummy-source;
+		port {
+			spss_etm0_out_funnel_spss: endpoint {
+				remote-endpoint =
+					<&funnel_spss_in_spss_etm0>;
+			};
+		};
+	};
+
 	funnel_apss_merg: funnel@7810000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b908>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
index 299f01b..e36a759e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi
@@ -389,6 +389,7 @@
 #include "pm660.dtsi"
 #include "pm660l.dtsi"
 #include "sdm670-regulator.dtsi"
+#include "sdm670-pmic-overlay.dtsi"
 
 &soc {
 	/delete-node/ thermal-zones;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 121565e..0618f92 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -14,9 +14,11 @@
 	mdss_mdp: qcom,mdss_mdp@ae00000 {
 		compatible = "qcom,sde-kms";
 		reg = <0x0ae00000 0x81d40>,
-		      <0x0aeb0000 0x2008>;
+		      <0x0aeb0000 0x2008>,
+		      <0x0aeac000 0xf0>;
 		reg-names = "mdp_phys",
-			"vbif_phys";
+			"vbif_phys",
+			"regdma_phys";
 
 		clocks =
 			<&clock_gcc GCC_DISP_AHB_CLK>,
@@ -179,6 +181,9 @@
 		/* offsets are relative to "mdp_phys + qcom,sde-off */
 		qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>;
 
+		qcom,sde-reg-dma-off = <0>;
+		qcom,sde-reg-dma-version = <0x1>;
+		qcom,sde-reg-dma-trigger-off = <0x119c>;
 
 		qcom,sde-sspp-vig-blocks {
 			qcom,sde-vig-csc-off = <0x1a00>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 70a20c1..d72c91c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -26,6 +26,8 @@
 #include <dt-bindings/thermal/thermal.h>
 #include <dt-bindings/msm/msm-bus-ids.h>
 
+#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024))
+
 / {
 	model = "Qualcomm Technologies, Inc. SDM845";
 	compatible = "qcom,sdm845";
@@ -545,6 +547,7 @@
 
 		wlan_fw_region: wlan_fw_region@8cb00000 {
 			compatible = "shared-dma-pool";
+			no-map;
 			reg = <0 0x8cb00000 0 0x100000>;
 		};
 
@@ -3006,6 +3009,7 @@
 			     <0 424 0 /* CE10 */ >,
 			     <0 425 0 /* CE11 */ >;
 		qcom,wlan-msa-memory = <0x100000>;
+		qcom,wlan-msa-fixed-region = <&wlan_fw_region>;
 
 		vdd-0.8-cx-mx-supply = <&pm8998_l5>;
 		vdd-1.8-xo-supply = <&pm8998_l7>;
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts b/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
index 3580896..ef1b9e5 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
+++ b/arch/arm64/boot/dts/xilinx/zynqmp-ep108.dts
@@ -27,7 +27,7 @@
 		stdout-path = "serial0:115200n8";
 	};
 
-	memory {
+	memory@0 {
 		device_type = "memory";
 		reg = <0x0 0x0 0x0 0x40000000>;
 	};
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
index 68a90833..54dc283 100644
--- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
+++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi
@@ -72,7 +72,7 @@
 			     <1 10 0xf08>;
 	};
 
-	amba_apu {
+	amba_apu: amba_apu@0 {
 		compatible = "simple-bus";
 		#address-cells = <2>;
 		#size-cells = <1>;
@@ -175,7 +175,7 @@
 		};
 
 		i2c0: i2c@ff020000 {
-			compatible = "cdns,i2c-r1p10";
+			compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
 			status = "disabled";
 			interrupt-parent = <&gic>;
 			interrupts = <0 17 4>;
@@ -185,7 +185,7 @@
 		};
 
 		i2c1: i2c@ff030000 {
-			compatible = "cdns,i2c-r1p10";
+			compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
 			status = "disabled";
 			interrupt-parent = <&gic>;
 			interrupts = <0 18 4>;
diff --git a/arch/arm64/include/asm/debugv8.h b/arch/arm64/include/asm/debugv8.h
new file mode 100644
index 0000000..e32de80
--- /dev/null
+++ b/arch/arm64/include/asm/debugv8.h
@@ -0,0 +1,229 @@
+/* Copyright (c) 2014, 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 __ASM_DEBUGV8_H
+#define __ASM_DEBUGV8_H
+
+#include <linux/types.h>
+
+/* 32 bit register reads for aarch 64 bit */
+#define dbg_readl(reg)			RSYSL_##reg()
+/* 64 bit register reads for aarch 64 bit */
+#define dbg_readq(reg)			RSYSQ_##reg()
+/* 32 and 64 bit register writes for aarch 64 bit */
+#define dbg_write(val, reg)		WSYS_##reg(val)
+
+#define MRSL(reg)				\
+({						\
+uint32_t val;					\
+asm volatile("mrs %0, "#reg : "=r" (val));	\
+val;						\
+})
+
+#define MRSQ(reg)				\
+({						\
+uint64_t val;					\
+asm volatile("mrs %0, "#reg : "=r" (val));	\
+val;						\
+})
+
+#define MSR(val, reg)				\
+({						\
+asm volatile("msr "#reg", %0" : : "r" (val));	\
+})
+
+/*
+ * Debug Feature Register
+ *
+ * Read only
+ */
+#define RSYSQ_ID_AA64DFR0_EL1()		MRSQ(ID_AA64DFR0_EL1)
+
+/*
+ * Debug Registers
+ *
+ * Available only in DBGv8
+ *
+ * Read only
+ * MDCCSR_EL0, MDRAR_EL1, OSLSR_EL1, DBGDTRRX_EL0, DBGAUTHSTATUS_EL1
+ *
+ * Write only
+ * DBGDTRTX_EL0, OSLAR_EL1
+ */
+/* 32 bit registers */
+#define RSYSL_DBGDTRRX_EL0()		MRSL(DBGDTRRX_EL0)
+#define RSYSL_MDCCSR_EL0()		MRSL(MDCCSR_EL0)
+#define RSYSL_MDSCR_EL1()		MRSL(MDSCR_EL1)
+#define RSYSL_OSDTRRX_EL1()		MRSL(OSDTRRX_EL1)
+#define RSYSL_OSDTRTX_EL1()		MRSL(OSDTRTX_EL1)
+#define RSYSL_OSDLR_EL1()		MRSL(OSDLR_EL1)
+#define RSYSL_OSLSR_EL1()		MRSL(OSLSR_EL1)
+#define RSYSL_MDCCINT_EL1()		MRSL(MDCCINT_EL1)
+#define RSYSL_OSECCR_EL1()		MRSL(OSECCR_EL1)
+#define RSYSL_DBGPRCR_EL1()		MRSL(DBGPRCR_EL1)
+#define RSYSL_DBGBCR0_EL1()		MRSL(DBGBCR0_EL1)
+#define RSYSL_DBGBCR1_EL1()		MRSL(DBGBCR1_EL1)
+#define RSYSL_DBGBCR2_EL1()		MRSL(DBGBCR2_EL1)
+#define RSYSL_DBGBCR3_EL1()		MRSL(DBGBCR3_EL1)
+#define RSYSL_DBGBCR4_EL1()		MRSL(DBGBCR4_EL1)
+#define RSYSL_DBGBCR5_EL1()		MRSL(DBGBCR5_EL1)
+#define RSYSL_DBGBCR6_EL1()		MRSL(DBGBCR6_EL1)
+#define RSYSL_DBGBCR7_EL1()		MRSL(DBGBCR7_EL1)
+#define RSYSL_DBGBCR8_EL1()		MRSL(DBGBCR8_EL1)
+#define RSYSL_DBGBCR9_EL1()		MRSL(DBGBCR9_EL1)
+#define RSYSL_DBGBCR10_EL1()		MRSL(DBGBCR10_EL1)
+#define RSYSL_DBGBCR11_EL1()		MRSL(DBGBCR11_EL1)
+#define RSYSL_DBGBCR12_EL1()		MRSL(DBGBCR12_EL1)
+#define RSYSL_DBGBCR13_EL1()		MRSL(DBGBCR13_EL1)
+#define RSYSL_DBGBCR14_EL1()		MRSL(DBGBCR14_EL1)
+#define RSYSL_DBGBCR15_EL1()		MRSL(DBGBCR15_EL1)
+#define RSYSL_DBGWCR0_EL1()		MRSL(DBGWCR0_EL1)
+#define RSYSL_DBGWCR1_EL1()		MRSL(DBGWCR1_EL1)
+#define RSYSL_DBGWCR2_EL1()		MRSL(DBGWCR2_EL1)
+#define RSYSL_DBGWCR3_EL1()		MRSL(DBGWCR3_EL1)
+#define RSYSL_DBGWCR4_EL1()		MRSL(DBGWCR4_EL1)
+#define RSYSL_DBGWCR5_EL1()		MRSL(DBGWCR5_EL1)
+#define RSYSL_DBGWCR6_EL1()		MRSL(DBGWCR6_EL1)
+#define RSYSL_DBGWCR7_EL1()		MRSL(DBGWCR7_EL1)
+#define RSYSL_DBGWCR8_EL1()		MRSL(DBGWCR8_EL1)
+#define RSYSL_DBGWCR9_EL1()		MRSL(DBGWCR9_EL1)
+#define RSYSL_DBGWCR10_EL1()		MRSL(DBGWCR10_EL1)
+#define RSYSL_DBGWCR11_EL1()		MRSL(DBGWCR11_EL1)
+#define RSYSL_DBGWCR12_EL1()		MRSL(DBGWCR12_EL1)
+#define RSYSL_DBGWCR13_EL1()		MRSL(DBGWCR13_EL1)
+#define RSYSL_DBGWCR14_EL1()		MRSL(DBGWCR14_EL1)
+#define RSYSL_DBGWCR15_EL1()		MRSL(DBGWCR15_EL1)
+#define RSYSL_DBGCLAIMSET_EL1()		MRSL(DBGCLAIMSET_EL1)
+#define RSYSL_DBGCLAIMCLR_EL1()		MRSL(DBGCLAIMCLR_EL1)
+#define RSYSL_DBGAUTHSTATUS_EL1()	MRSL(DBGAUTHSTATUS_EL1)
+#define RSYSL_DBGVCR32_EL2()		MRSL(DBGVCR32_EL2)
+#define RSYSL_MDCR_EL2()		MRSL(MDCR_EL2)
+#define RSYSL_MDCR_EL3()		MRSL(MDCR_EL3)
+/* 64 bit registers */
+#define RSYSQ_DBGDTR_EL0()		MRSQ(DBGDTR_EL0)
+#define RSYSQ_MDRAR_EL1()		MRSQ(MDRAR_EL1)
+#define RSYSQ_DBGBVR0_EL1()		MRSQ(DBGBVR0_EL1)
+#define RSYSQ_DBGBVR1_EL1()		MRSQ(DBGBVR1_EL1)
+#define RSYSQ_DBGBVR2_EL1()		MRSQ(DBGBVR2_EL1)
+#define RSYSQ_DBGBVR3_EL1()		MRSQ(DBGBVR3_EL1)
+#define RSYSQ_DBGBVR4_EL1()		MRSQ(DBGBVR4_EL1)
+#define RSYSQ_DBGBVR5_EL1()		MRSQ(DBGBVR5_EL1)
+#define RSYSQ_DBGBVR6_EL1()		MRSQ(DBGBVR6_EL1)
+#define RSYSQ_DBGBVR7_EL1()		MRSQ(DBGBVR7_EL1)
+#define RSYSQ_DBGBVR8_EL1()		MRSQ(DBGBVR8_EL1)
+#define RSYSQ_DBGBVR9_EL1()		MRSQ(DBGBVR9_EL1)
+#define RSYSQ_DBGBVR10_EL1()		MRSQ(DBGBVR10_EL1)
+#define RSYSQ_DBGBVR11_EL1()		MRSQ(DBGBVR11_EL1)
+#define RSYSQ_DBGBVR12_EL1()		MRSQ(DBGBVR12_EL1)
+#define RSYSQ_DBGBVR13_EL1()		MRSQ(DBGBVR13_EL1)
+#define RSYSQ_DBGBVR14_EL1()		MRSQ(DBGBVR14_EL1)
+#define RSYSQ_DBGBVR15_EL1()		MRSQ(DBGBVR15_EL1)
+#define RSYSQ_DBGWVR0_EL1()		MRSQ(DBGWVR0_EL1)
+#define RSYSQ_DBGWVR1_EL1()		MRSQ(DBGWVR1_EL1)
+#define RSYSQ_DBGWVR2_EL1()		MRSQ(DBGWVR2_EL1)
+#define RSYSQ_DBGWVR3_EL1()		MRSQ(DBGWVR3_EL1)
+#define RSYSQ_DBGWVR4_EL1()		MRSQ(DBGWVR4_EL1)
+#define RSYSQ_DBGWVR5_EL1()		MRSQ(DBGWVR5_EL1)
+#define RSYSQ_DBGWVR6_EL1()		MRSQ(DBGWVR6_EL1)
+#define RSYSQ_DBGWVR7_EL1()		MRSQ(DBGWVR7_EL1)
+#define RSYSQ_DBGWVR8_EL1()		MRSQ(DBGWVR8_EL1)
+#define RSYSQ_DBGWVR9_EL1()		MRSQ(DBGWVR9_EL1)
+#define RSYSQ_DBGWVR10_EL1()		MRSQ(DBGWVR10_EL1)
+#define RSYSQ_DBGWVR11_EL1()		MRSQ(DBGWVR11_EL1)
+#define RSYSQ_DBGWVR12_EL1()		MRSQ(DBGWVR12_EL1)
+#define RSYSQ_DBGWVR13_EL1()		MRSQ(DBGWVR13_EL1)
+#define RSYSQ_DBGWVR14_EL1()		MRSQ(DBGWVR14_EL1)
+#define RSYSQ_DBGWVR15_EL1()		MRSQ(DBGWVR15_EL1)
+
+/* 32 bit registers */
+#define WSYS_DBGDTRTX_EL0(val)		MSR(val, DBGDTRTX_EL0)
+#define WSYS_MDCCINT_EL1(val)		MSR(val, MDCCINT_EL1)
+#define WSYS_MDSCR_EL1(val)		MSR(val, MDSCR_EL1)
+#define WSYS_OSDTRRX_EL1(val)		MSR(val, OSDTRRX_EL1)
+#define WSYS_OSDTRTX_EL1(val)		MSR(val, OSDTRTX_EL1)
+#define WSYS_OSDLR_EL1(val)		MSR(val, OSDLR_EL1)
+#define WSYS_OSECCR_EL1(val)		MSR(val, OSECCR_EL1)
+#define WSYS_DBGPRCR_EL1(val)		MSR(val, DBGPRCR_EL1)
+#define WSYS_DBGBCR0_EL1(val)		MSR(val, DBGBCR0_EL1)
+#define WSYS_DBGBCR1_EL1(val)		MSR(val, DBGBCR1_EL1)
+#define WSYS_DBGBCR2_EL1(val)		MSR(val, DBGBCR2_EL1)
+#define WSYS_DBGBCR3_EL1(val)		MSR(val, DBGBCR3_EL1)
+#define WSYS_DBGBCR4_EL1(val)		MSR(val, DBGBCR4_EL1)
+#define WSYS_DBGBCR5_EL1(val)		MSR(val, DBGBCR5_EL1)
+#define WSYS_DBGBCR6_EL1(val)		MSR(val, DBGBCR6_EL1)
+#define WSYS_DBGBCR7_EL1(val)		MSR(val, DBGBCR7_EL1)
+#define WSYS_DBGBCR8_EL1(val)		MSR(val, DBGBCR8_EL1)
+#define WSYS_DBGBCR9_EL1(val)		MSR(val, DBGBCR9_EL1)
+#define WSYS_DBGBCR10_EL1(val)		MSR(val, DBGBCR10_EL1)
+#define WSYS_DBGBCR11_EL1(val)		MSR(val, DBGBCR11_EL1)
+#define WSYS_DBGBCR12_EL1(val)		MSR(val, DBGBCR12_EL1)
+#define WSYS_DBGBCR13_EL1(val)		MSR(val, DBGBCR13_EL1)
+#define WSYS_DBGBCR14_EL1(val)		MSR(val, DBGBCR14_EL1)
+#define WSYS_DBGBCR15_EL1(val)		MSR(val, DBGBCR15_EL1)
+#define WSYS_DBGWCR0_EL1(val)		MSR(val, DBGWCR0_EL1)
+#define WSYS_DBGWCR1_EL1(val)		MSR(val, DBGWCR1_EL1)
+#define WSYS_DBGWCR2_EL1(val)		MSR(val, DBGWCR2_EL1)
+#define WSYS_DBGWCR3_EL1(val)		MSR(val, DBGWCR3_EL1)
+#define WSYS_DBGWCR4_EL1(val)		MSR(val, DBGWCR4_EL1)
+#define WSYS_DBGWCR5_EL1(val)		MSR(val, DBGWCR5_EL1)
+#define WSYS_DBGWCR6_EL1(val)		MSR(val, DBGWCR6_EL1)
+#define WSYS_DBGWCR7_EL1(val)		MSR(val, DBGWCR7_EL1)
+#define WSYS_DBGWCR8_EL1(val)		MSR(val, DBGWCR8_EL1)
+#define WSYS_DBGWCR9_EL1(val)		MSR(val, DBGWCR9_EL1)
+#define WSYS_DBGWCR10_EL1(val)		MSR(val, DBGWCR10_EL1)
+#define WSYS_DBGWCR11_EL1(val)		MSR(val, DBGWCR11_EL1)
+#define WSYS_DBGWCR12_EL1(val)		MSR(val, DBGWCR12_EL1)
+#define WSYS_DBGWCR13_EL1(val)		MSR(val, DBGWCR13_EL1)
+#define WSYS_DBGWCR14_EL1(val)		MSR(val, DBGWCR14_EL1)
+#define WSYS_DBGWCR15_EL1(val)		MSR(val, DBGWCR15_EL1)
+#define WSYS_DBGCLAIMSET_EL1(val)	MSR(val, DBGCLAIMSET_EL1)
+#define WSYS_DBGCLAIMCLR_EL1(val)	MSR(val, DBGCLAIMCLR_EL1)
+#define WSYS_OSLAR_EL1(val)		MSR(val, OSLAR_EL1)
+#define WSYS_DBGVCR32_EL2(val)		MSR(val, DBGVCR32_EL2)
+#define WSYS_MDCR_EL2(val)		MSR(val, MDCR_EL2)
+#define WSYS_MDCR_EL3(val)		MSR(val, MDCR_EL3)
+/* 64 bit registers */
+#define WSYS_DBGDTR_EL0(val)		MSR(val, DBGDTR_EL0)
+#define WSYS_DBGBVR0_EL1(val)		MSR(val, DBGBVR0_EL1)
+#define WSYS_DBGBVR1_EL1(val)		MSR(val, DBGBVR1_EL1)
+#define WSYS_DBGBVR2_EL1(val)		MSR(val, DBGBVR2_EL1)
+#define WSYS_DBGBVR3_EL1(val)		MSR(val, DBGBVR3_EL1)
+#define WSYS_DBGBVR4_EL1(val)		MSR(val, DBGBVR4_EL1)
+#define WSYS_DBGBVR5_EL1(val)		MSR(val, DBGBVR5_EL1)
+#define WSYS_DBGBVR6_EL1(val)		MSR(val, DBGBVR6_EL1)
+#define WSYS_DBGBVR7_EL1(val)		MSR(val, DBGBVR7_EL1)
+#define WSYS_DBGBVR8_EL1(val)		MSR(val, DBGBVR8_EL1)
+#define WSYS_DBGBVR9_EL1(val)		MSR(val, DBGBVR9_EL1)
+#define WSYS_DBGBVR10_EL1(val)		MSR(val, DBGBVR10_EL1)
+#define WSYS_DBGBVR11_EL1(val)		MSR(val, DBGBVR11_EL1)
+#define WSYS_DBGBVR12_EL1(val)		MSR(val, DBGBVR12_EL1)
+#define WSYS_DBGBVR13_EL1(val)		MSR(val, DBGBVR13_EL1)
+#define WSYS_DBGBVR14_EL1(val)		MSR(val, DBGBVR14_EL1)
+#define WSYS_DBGBVR15_EL1(val)		MSR(val, DBGBVR15_EL1)
+#define WSYS_DBGWVR0_EL1(val)		MSR(val, DBGWVR0_EL1)
+#define WSYS_DBGWVR1_EL1(val)		MSR(val, DBGWVR1_EL1)
+#define WSYS_DBGWVR2_EL1(val)		MSR(val, DBGWVR2_EL1)
+#define WSYS_DBGWVR3_EL1(val)		MSR(val, DBGWVR3_EL1)
+#define WSYS_DBGWVR4_EL1(val)		MSR(val, DBGWVR4_EL1)
+#define WSYS_DBGWVR5_EL1(val)		MSR(val, DBGWVR5_EL1)
+#define WSYS_DBGWVR6_EL1(val)		MSR(val, DBGWVR6_EL1)
+#define WSYS_DBGWVR7_EL1(val)		MSR(val, DBGWVR7_EL1)
+#define WSYS_DBGWVR8_EL1(val)		MSR(val, DBGWVR8_EL1)
+#define WSYS_DBGWVR9_EL1(val)		MSR(val, DBGWVR9_EL1)
+#define WSYS_DBGWVR10_EL1(val)		MSR(val, DBGWVR10_EL1)
+#define WSYS_DBGWVR11_EL1(val)		MSR(val, DBGWVR11_EL1)
+#define WSYS_DBGWVR12_EL1(val)		MSR(val, DBGWVR12_EL1)
+#define WSYS_DBGWVR13_EL1(val)		MSR(val, DBGWVR13_EL1)
+#define WSYS_DBGWVR14_EL1(val)		MSR(val, DBGWVR14_EL1)
+#define WSYS_DBGWVR15_EL1(val)		MSR(val, DBGWVR15_EL1)
+
+#endif
diff --git a/arch/arm64/include/asm/etmv4x.h b/arch/arm64/include/asm/etmv4x.h
new file mode 100644
index 0000000..4fb91ca
--- /dev/null
+++ b/arch/arm64/include/asm/etmv4x.h
@@ -0,0 +1,385 @@
+/* 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 __ASM_ETMV4X_H
+#define __ASM_ETMV4X_H
+
+#include <linux/types.h>
+
+/* 32 bit register reads for AArch64 */
+#define trc_readl(reg)			RSYSL_##reg()
+/* 64 bit register reads for AArch64 */
+#define trc_readq(reg)			RSYSQ_##reg()
+/* 32 and 64 bit register writes for AArch64 */
+#define trc_write(val, reg)		WSYS_##reg(val)
+
+#define MRSL(op0, op1, crn, crm, op2)					     \
+({									     \
+uint32_t val;								     \
+asm volatile("mrs %0, S"#op0"_"#op1"_"#crn"_"#crm"_"#op2 : "=r" (val));      \
+val;									     \
+})
+
+#define MRSQ(op0, op1, crn, crm, op2)					     \
+({									     \
+uint64_t val;								     \
+asm volatile("mrs %0, S"#op0"_"#op1"_"#crn"_"#crm"_"#op2 : "=r" (val));      \
+val;									     \
+})
+
+#define MSR(val, op0, op1, crn, crm, op2)				     \
+({									     \
+asm volatile("msr S"#op0"_"#op1"_"#crn"_"#crm"_"#op2", %0" : : "r" (val));   \
+})
+
+/* Clock and Power Management Register */
+#define RSYSL_CPMR_EL1()		MRSL(3, 7, c15, c0, 5)
+#define WSYS_CPMR_EL1(val)		MSR(val, 3, 7, c15, c0, 5)
+
+/*
+ * ETMv4 Registers
+ *
+ * Read only
+ * ETMAUTHSTATUS, ETMDEVARCH, ETMDEVID, ETMIDRn[0-13], ETMOSLSR, ETMSTATR
+ *
+ * Write only
+ * ETMOSLAR
+ */
+/* 32 bit registers */
+#define RSYSL_ETMAUTHSTATUS()		MRSL(2, 1, c7, c14, 6)
+#define RSYSL_ETMAUXCTLR()		MRSL(2, 1, c0, c6, 0)
+#define RSYSL_ETMCCCTLR()		MRSL(2, 1, c0, c14, 0)
+#define RSYSL_ETMCIDCCTLR0()		MRSL(2, 1, c3, c0, 2)
+#define RSYSL_ETMCNTCTLR0()		MRSL(2, 1, c0, c4, 5)
+#define RSYSL_ETMCNTCTLR1()		MRSL(2, 1, c0, c5, 5)
+#define RSYSL_ETMCNTCTLR2()		MRSL(2, 1, c0, c6, 5)
+#define RSYSL_ETMCNTCTLR3()		MRSL(2, 1, c0, c7, 5)
+#define RSYSL_ETMCNTRLDVR0()		MRSL(2, 1, c0, c0, 5)
+#define RSYSL_ETMCNTRLDVR1()		MRSL(2, 1, c0, c1, 5)
+#define RSYSL_ETMCNTRLDVR2()		MRSL(2, 1, c0, c2, 5)
+#define RSYSL_ETMCNTRLDVR3()		MRSL(2, 1, c0, c3, 5)
+#define RSYSL_ETMCNTVR0()		MRSL(2, 1, c0, c8, 5)
+#define RSYSL_ETMCNTVR1()		MRSL(2, 1, c0, c9, 5)
+#define RSYSL_ETMCNTVR2()		MRSL(2, 1, c0, c10, 5)
+#define RSYSL_ETMCNTVR3()		MRSL(2, 1, c0, c11, 5)
+#define RSYSL_ETMCONFIGR()		MRSL(2, 1, c0, c4, 0)
+#define RSYSL_ETMDEVARCH()		MRSL(2, 1, c7, c15, 6)
+#define RSYSL_ETMDEVID()		MRSL(2, 1, c7, c2, 7)
+#define RSYSL_ETMEVENTCTL0R()		MRSL(2, 1, c0, c8, 0)
+#define RSYSL_ETMEVENTCTL1R()		MRSL(2, 1, c0, c9, 0)
+#define RSYSL_ETMEXTINSELR()		MRSL(2, 1, c0, c8, 4)
+#define RSYSL_ETMIDR0()			MRSL(2, 1, c0, c8, 7)
+#define RSYSL_ETMIDR1()			MRSL(2, 1, c0, c9, 7)
+#define RSYSL_ETMIDR10()		MRSL(2, 1, c0, c2, 6)
+#define RSYSL_ETMIDR11()		MRSL(2, 1, c0, c3, 6)
+#define RSYSL_ETMIDR12()		MRSL(2, 1, c0, c4, 6)
+#define RSYSL_ETMIDR13()		MRSL(2, 1, c0, c5, 6)
+#define RSYSL_ETMIDR2()			MRSL(2, 1, c0, c10, 7)
+#define RSYSL_ETMIDR3()			MRSL(2, 1, c0, c11, 7)
+#define RSYSL_ETMIDR4()			MRSL(2, 1, c0, c12, 7)
+#define RSYSL_ETMIDR5()			MRSL(2, 1, c0, c13, 7)
+#define RSYSL_ETMIDR6()			MRSL(2, 1, c0, c14, 7)
+#define RSYSL_ETMIDR7()			MRSL(2, 1, c0, c15, 7)
+#define RSYSL_ETMIDR8()			MRSL(2, 1, c0, c0, 6)
+#define RSYSL_ETMIDR9()			MRSL(2, 1, c0, c1, 6)
+#define RSYSL_ETMIMSPEC0()		MRSL(2, 1, c0, c0, 7)
+#define RSYSL_ETMOSLSR()		MRSL(2, 1, c1, c1, 4)
+#define RSYSL_ETMPRGCTLR()		MRSL(2, 1, c0, c1, 0)
+#define RSYSL_ETMRSCTLR10()		MRSL(2, 1, c1, c10, 0)
+#define RSYSL_ETMRSCTLR11()		MRSL(2, 1, c1, c11, 0)
+#define RSYSL_ETMRSCTLR12()		MRSL(2, 1, c1, c12, 0)
+#define RSYSL_ETMRSCTLR13()		MRSL(2, 1, c1, c13, 0)
+#define RSYSL_ETMRSCTLR14()		MRSL(2, 1, c1, c14, 0)
+#define RSYSL_ETMRSCTLR15()		MRSL(2, 1, c1, c15, 0)
+#define RSYSL_ETMRSCTLR2()		MRSL(2, 1, c1, c2, 0)
+#define RSYSL_ETMRSCTLR3()		MRSL(2, 1, c1, c3, 0)
+#define RSYSL_ETMRSCTLR4()		MRSL(2, 1, c1, c4, 0)
+#define RSYSL_ETMRSCTLR5()		MRSL(2, 1, c1, c5, 0)
+#define RSYSL_ETMRSCTLR6()		MRSL(2, 1, c1, c6, 0)
+#define RSYSL_ETMRSCTLR7()		MRSL(2, 1, c1, c7, 0)
+#define RSYSL_ETMRSCTLR8()		MRSL(2, 1, c1, c8, 0)
+#define RSYSL_ETMRSCTLR9()		MRSL(2, 1, c1, c9, 0)
+#define RSYSL_ETMRSCTLR16()		MRSL(2, 1, c1, c0, 1)
+#define RSYSL_ETMRSCTLR17()		MRSL(2, 1, c1, c1, 1)
+#define RSYSL_ETMRSCTLR18()		MRSL(2, 1, c1, c2, 1)
+#define RSYSL_ETMRSCTLR19()		MRSL(2, 1, c1, c3, 1)
+#define RSYSL_ETMRSCTLR20()		MRSL(2, 1, c1, c4, 1)
+#define RSYSL_ETMRSCTLR21()		MRSL(2, 1, c1, c5, 1)
+#define RSYSL_ETMRSCTLR22()		MRSL(2, 1, c1, c6, 1)
+#define RSYSL_ETMRSCTLR23()		MRSL(2, 1, c1, c7, 1)
+#define RSYSL_ETMRSCTLR24()		MRSL(2, 1, c1, c8, 1)
+#define RSYSL_ETMRSCTLR25()		MRSL(2, 1, c1, c9, 1)
+#define RSYSL_ETMRSCTLR26()		MRSL(2, 1, c1, c10, 1)
+#define RSYSL_ETMRSCTLR27()		MRSL(2, 1, c1, c11, 1)
+#define RSYSL_ETMRSCTLR28()		MRSL(2, 1, c1, c12, 1)
+#define RSYSL_ETMRSCTLR29()		MRSL(2, 1, c1, c13, 1)
+#define RSYSL_ETMRSCTLR30()		MRSL(2, 1, c1, c14, 1)
+#define RSYSL_ETMRSCTLR31()		MRSL(2, 1, c1, c15, 1)
+#define RSYSL_ETMSEQEVR0()		MRSL(2, 1, c0, c0, 4)
+#define RSYSL_ETMSEQEVR1()		MRSL(2, 1, c0, c1, 4)
+#define RSYSL_ETMSEQEVR2()		MRSL(2, 1, c0, c2, 4)
+#define RSYSL_ETMSEQRSTEVR()		MRSL(2, 1, c0, c6, 4)
+#define RSYSL_ETMSEQSTR()		MRSL(2, 1, c0, c7, 4)
+#define RSYSL_ETMSTALLCTLR()		MRSL(2, 1, c0, c11, 0)
+#define RSYSL_ETMSTATR()		MRSL(2, 1, c0, c3, 0)
+#define RSYSL_ETMSYNCPR()		MRSL(2, 1, c0, c13, 0)
+#define RSYSL_ETMTRACEIDR()		MRSL(2, 1, c0, c0, 1)
+#define RSYSL_ETMTSCTLR()		MRSL(2, 1, c0, c12, 0)
+#define RSYSL_ETMVICTLR()		MRSL(2, 1, c0, c0, 2)
+#define RSYSL_ETMVIIECTLR()		MRSL(2, 1, c0, c1, 2)
+#define RSYSL_ETMVISSCTLR()		MRSL(2, 1, c0, c2, 2)
+#define RSYSL_ETMSSCCR0()		MRSL(2, 1, c1, c0, 2)
+#define RSYSL_ETMSSCCR1()		MRSL(2, 1, c1, c1, 2)
+#define RSYSL_ETMSSCCR2()		MRSL(2, 1, c1, c2, 2)
+#define RSYSL_ETMSSCCR3()		MRSL(2, 1, c1, c3, 2)
+#define RSYSL_ETMSSCCR4()		MRSL(2, 1, c1, c4, 2)
+#define RSYSL_ETMSSCCR5()		MRSL(2, 1, c1, c5, 2)
+#define RSYSL_ETMSSCCR6()		MRSL(2, 1, c1, c6, 2)
+#define RSYSL_ETMSSCCR7()		MRSL(2, 1, c1, c7, 2)
+#define RSYSL_ETMSSCSR0()		MRSL(2, 1, c1, c8, 2)
+#define RSYSL_ETMSSCSR1()		MRSL(2, 1, c1, c9, 2)
+#define RSYSL_ETMSSCSR2()		MRSL(2, 1, c1, c10, 2)
+#define RSYSL_ETMSSCSR3()		MRSL(2, 1, c1, c11, 2)
+#define RSYSL_ETMSSCSR4()		MRSL(2, 1, c1, c12, 2)
+#define RSYSL_ETMSSCSR5()		MRSL(2, 1, c1, c13, 2)
+#define RSYSL_ETMSSCSR6()		MRSL(2, 1, c1, c14, 2)
+#define RSYSL_ETMSSCSR7()		MRSL(2, 1, c1, c15, 2)
+#define RSYSL_ETMSSPCICR0()		MRSL(2, 1, c1, c0, 3)
+#define RSYSL_ETMSSPCICR1()		MRSL(2, 1, c1, c1, 3)
+#define RSYSL_ETMSSPCICR2()		MRSL(2, 1, c1, c2, 3)
+#define RSYSL_ETMSSPCICR3()		MRSL(2, 1, c1, c3, 3)
+#define RSYSL_ETMSSPCICR4()		MRSL(2, 1, c1, c4, 3)
+#define RSYSL_ETMSSPCICR5()		MRSL(2, 1, c1, c5, 3)
+#define RSYSL_ETMSSPCICR6()		MRSL(2, 1, c1, c6, 3)
+#define RSYSL_ETMSSPCICR7()		MRSL(2, 1, c1, c7, 3)
+
+/* 64 bit registers */
+#define RSYSQ_ETMACATR0()		MRSQ(2, 1, c2, c0, 2)
+#define RSYSQ_ETMACATR1()		MRSQ(2, 1, c2, c2, 2)
+#define RSYSQ_ETMACATR2()		MRSQ(2, 1, c2, c4, 2)
+#define RSYSQ_ETMACATR3()		MRSQ(2, 1, c2, c6, 2)
+#define RSYSQ_ETMACATR4()		MRSQ(2, 1, c2, c8, 2)
+#define RSYSQ_ETMACATR5()		MRSQ(2, 1, c2, c10, 2)
+#define RSYSQ_ETMACATR6()		MRSQ(2, 1, c2, c12, 2)
+#define RSYSQ_ETMACATR7()		MRSQ(2, 1, c2, c14, 2)
+#define RSYSQ_ETMACATR8()		MRSQ(2, 1, c2, c0, 3)
+#define RSYSQ_ETMACATR9()		MRSQ(2, 1, c2, c2, 3)
+#define RSYSQ_ETMACATR10()		MRSQ(2, 1, c2, c4, 3)
+#define RSYSQ_ETMACATR11()		MRSQ(2, 1, c2, c6, 3)
+#define RSYSQ_ETMACATR12()		MRSQ(2, 1, c2, c8, 3)
+#define RSYSQ_ETMACATR13()		MRSQ(2, 1, c2, c10, 3)
+#define RSYSQ_ETMACATR14()		MRSQ(2, 1, c2, c12, 3)
+#define RSYSQ_ETMACATR15()		MRSQ(2, 1, c2, c14, 3)
+#define RSYSQ_ETMCIDCVR0()		MRSQ(2, 1, c3, c0, 0)
+#define RSYSQ_ETMCIDCVR1()		MRSQ(2, 1, c3, c2, 0)
+#define RSYSQ_ETMCIDCVR2()		MRSQ(2, 1, c3, c4, 0)
+#define RSYSQ_ETMCIDCVR3()		MRSQ(2, 1, c3, c6, 0)
+#define RSYSQ_ETMCIDCVR4()		MRSQ(2, 1, c3, c8, 0)
+#define RSYSQ_ETMCIDCVR5()		MRSQ(2, 1, c3, c10, 0)
+#define RSYSQ_ETMCIDCVR6()		MRSQ(2, 1, c3, c12, 0)
+#define RSYSQ_ETMCIDCVR7()		MRSQ(2, 1, c3, c14, 0)
+#define RSYSQ_ETMACVR0()		MRSQ(2, 1, c2, c0, 0)
+#define RSYSQ_ETMACVR1()		MRSQ(2, 1, c2, c2, 0)
+#define RSYSQ_ETMACVR2()		MRSQ(2, 1, c2, c4, 0)
+#define RSYSQ_ETMACVR3()		MRSQ(2, 1, c2, c6, 0)
+#define RSYSQ_ETMACVR4()		MRSQ(2, 1, c2, c8, 0)
+#define RSYSQ_ETMACVR5()		MRSQ(2, 1, c2, c10, 0)
+#define RSYSQ_ETMACVR6()		MRSQ(2, 1, c2, c12, 0)
+#define RSYSQ_ETMACVR7()		MRSQ(2, 1, c2, c14, 0)
+#define RSYSQ_ETMACVR8()		MRSQ(2, 1, c2, c0, 1)
+#define RSYSQ_ETMACVR9()		MRSQ(2, 1, c2, c2, 1)
+#define RSYSQ_ETMACVR10()		MRSQ(2, 1, c2, c4, 1)
+#define RSYSQ_ETMACVR11()		MRSQ(2, 1, c2, c6, 1)
+#define RSYSQ_ETMACVR12()		MRSQ(2, 1, c2, c8, 1)
+#define RSYSQ_ETMACVR13()		MRSQ(2, 1, c2, c10, 1)
+#define RSYSQ_ETMACVR14()		MRSQ(2, 1, c2, c12, 1)
+#define RSYSQ_ETMACVR15()		MRSQ(2, 1, c2, c14, 1)
+#define RSYSQ_ETMVMIDCVR0()		MRSQ(2, 1, c3, c0, 1)
+#define RSYSQ_ETMVMIDCVR1()		MRSQ(2, 1, c3, c2, 1)
+#define RSYSQ_ETMVMIDCVR2()		MRSQ(2, 1, c3, c4, 1)
+#define RSYSQ_ETMVMIDCVR3()		MRSQ(2, 1, c3, c6, 1)
+#define RSYSQ_ETMVMIDCVR4()		MRSQ(2, 1, c3, c8, 1)
+#define RSYSQ_ETMVMIDCVR5()		MRSQ(2, 1, c3, c10, 1)
+#define RSYSQ_ETMVMIDCVR6()		MRSQ(2, 1, c3, c12, 1)
+#define RSYSQ_ETMVMIDCVR7()		MRSQ(2, 1, c3, c14, 1)
+#define RSYSQ_ETMDVCVR0()		MRSQ(2, 1, c2, c0, 4)
+#define RSYSQ_ETMDVCVR1()		MRSQ(2, 1, c2, c4, 4)
+#define RSYSQ_ETMDVCVR2()		MRSQ(2, 1, c2, c8, 4)
+#define RSYSQ_ETMDVCVR3()		MRSQ(2, 1, c2, c12, 4)
+#define RSYSQ_ETMDVCVR4()		MRSQ(2, 1, c2, c0, 5)
+#define RSYSQ_ETMDVCVR5()		MRSQ(2, 1, c2, c4, 5)
+#define RSYSQ_ETMDVCVR6()		MRSQ(2, 1, c2, c8, 5)
+#define RSYSQ_ETMDVCVR7()		MRSQ(2, 1, c2, c12, 5)
+#define RSYSQ_ETMDVCMR0()		MRSQ(2, 1, c2, c0, 6)
+#define RSYSQ_ETMDVCMR1()		MRSQ(2, 1, c2, c4, 6)
+#define RSYSQ_ETMDVCMR2()		MRSQ(2, 1, c2, c8, 6)
+#define RSYSQ_ETMDVCMR3()		MRSQ(2, 1, c2, c12, 6)
+#define RSYSQ_ETMDVCMR4()		MRSQ(2, 1, c2, c0, 7)
+#define RSYSQ_ETMDVCMR5()		MRSQ(2, 1, c2, c4, 7)
+#define RSYSQ_ETMDVCMR6()		MRSQ(2, 1, c2, c8, 7)
+#define RSYSQ_ETMDVCMR7()		MRSQ(2, 1, c2, c12, 7)
+
+/* 32 and 64 bit registers */
+#define WSYS_ETMAUXCTLR(val)		MSR(val, 2, 1, c0, c6, 0)
+#define WSYS_ETMACATR0(val)		MSR(val, 2, 1, c2, c0, 2)
+#define WSYS_ETMACATR1(val)		MSR(val, 2, 1, c2, c2, 2)
+#define WSYS_ETMACATR2(val)		MSR(val, 2, 1, c2, c4, 2)
+#define WSYS_ETMACATR3(val)		MSR(val, 2, 1, c2, c6, 2)
+#define WSYS_ETMACATR4(val)		MSR(val, 2, 1, c2, c8, 2)
+#define WSYS_ETMACATR5(val)		MSR(val, 2, 1, c2, c10, 2)
+#define WSYS_ETMACATR6(val)		MSR(val, 2, 1, c2, c12, 2)
+#define WSYS_ETMACATR7(val)		MSR(val, 2, 1, c2, c14, 2)
+#define WSYS_ETMACATR8(val)		MSR(val, 2, 1, c2, c0, 3)
+#define WSYS_ETMACATR9(val)		MSR(val, 2, 1, c2, c2, 3)
+#define WSYS_ETMACATR10(val)		MSR(val, 2, 1, c2, c4, 3)
+#define WSYS_ETMACATR11(val)		MSR(val, 2, 1, c2, c6, 3)
+#define WSYS_ETMACATR12(val)		MSR(val, 2, 1, c2, c8, 3)
+#define WSYS_ETMACATR13(val)		MSR(val, 2, 1, c2, c10, 3)
+#define WSYS_ETMACATR14(val)		MSR(val, 2, 1, c2, c12, 3)
+#define WSYS_ETMACATR15(val)		MSR(val, 2, 1, c2, c14, 3)
+#define WSYS_ETMACVR0(val)		MSR(val, 2, 1, c2, c0, 0)
+#define WSYS_ETMACVR1(val)		MSR(val, 2, 1, c2, c2, 0)
+#define WSYS_ETMACVR2(val)		MSR(val, 2, 1, c2, c4, 0)
+#define WSYS_ETMACVR3(val)		MSR(val, 2, 1, c2, c6, 0)
+#define WSYS_ETMACVR4(val)		MSR(val, 2, 1, c2, c8, 0)
+#define WSYS_ETMACVR5(val)		MSR(val, 2, 1, c2, c10, 0)
+#define WSYS_ETMACVR6(val)		MSR(val, 2, 1, c2, c12, 0)
+#define WSYS_ETMACVR7(val)		MSR(val, 2, 1, c2, c14, 0)
+#define WSYS_ETMACVR8(val)		MSR(val, 2, 1, c2, c0, 1)
+#define WSYS_ETMACVR9(val)		MSR(val, 2, 1, c2, c2, 1)
+#define WSYS_ETMACVR10(val)		MSR(val, 2, 1, c2, c4, 1)
+#define WSYS_ETMACVR11(val)		MSR(val, 2, 1, c2, c6, 1)
+#define WSYS_ETMACVR12(val)		MSR(val, 2, 1, c2, c8, 1)
+#define WSYS_ETMACVR13(val)		MSR(val, 2, 1, c2, c10, 1)
+#define WSYS_ETMACVR14(val)		MSR(val, 2, 1, c2, c12, 1)
+#define WSYS_ETMACVR15(val)		MSR(val, 2, 1, c2, c14, 1)
+#define WSYS_ETMCCCTLR(val)		MSR(val, 2, 1, c0, c14, 0)
+#define WSYS_ETMCIDCCTLR0(val)		MSR(val, 2, 1, c3, c0, 2)
+#define WSYS_ETMCIDCVR0(val)		MSR(val, 2, 1, c3, c0, 0)
+#define WSYS_ETMCIDCVR1(val)		MSR(val, 2, 1, c3, c2, 0)
+#define WSYS_ETMCIDCVR2(val)		MSR(val, 2, 1, c3, c4, 0)
+#define WSYS_ETMCIDCVR3(val)		MSR(val, 2, 1, c3, c6, 0)
+#define WSYS_ETMCIDCVR4(val)		MSR(val, 2, 1, c3, c8, 0)
+#define WSYS_ETMCIDCVR5(val)		MSR(val, 2, 1, c3, c10, 0)
+#define WSYS_ETMCIDCVR6(val)		MSR(val, 2, 1, c3, c12, 0)
+#define WSYS_ETMCIDCVR7(val)		MSR(val, 2, 1, c3, c14, 0)
+#define WSYS_ETMCNTCTLR0(val)		MSR(val, 2, 1, c0, c4, 5)
+#define WSYS_ETMCNTCTLR1(val)		MSR(val, 2, 1, c0, c5, 5)
+#define WSYS_ETMCNTCTLR2(val)		MSR(val, 2, 1, c0, c6, 5)
+#define WSYS_ETMCNTCTLR3(val)		MSR(val, 2, 1, c0, c7, 5)
+#define WSYS_ETMCNTRLDVR0(val)		MSR(val, 2, 1, c0, c0, 5)
+#define WSYS_ETMCNTRLDVR1(val)		MSR(val, 2, 1, c0, c1, 5)
+#define WSYS_ETMCNTRLDVR2(val)		MSR(val, 2, 1, c0, c2, 5)
+#define WSYS_ETMCNTRLDVR3(val)		MSR(val, 2, 1, c0, c3, 5)
+#define WSYS_ETMCNTVR0(val)		MSR(val, 2, 1, c0, c8, 5)
+#define WSYS_ETMCNTVR1(val)		MSR(val, 2, 1, c0, c9, 5)
+#define WSYS_ETMCNTVR2(val)		MSR(val, 2, 1, c0, c10, 5)
+#define WSYS_ETMCNTVR3(val)		MSR(val, 2, 1, c0, c11, 5)
+#define WSYS_ETMCONFIGR(val)		MSR(val, 2, 1, c0, c4, 0)
+#define WSYS_ETMEVENTCTL0R(val)		MSR(val, 2, 1, c0, c8, 0)
+#define WSYS_ETMEVENTCTL1R(val)		MSR(val, 2, 1, c0, c9, 0)
+#define WSYS_ETMEXTINSELR(val)		MSR(val, 2, 1, c0, c8, 4)
+#define WSYS_ETMIMSPEC0(val)		MSR(val, 2, 1, c0, c0, 7)
+#define WSYS_ETMOSLAR(val)		MSR(val, 2, 1, c1, c0, 4)
+#define WSYS_ETMPRGCTLR(val)		MSR(val, 2, 1, c0, c1, 0)
+#define WSYS_ETMRSCTLR10(val)		MSR(val, 2, 1, c1, c10, 0)
+#define WSYS_ETMRSCTLR11(val)		MSR(val, 2, 1, c1, c11, 0)
+#define WSYS_ETMRSCTLR12(val)		MSR(val, 2, 1, c1, c12, 0)
+#define WSYS_ETMRSCTLR13(val)		MSR(val, 2, 1, c1, c13, 0)
+#define WSYS_ETMRSCTLR14(val)		MSR(val, 2, 1, c1, c14, 0)
+#define WSYS_ETMRSCTLR15(val)		MSR(val, 2, 1, c1, c15, 0)
+#define WSYS_ETMRSCTLR2(val)		MSR(val, 2, 1, c1, c2, 0)
+#define WSYS_ETMRSCTLR3(val)		MSR(val, 2, 1, c1, c3, 0)
+#define WSYS_ETMRSCTLR4(val)		MSR(val, 2, 1, c1, c4, 0)
+#define WSYS_ETMRSCTLR5(val)		MSR(val, 2, 1, c1, c5, 0)
+#define WSYS_ETMRSCTLR6(val)		MSR(val, 2, 1, c1, c6, 0)
+#define WSYS_ETMRSCTLR7(val)		MSR(val, 2, 1, c1, c7, 0)
+#define WSYS_ETMRSCTLR8(val)		MSR(val, 2, 1, c1, c8, 0)
+#define WSYS_ETMRSCTLR9(val)		MSR(val, 2, 1, c1, c9, 0)
+#define WSYS_ETMRSCTLR16(val)		MSR(val, 2, 1, c1, c0, 1)
+#define WSYS_ETMRSCTLR17(val)		MSR(val, 2, 1, c1, c1, 1)
+#define WSYS_ETMRSCTLR18(val)		MSR(val, 2, 1, c1, c2, 1)
+#define WSYS_ETMRSCTLR19(val)		MSR(val, 2, 1, c1, c3, 1)
+#define WSYS_ETMRSCTLR20(val)		MSR(val, 2, 1, c1, c4, 1)
+#define WSYS_ETMRSCTLR21(val)		MSR(val, 2, 1, c1, c5, 1)
+#define WSYS_ETMRSCTLR22(val)		MSR(val, 2, 1, c1, c6, 1)
+#define WSYS_ETMRSCTLR23(val)		MSR(val, 2, 1, c1, c7, 1)
+#define WSYS_ETMRSCTLR24(val)		MSR(val, 2, 1, c1, c8, 1)
+#define WSYS_ETMRSCTLR25(val)		MSR(val, 2, 1, c1, c9, 1)
+#define WSYS_ETMRSCTLR26(val)		MSR(val, 2, 1, c1, c10, 1)
+#define WSYS_ETMRSCTLR27(val)		MSR(val, 2, 1, c1, c11, 1)
+#define WSYS_ETMRSCTLR28(val)		MSR(val, 2, 1, c1, c12, 1)
+#define WSYS_ETMRSCTLR29(val)		MSR(val, 2, 1, c1, c13, 1)
+#define WSYS_ETMRSCTLR30(val)		MSR(val, 2, 1, c1, c14, 1)
+#define WSYS_ETMRSCTLR31(val)		MSR(val, 2, 1, c1, c15, 1)
+#define WSYS_ETMSEQEVR0(val)		MSR(val, 2, 1, c0, c0, 4)
+#define WSYS_ETMSEQEVR1(val)		MSR(val, 2, 1, c0, c1, 4)
+#define WSYS_ETMSEQEVR2(val)		MSR(val, 2, 1, c0, c2, 4)
+#define WSYS_ETMSEQRSTEVR(val)		MSR(val, 2, 1, c0, c6, 4)
+#define WSYS_ETMSEQSTR(val)		MSR(val, 2, 1, c0, c7, 4)
+#define WSYS_ETMSTALLCTLR(val)		MSR(val, 2, 1, c0, c11, 0)
+#define WSYS_ETMSYNCPR(val)		MSR(val, 2, 1, c0, c13, 0)
+#define WSYS_ETMTRACEIDR(val)		MSR(val, 2, 1, c0, c0, 1)
+#define WSYS_ETMTSCTLR(val)		MSR(val, 2, 1, c0, c12, 0)
+#define WSYS_ETMVICTLR(val)		MSR(val, 2, 1, c0, c0, 2)
+#define WSYS_ETMVIIECTLR(val)		MSR(val, 2, 1, c0, c1, 2)
+#define WSYS_ETMVISSCTLR(val)		MSR(val, 2, 1, c0, c2, 2)
+#define WSYS_ETMVMIDCVR0(val)		MSR(val, 2, 1, c3, c0, 1)
+#define WSYS_ETMVMIDCVR1(val)		MSR(val, 2, 1, c3, c2, 1)
+#define WSYS_ETMVMIDCVR2(val)		MSR(val, 2, 1, c3, c4, 1)
+#define WSYS_ETMVMIDCVR3(val)		MSR(val, 2, 1, c3, c6, 1)
+#define WSYS_ETMVMIDCVR4(val)		MSR(val, 2, 1, c3, c8, 1)
+#define WSYS_ETMVMIDCVR5(val)		MSR(val, 2, 1, c3, c10, 1)
+#define WSYS_ETMVMIDCVR6(val)		MSR(val, 2, 1, c3, c12, 1)
+#define WSYS_ETMVMIDCVR7(val)		MSR(val, 2, 1, c3, c14, 1)
+#define WSYS_ETMDVCVR0(val)		MSR(val, 2, 1, c2, c0, 4)
+#define WSYS_ETMDVCVR1(val)		MSR(val, 2, 1, c2, c4, 4)
+#define WSYS_ETMDVCVR2(val)		MSR(val, 2, 1, c2, c8, 4)
+#define WSYS_ETMDVCVR3(val)		MSR(val, 2, 1, c2, c12, 4)
+#define WSYS_ETMDVCVR4(val)		MSR(val, 2, 1, c2, c0, 5)
+#define WSYS_ETMDVCVR5(val)		MSR(val, 2, 1, c2, c4, 5)
+#define WSYS_ETMDVCVR6(val)		MSR(val, 2, 1, c2, c8, 5)
+#define WSYS_ETMDVCVR7(val)		MSR(val, 2, 1, c2, c12, 5)
+#define WSYS_ETMDVCMR0(val)		MSR(val, 2, 1, c2, c0, 6)
+#define WSYS_ETMDVCMR1(val)		MSR(val, 2, 1, c2, c4, 6)
+#define WSYS_ETMDVCMR2(val)		MSR(val, 2, 1, c2, c8, 6)
+#define WSYS_ETMDVCMR3(val)		MSR(val, 2, 1, c2, c12, 6)
+#define WSYS_ETMDVCMR4(val)		MSR(val, 2, 1, c2, c0, 7)
+#define WSYS_ETMDVCMR5(val)		MSR(val, 2, 1, c2, c4, 7)
+#define WSYS_ETMDVCMR6(val)		MSR(val, 2, 1, c2, c8, 7)
+#define WSYS_ETMDVCMR7(val)		MSR(val, 2, 1, c2, c12, 7)
+#define WSYS_ETMSSCCR0(val)		MSR(val, 2, 1, c1, c0, 2)
+#define WSYS_ETMSSCCR1(val)		MSR(val, 2, 1, c1, c1, 2)
+#define WSYS_ETMSSCCR2(val)		MSR(val, 2, 1, c1, c2, 2)
+#define WSYS_ETMSSCCR3(val)		MSR(val, 2, 1, c1, c3, 2)
+#define WSYS_ETMSSCCR4(val)		MSR(val, 2, 1, c1, c4, 2)
+#define WSYS_ETMSSCCR5(val)		MSR(val, 2, 1, c1, c5, 2)
+#define WSYS_ETMSSCCR6(val)		MSR(val, 2, 1, c1, c6, 2)
+#define WSYS_ETMSSCCR7(val)		MSR(val, 2, 1, c1, c7, 2)
+#define WSYS_ETMSSCSR0(val)		MSR(val, 2, 1, c1, c8, 2)
+#define WSYS_ETMSSCSR1(val)		MSR(val, 2, 1, c1, c9, 2)
+#define WSYS_ETMSSCSR2(val)		MSR(val, 2, 1, c1, c10, 2)
+#define WSYS_ETMSSCSR3(val)		MSR(val, 2, 1, c1, c11, 2)
+#define WSYS_ETMSSCSR4(val)		MSR(val, 2, 1, c1, c12, 2)
+#define WSYS_ETMSSCSR5(val)		MSR(val, 2, 1, c1, c13, 2)
+#define WSYS_ETMSSCSR6(val)		MSR(val, 2, 1, c1, c14, 2)
+#define WSYS_ETMSSCSR7(val)		MSR(val, 2, 1, c1, c15, 2)
+#define WSYS_ETMSSPCICR0(val)		MSR(val, 2, 1, c1, c0, 3)
+#define WSYS_ETMSSPCICR1(val)		MSR(val, 2, 1, c1, c1, 3)
+#define WSYS_ETMSSPCICR2(val)		MSR(val, 2, 1, c1, c2, 3)
+#define WSYS_ETMSSPCICR3(val)		MSR(val, 2, 1, c1, c3, 3)
+#define WSYS_ETMSSPCICR4(val)		MSR(val, 2, 1, c1, c4, 3)
+#define WSYS_ETMSSPCICR5(val)		MSR(val, 2, 1, c1, c5, 3)
+#define WSYS_ETMSSPCICR6(val)		MSR(val, 2, 1, c1, c6, 3)
+#define WSYS_ETMSSPCICR7(val)		MSR(val, 2, 1, c1, c7, 3)
+
+#endif
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 7b670f1..f2fe96f 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -420,6 +420,11 @@
 	return &cpu_topology[cpu].core_sibling;
 }
 
+static int cpu_cpu_flags(void)
+{
+	return SD_ASYM_CPUCAPACITY;
+}
+
 static inline int cpu_corepower_flags(void)
 {
 	return SD_SHARE_PKG_RESOURCES  | SD_SHARE_POWERDOMAIN | \
@@ -430,7 +435,7 @@
 #ifdef CONFIG_SCHED_MC
 	{ cpu_coregroup_mask, cpu_corepower_flags, cpu_core_energy, SD_INIT_NAME(MC) },
 #endif
-	{ cpu_cpu_mask, NULL, cpu_cluster_energy, SD_INIT_NAME(DIE) },
+	{ cpu_cpu_mask, cpu_cpu_flags, cpu_cluster_energy, SD_INIT_NAME(DIE) },
 	{ NULL, },
 };
 
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index b6b81f8..7f9501a 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -103,21 +103,21 @@
 			break;
 
 		pud = pud_offset(pgd, addr);
-		printk(", *pud=%016llx", pud_val(*pud));
+		pr_cont(", *pud=%016llx", pud_val(*pud));
 		if (pud_none(*pud) || pud_bad(*pud))
 			break;
 
 		pmd = pmd_offset(pud, addr);
-		printk(", *pmd=%016llx", pmd_val(*pmd));
+		pr_cont(", *pmd=%016llx", pmd_val(*pmd));
 		if (pmd_none(*pmd) || pmd_bad(*pmd))
 			break;
 
 		pte = pte_offset_map(pmd, addr);
-		printk(", *pte=%016llx", pte_val(*pte));
+		pr_cont(", *pte=%016llx", pte_val(*pte));
 		pte_unmap(pte);
 	} while(0);
 
-	printk("\n");
+	pr_cont("\n");
 }
 
 #ifdef CONFIG_ARM64_HW_AFDBM
diff --git a/arch/openrisc/kernel/vmlinux.lds.S b/arch/openrisc/kernel/vmlinux.lds.S
index d68b9ed..c50609a 100644
--- a/arch/openrisc/kernel/vmlinux.lds.S
+++ b/arch/openrisc/kernel/vmlinux.lds.S
@@ -38,6 +38,8 @@
         /* Read-only sections, merged into text segment: */
         . = LOAD_BASE ;
 
+	_text = .;
+
 	/* _s_kernel_ro must be page aligned */
 	. = ALIGN(PAGE_SIZE);
 	_s_kernel_ro = .;
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 53ec75f..c721ea2 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -452,8 +452,8 @@
 	  before it can be accessed through the kernel mapping. */
 	preempt_disable();
 	flush_dcache_page_asm(__pa(vfrom), vaddr);
-	preempt_enable();
 	copy_page_asm(vto, vfrom);
+	preempt_enable();
 }
 EXPORT_SYMBOL(copy_user_page);
 
@@ -538,6 +538,10 @@
 	struct vm_area_struct *vma;
 	pgd_t *pgd;
 
+	/* Flush the TLB to avoid speculation if coherency is required. */
+	if (parisc_requires_coherency())
+		flush_tlb_all();
+
 	/* Flushing the whole cache on each cpu takes forever on
 	   rp3440, etc.  So, avoid it if the mm isn't too big.  */
 	if (mm_total_size(mm) >= parisc_cache_flush_threshold) {
@@ -594,33 +598,22 @@
 void flush_cache_range(struct vm_area_struct *vma,
 		unsigned long start, unsigned long end)
 {
-	unsigned long addr;
-	pgd_t *pgd;
-
 	BUG_ON(!vma->vm_mm->context);
 
+	/* Flush the TLB to avoid speculation if coherency is required. */
+	if (parisc_requires_coherency())
+		flush_tlb_range(vma, start, end);
+
 	if ((end - start) >= parisc_cache_flush_threshold) {
 		flush_cache_all();
 		return;
 	}
 
-	if (vma->vm_mm->context == mfsp(3)) {
-		flush_user_dcache_range_asm(start, end);
-		if (vma->vm_flags & VM_EXEC)
-			flush_user_icache_range_asm(start, end);
-		return;
-	}
+	BUG_ON(vma->vm_mm->context != mfsp(3));
 
-	pgd = vma->vm_mm->pgd;
-	for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
-		unsigned long pfn;
-		pte_t *ptep = get_ptep(pgd, addr);
-		if (!ptep)
-			continue;
-		pfn = pte_pfn(*ptep);
-		if (pfn_valid(pfn))
-			__flush_cache_page(vma, addr, PFN_PHYS(pfn));
-	}
+	flush_user_dcache_range_asm(start, end);
+	if (vma->vm_flags & VM_EXEC)
+		flush_user_icache_range_asm(start, end);
 }
 
 void
@@ -629,7 +622,8 @@
 	BUG_ON(!vma->vm_mm->context);
 
 	if (pfn_valid(pfn)) {
-		flush_tlb_page(vma, vmaddr);
+		if (parisc_requires_coherency())
+			flush_tlb_page(vma, vmaddr);
 		__flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
 	}
 }
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index e7ffde2..7593787 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -50,6 +50,7 @@
 #include <linux/uaccess.h>
 #include <linux/rcupdate.h>
 #include <linux/random.h>
+#include <linux/nmi.h>
 
 #include <asm/io.h>
 #include <asm/asm-offsets.h>
@@ -142,6 +143,7 @@
 
 	/* prevent soft lockup/stalled CPU messages for endless loop. */
 	rcu_sysrq_start();
+	lockup_detector_suspend();
 	for (;;);
 }
 
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 3297715..8b3b46b 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -44,22 +44,8 @@
 extern int sysfs_add_device_to_node(struct device *dev, int nid);
 extern void sysfs_remove_device_from_node(struct device *dev, int nid);
 
-static inline int early_cpu_to_node(int cpu)
-{
-	int nid;
-
-	nid = numa_cpu_lookup_table[cpu];
-
-	/*
-	 * Fall back to node 0 if nid is unset (it should be, except bugs).
-	 * This allows callers to safely do NODE_DATA(early_cpu_to_node(cpu)).
-	 */
-	return (nid < 0) ? 0 : nid;
-}
 #else
 
-static inline int early_cpu_to_node(int cpu) { return 0; }
-
 static inline void dump_numa_cpu_topology(void) {}
 
 static inline int sysfs_add_device_to_node(struct device *dev, int nid)
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index ada71be..a12be60 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -595,7 +595,7 @@
 
 static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
 {
-	return __alloc_bootmem_node(NODE_DATA(early_cpu_to_node(cpu)), size, align,
+	return __alloc_bootmem_node(NODE_DATA(cpu_to_node(cpu)), size, align,
 				    __pa(MAX_DMA_ADDRESS));
 }
 
@@ -606,7 +606,7 @@
 
 static int pcpu_cpu_distance(unsigned int from, unsigned int to)
 {
-	if (early_cpu_to_node(from) == early_cpu_to_node(to))
+	if (cpu_to_node(from) == cpu_to_node(to))
 		return LOCAL_DISTANCE;
 	else
 		return REMOTE_DISTANCE;
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 5c02984..218cba2 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -2808,6 +2808,8 @@
 	int r;
 	int srcu_idx;
 	unsigned long ebb_regs[3] = {};	/* shut up GCC */
+	unsigned long user_tar = 0;
+	unsigned int user_vrsave;
 
 	if (!vcpu->arch.sane) {
 		run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
@@ -2828,6 +2830,8 @@
 			run->fail_entry.hardware_entry_failure_reason = 0;
 			return -EINVAL;
 		}
+		/* Enable TM so we can read the TM SPRs */
+		mtmsr(mfmsr() | MSR_TM);
 		current->thread.tm_tfhar = mfspr(SPRN_TFHAR);
 		current->thread.tm_tfiar = mfspr(SPRN_TFIAR);
 		current->thread.tm_texasr = mfspr(SPRN_TEXASR);
@@ -2856,12 +2860,14 @@
 
 	flush_all_to_thread(current);
 
-	/* Save userspace EBB register values */
+	/* Save userspace EBB and other register values */
 	if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
 		ebb_regs[0] = mfspr(SPRN_EBBHR);
 		ebb_regs[1] = mfspr(SPRN_EBBRR);
 		ebb_regs[2] = mfspr(SPRN_BESCR);
+		user_tar = mfspr(SPRN_TAR);
 	}
+	user_vrsave = mfspr(SPRN_VRSAVE);
 
 	vcpu->arch.wqp = &vcpu->arch.vcore->wq;
 	vcpu->arch.pgdir = current->mm->pgd;
@@ -2885,12 +2891,15 @@
 			r = kvmppc_xics_rm_complete(vcpu, 0);
 	} while (is_kvmppc_resume_guest(r));
 
-	/* Restore userspace EBB register values */
+	/* Restore userspace EBB and other register values */
 	if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
 		mtspr(SPRN_EBBHR, ebb_regs[0]);
 		mtspr(SPRN_EBBRR, ebb_regs[1]);
 		mtspr(SPRN_BESCR, ebb_regs[2]);
+		mtspr(SPRN_TAR, user_tar);
+		mtspr(SPRN_FSCR, current->thread.fscr);
 	}
+	mtspr(SPRN_VRSAVE, user_vrsave);
 
  out:
 	vcpu->arch.state = KVMPPC_VCPU_NOTREADY;
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 6f81adb..0447a22 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -37,6 +37,13 @@
 #define NAPPING_CEDE	1
 #define NAPPING_NOVCPU	2
 
+/* Stack frame offsets for kvmppc_hv_entry */
+#define SFS			112
+#define STACK_SLOT_TRAP		(SFS-4)
+#define STACK_SLOT_CIABR	(SFS-16)
+#define STACK_SLOT_DAWR		(SFS-24)
+#define STACK_SLOT_DAWRX	(SFS-32)
+
 /*
  * Call kvmppc_hv_entry in real mode.
  * Must be called with interrupts hard-disabled.
@@ -289,10 +296,10 @@
 	bl	kvmhv_accumulate_time
 #endif
 13:	mr	r3, r12
-	stw	r12, 112-4(r1)
+	stw	r12, STACK_SLOT_TRAP(r1)
 	bl	kvmhv_commence_exit
 	nop
-	lwz	r12, 112-4(r1)
+	lwz	r12, STACK_SLOT_TRAP(r1)
 	b	kvmhv_switch_to_host
 
 /*
@@ -537,7 +544,7 @@
 	 */
 	mflr	r0
 	std	r0, PPC_LR_STKOFF(r1)
-	stdu	r1, -112(r1)
+	stdu	r1, -SFS(r1)
 
 	/* Save R1 in the PACA */
 	std	r1, HSTATE_HOST_R1(r13)
@@ -698,6 +705,16 @@
 	mtspr	SPRN_PURR,r7
 	mtspr	SPRN_SPURR,r8
 
+	/* Save host values of some registers */
+BEGIN_FTR_SECTION
+	mfspr	r5, SPRN_CIABR
+	mfspr	r6, SPRN_DAWR
+	mfspr	r7, SPRN_DAWRX
+	std	r5, STACK_SLOT_CIABR(r1)
+	std	r6, STACK_SLOT_DAWR(r1)
+	std	r7, STACK_SLOT_DAWRX(r1)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+
 BEGIN_FTR_SECTION
 	/* Set partition DABR */
 	/* Do this before re-enabling PMU to avoid P7 DABR corruption bug */
@@ -1361,8 +1378,7 @@
 	 */
 	li	r0, 0
 	mtspr	SPRN_IAMR, r0
-	mtspr	SPRN_CIABR, r0
-	mtspr	SPRN_DAWRX, r0
+	mtspr	SPRN_PSPB, r0
 	mtspr	SPRN_TCSCR, r0
 	mtspr	SPRN_WORT, r0
 	/* Set MMCRS to 1<<31 to freeze and disable the SPMC counters */
@@ -1378,6 +1394,7 @@
 	std	r6,VCPU_UAMOR(r9)
 	li	r6,0
 	mtspr	SPRN_AMR,r6
+	mtspr	SPRN_UAMOR, r6
 
 	/* Switch DSCR back to host value */
 	mfspr	r8, SPRN_DSCR
@@ -1519,6 +1536,16 @@
 	slbia
 	ptesync
 
+	/* Restore host values of some registers */
+BEGIN_FTR_SECTION
+	ld	r5, STACK_SLOT_CIABR(r1)
+	ld	r6, STACK_SLOT_DAWR(r1)
+	ld	r7, STACK_SLOT_DAWRX(r1)
+	mtspr	SPRN_CIABR, r5
+	mtspr	SPRN_DAWR, r6
+	mtspr	SPRN_DAWRX, r7
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+
 	/*
 	 * POWER7/POWER8 guest -> host partition switch code.
 	 * We don't have to lock against tlbies but we do
@@ -1652,8 +1679,8 @@
 	li	r0, KVM_GUEST_MODE_NONE
 	stb	r0, HSTATE_IN_GUEST(r13)
 
-	ld	r0, 112+PPC_LR_STKOFF(r1)
-	addi	r1, r1, 112
+	ld	r0, SFS+PPC_LR_STKOFF(r1)
+	addi	r1, r1, SFS
 	mtlr	r0
 	blr
 
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index cc66c49..666ad06 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -82,7 +82,6 @@
 
 	of_detach_node(np);
 	of_node_put(parent);
-	of_node_put(np); /* Must decrement the refcount */
 	return 0;
 }
 
diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c
index fec8a46..1076c9a 100644
--- a/arch/x86/events/intel/cstate.c
+++ b/arch/x86/events/intel/cstate.c
@@ -434,6 +434,7 @@
 	.stop		= cstate_pmu_event_stop,
 	.read		= cstate_pmu_event_update,
 	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+	.module		= THIS_MODULE,
 };
 
 static struct pmu cstate_pkg_pmu = {
@@ -447,6 +448,7 @@
 	.stop		= cstate_pmu_event_stop,
 	.read		= cstate_pmu_event_update,
 	.capabilities	= PERF_PMU_CAP_NO_INTERRUPT,
+	.module		= THIS_MODULE,
 };
 
 static const struct cstate_model nhm_cstates __initconst = {
diff --git a/arch/x86/events/intel/rapl.c b/arch/x86/events/intel/rapl.c
index 8b902b6..970c1de 100644
--- a/arch/x86/events/intel/rapl.c
+++ b/arch/x86/events/intel/rapl.c
@@ -697,6 +697,7 @@
 	rapl_pmus->pmu.start		= rapl_pmu_event_start;
 	rapl_pmus->pmu.stop		= rapl_pmu_event_stop;
 	rapl_pmus->pmu.read		= rapl_pmu_event_read;
+	rapl_pmus->pmu.module		= THIS_MODULE;
 	return 0;
 }
 
diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c
index 19d646a..aec6cc9 100644
--- a/arch/x86/events/intel/uncore.c
+++ b/arch/x86/events/intel/uncore.c
@@ -733,6 +733,7 @@
 			.start		= uncore_pmu_event_start,
 			.stop		= uncore_pmu_event_stop,
 			.read		= uncore_pmu_event_read,
+			.module		= THIS_MODULE,
 		};
 	} else {
 		pmu->pmu = *pmu->type->pmu;
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 3dfca7b..a5b47c1 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -955,6 +955,9 @@
 	const char *name = get_name(bank, NULL);
 	int err = 0;
 
+	if (!dev)
+		return -ENODEV;
+
 	if (is_shared_bank(bank)) {
 		nb = node_to_amd_nb(amd_get_nb_id(cpu));
 
diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile
index dd6cfa4..75029d0 100644
--- a/arch/x86/platform/intel-mid/device_libs/Makefile
+++ b/arch/x86/platform/intel-mid/device_libs/Makefile
@@ -15,7 +15,7 @@
 obj-$(subst m,y,$(CONFIG_GPIO_INTEL_PMIC)) += platform_pmic_gpio.o
 obj-$(subst m,y,$(CONFIG_INTEL_MFLD_THERMAL)) += platform_msic_thermal.o
 # SPI Devices
-obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_spidev.o
+obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_mrfld_spidev.o
 # I2C Devices
 obj-$(subst m,y,$(CONFIG_SENSORS_EMC1403)) += platform_emc1403.o
 obj-$(subst m,y,$(CONFIG_SENSORS_LIS3LV02D)) += platform_lis331.o
diff --git a/arch/x86/platform/intel-mid/device_libs/platform_spidev.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_spidev.c
similarity index 91%
rename from arch/x86/platform/intel-mid/device_libs/platform_spidev.c
rename to arch/x86/platform/intel-mid/device_libs/platform_mrfld_spidev.c
index 30c601b..27186ad 100644
--- a/arch/x86/platform/intel-mid/device_libs/platform_spidev.c
+++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_spidev.c
@@ -11,6 +11,7 @@
  * of the License.
  */
 
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/sfi.h>
 #include <linux/spi/pxa2xx_spi.h>
@@ -34,6 +35,9 @@
 {
 	struct spi_board_info *spi_info = info;
 
+	if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER)
+		return ERR_PTR(-ENODEV);
+
 	spi_info->mode = SPI_MODE_0;
 	spi_info->controller_data = &spidev_spi_chip;
 
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
index 121010a..18c94e1 100644
--- a/crypto/authencesn.c
+++ b/crypto/authencesn.c
@@ -248,6 +248,9 @@
 	u8 *ihash = ohash + crypto_ahash_digestsize(auth);
 	u32 tmp[2];
 
+	if (!authsize)
+		goto decrypt;
+
 	/* Move high-order bits of sequence number back. */
 	scatterwalk_map_and_copy(tmp, dst, 4, 4, 0);
 	scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0);
@@ -256,6 +259,8 @@
 	if (crypto_memneq(ihash, ohash, authsize))
 		return -EBADMSG;
 
+decrypt:
+
 	sg_init_table(areq_ctx->dst, 2);
 	dst = scatterwalk_ffwd(areq_ctx->dst, dst, assoclen);
 
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 5ea5dc2..73c9c7f 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -98,7 +98,15 @@
 	if (check_children && list_empty(&adev->children))
 		return -ENODEV;
 
-	return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
+	/*
+	 * If the device has a _HID (or _CID) returning a valid ACPI/PNP
+	 * device ID, it is better to make it look less attractive here, so that
+	 * the other device with the same _ADR value (that may not have a valid
+	 * device ID) can be matched going forward.  [This means a second spec
+	 * violation in a row, so whatever we do here is best effort anyway.]
+	 */
+	return sta_present && list_empty(&adev->pnp.ids) ?
+			FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
 }
 
 struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 632c814..88edacd 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -1013,7 +1013,7 @@
 {
 	struct binder_thread *thread;
 
-	BUG_ON(!spin_is_locked(&proc->inner_lock));
+	assert_spin_locked(&proc->inner_lock);
 	thread = list_first_entry_or_null(&proc->waiting_threads,
 					  struct binder_thread,
 					  waiting_thread_node);
@@ -1044,7 +1044,7 @@
 					 struct binder_thread *thread,
 					 bool sync)
 {
-	BUG_ON(!spin_is_locked(&proc->inner_lock));
+	assert_spin_locked(&proc->inner_lock);
 
 	if (thread) {
 		if (sync)
@@ -1223,7 +1223,7 @@
 	struct rb_node *n = proc->nodes.rb_node;
 	struct binder_node *node;
 
-	BUG_ON(!spin_is_locked(&proc->inner_lock));
+	assert_spin_locked(&proc->inner_lock);
 
 	while (n) {
 		node = rb_entry(n, struct binder_node, rb_node);
@@ -1269,7 +1269,8 @@
 	__u32 flags = fp ? fp->flags : 0;
 	s8 priority;
 
-	BUG_ON(!spin_is_locked(&proc->inner_lock));
+	assert_spin_locked(&proc->inner_lock);
+
 	while (*p) {
 
 		parent = *p;
@@ -1348,9 +1349,9 @@
 {
 	struct binder_proc *proc = node->proc;
 
-	BUG_ON(!spin_is_locked(&node->lock));
+	assert_spin_locked(&node->lock);
 	if (proc)
-		BUG_ON(!spin_is_locked(&proc->inner_lock));
+		assert_spin_locked(&proc->inner_lock);
 	if (strong) {
 		if (internal) {
 			if (target_list == NULL &&
@@ -1402,9 +1403,9 @@
 {
 	struct binder_proc *proc = node->proc;
 
-	BUG_ON(!spin_is_locked(&node->lock));
+	assert_spin_locked(&node->lock);
 	if (proc)
-		BUG_ON(!spin_is_locked(&proc->inner_lock));
+		assert_spin_locked(&proc->inner_lock);
 	if (strong) {
 		if (internal)
 			node->internal_strong_refs--;
@@ -1928,7 +1929,7 @@
 					   struct binder_transaction *t)
 {
 	BUG_ON(!target_thread);
-	BUG_ON(!spin_is_locked(&target_thread->proc->inner_lock));
+	assert_spin_locked(&target_thread->proc->inner_lock);
 	BUG_ON(target_thread->transaction_stack != t);
 	BUG_ON(target_thread->transaction_stack->from != target_thread);
 	target_thread->transaction_stack =
@@ -5071,7 +5072,6 @@
 	struct binder_proc *to_proc;
 	struct binder_buffer *buffer = t->buffer;
 
-	WARN_ON(!spin_is_locked(&proc->inner_lock));
 	spin_lock(&t->lock);
 	to_proc = t->to_proc;
 	seq_printf(m,
@@ -5160,7 +5160,6 @@
 	size_t start_pos = m->count;
 	size_t header_pos;
 
-	WARN_ON(!spin_is_locked(&thread->proc->inner_lock));
 	seq_printf(m, "  thread %d: l %02x need_return %d tr %d\n",
 			thread->pid, thread->looper,
 			thread->looper_need_return,
@@ -5197,10 +5196,6 @@
 	struct binder_work *w;
 	int count;
 
-	WARN_ON(!spin_is_locked(&node->lock));
-	if (node->proc)
-		WARN_ON(!spin_is_locked(&node->proc->inner_lock));
-
 	count = 0;
 	hlist_for_each_entry(ref, &node->refs, node_entry)
 		count++;
@@ -5227,7 +5222,6 @@
 static void print_binder_ref_olocked(struct seq_file *m,
 				     struct binder_ref *ref)
 {
-	WARN_ON(!spin_is_locked(&ref->proc->outer_lock));
 	binder_node_lock(ref->node);
 	seq_printf(m, "  ref %d: desc %d %snode %d s %d w %d d %pK\n",
 		   ref->data.debug_id, ref->data.desc,
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 4facc75..9093110 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -1162,10 +1162,11 @@
 			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
 			ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
 		} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
-			/* Set a long timer to let the reboot happens, but
-			   reboot if it hangs, but only if the watchdog
+			/* Set a long timer to let the reboot happen or
+			   reset if it hangs, but only if the watchdog
 			   timer was already running. */
-			timeout = 120;
+			if (timeout < 120)
+				timeout = 120;
 			pretimeout = 0;
 			ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
 			ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
index 1984d4a..3819959 100644
--- a/drivers/clk/qcom/camcc-sdm845.c
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -1959,6 +1959,7 @@
 static const struct of_device_id cam_cc_sdm845_match_table[] = {
 	{ .compatible = "qcom,cam_cc-sdm845" },
 	{ .compatible = "qcom,cam_cc-sdm845-v2" },
+	{ .compatible = "qcom,cam_cc-sdm670" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, cam_cc_sdm845_match_table);
@@ -1986,6 +1987,11 @@
 	cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 80000000;
 }
 
+static void cam_cc_sdm845_fixup_sdm670(void)
+{
+	cam_cc_sdm845_fixup_sdm845v2();
+}
+
 static int cam_cc_sdm845_fixup(struct platform_device *pdev)
 {
 	const char *compat = NULL;
@@ -1997,6 +2003,8 @@
 
 	if (!strcmp(compat, "qcom,cam_cc-sdm845-v2"))
 		cam_cc_sdm845_fixup_sdm845v2();
+	else if (!strcmp(compat, "qcom,cam_cc-sdm670"))
+		cam_cc_sdm845_fixup_sdm670();
 
 	return 0;
 }
diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c
index e1cda90..2109132 100644
--- a/drivers/clk/qcom/clk-rpmh.c
+++ b/drivers/clk/qcom/clk-rpmh.c
@@ -317,10 +317,32 @@
 
 static const struct of_device_id clk_rpmh_match_table[] = {
 	{ .compatible = "qcom,rpmh-clk-sdm845", .data = &clk_rpmh_sdm845},
+	{ .compatible = "qcom,rpmh-clk-sdm670", .data = &clk_rpmh_sdm845},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, clk_rpmh_match_table);
 
+static void clk_rpmh_sdm670_fixup_sdm670(void)
+{
+	sdm845_rpmh_clocks[RPMH_RF_CLK3] = NULL;
+	sdm845_rpmh_clocks[RPMH_RF_CLK3_A] = NULL;
+}
+
+static int clk_rpmh_sdm670_fixup(struct platform_device *pdev)
+{
+	const char *compat = NULL;
+	int compatlen = 0;
+
+	compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen);
+	if (!compat || (compatlen <= 0))
+		return -EINVAL;
+
+	if (!strcmp(compat, "qcom,rpmh-clk-sdm670"))
+		clk_rpmh_sdm670_fixup_sdm670();
+
+	return 0;
+}
+
 static int clk_rpmh_probe(struct platform_device *pdev)
 {
 	struct clk **clks;
@@ -388,6 +410,10 @@
 		goto err2;
 	}
 
+	ret = clk_rpmh_sdm670_fixup(pdev);
+	if (ret)
+		return ret;
+
 	hw_clks = desc->clks;
 	num_clks = desc->num_clks;
 
@@ -404,6 +430,11 @@
 	data->clk_num = num_clks;
 
 	for (i = 0; i < num_clks; i++) {
+		if (!hw_clks[i]) {
+			clks[i] = ERR_PTR(-ENOENT);
+			continue;
+		}
+
 		rpmh_clk = to_clk_rpmh(hw_clks[i]);
 		rpmh_clk->res_addr = cmd_db_get_addr(rpmh_clk->res_name);
 		if (!rpmh_clk->res_addr) {
diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c
index cb0cadd..ef1da5c 100644
--- a/drivers/clk/qcom/debugcc-sdm845.c
+++ b/drivers/clk/qcom/debugcc-sdm845.c
@@ -235,6 +235,9 @@
 	"gcc_video_ahb_clk",
 	"gcc_video_axi_clk",
 	"gcc_video_xo_clk",
+	"gcc_sdcc1_ahb_clk",
+	"gcc_sdcc1_apps_clk",
+	"gcc_sdcc1_ice_core_clk",
 	"gpu_cc_acd_cxo_clk",
 	"gpu_cc_ahb_clk",
 	"gpu_cc_crc_ahb_clk",
@@ -685,6 +688,12 @@
 			0x3F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
 		{ "gcc_video_xo_clk", 0x42, 4, GCC,
 			0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_sdcc1_ahb_clk", 0x15C, 4, GCC,
+			0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_sdcc1_apps_clk", 0x15B, 4, GCC,
+			0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+		{ "gcc_sdcc1_ice_core_clk", 0x15D, 4, GCC,
+			0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
 		{ "gpu_cc_acd_cxo_clk", 0x144, 4, GPU_CC,
 			0x1F, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
 		{ "gpu_cc_ahb_clk", 0x144, 4, GPU_CC,
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index 53bfe77..d57bf5f 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -1014,6 +1014,7 @@
 static const struct of_device_id disp_cc_sdm845_match_table[] = {
 	{ .compatible = "qcom,dispcc-sdm845" },
 	{ .compatible = "qcom,dispcc-sdm845-v2" },
+	{ .compatible = "qcom,dispcc-sdm670" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, disp_cc_sdm845_match_table);
@@ -1064,6 +1065,11 @@
 		430000000;
 }
 
+static void disp_cc_sdm845_fixup_sdm670(struct regmap *regmap)
+{
+	disp_cc_sdm845_fixup_sdm845v2(regmap);
+}
+
 static int disp_cc_sdm845_fixup(struct platform_device *pdev,
 						struct regmap *regmap)
 {
@@ -1076,6 +1082,8 @@
 
 	if (!strcmp(compat, "qcom,dispcc-sdm845-v2"))
 		disp_cc_sdm845_fixup_sdm845v2(regmap);
+	else if (!strcmp(compat, "qcom,dispcc-sdm670"))
+		disp_cc_sdm845_fixup_sdm670(regmap);
 
 	return 0;
 }
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 17b2403..a363235 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -198,6 +198,22 @@
 	"core_bi_pll_test_se",
 };
 
+static const struct parent_map gcc_parent_map_7[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_GPLL0_OUT_MAIN, 1 },
+	{ P_GPLL6_OUT_MAIN, 2 },
+	{ P_GPLL0_OUT_EVEN, 6 },
+	{ P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_11[] = {
+	"bi_tcxo",
+	"gpll0",
+	"gpll6",
+	"gpll0_out_even",
+	"core_bi_pll_test_se",
+};
+
 static struct clk_dummy measure_only_snoc_clk = {
 	.rrate = 1000,
 	.hw.init = &(struct clk_init_data){
@@ -301,6 +317,28 @@
 	},
 };
 
+static struct clk_alpha_pll gpll6 = {
+	.offset = 0x13000,
+	.vco_table = fabia_vco,
+	.num_vco = ARRAY_SIZE(fabia_vco),
+	.type = FABIA_PLL,
+	.clkr = {
+		.enable_reg = 0x52000,
+		.enable_mask = BIT(6),
+		.hw.init = &(struct clk_init_data){
+			.name = "gpll6",
+			.parent_names = (const char *[]){ "bi_tcxo" },
+			.num_parents = 1,
+			.ops = &clk_fabia_fixed_pll_ops,
+			VDD_CX_FMAX_MAP4(
+				MIN, 615000000,
+				LOW, 1066000000,
+				LOW_L1, 1600000000,
+				NOMINAL, 2000000000),
+		},
+	},
+};
+
 static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = {
 	F(19200000, P_BI_TCXO, 1, 0, 0),
 	{ }
@@ -330,6 +368,12 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src_sdm670[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = {
 	.cmd_rcgr = 0x4815c,
 	.mnd_width = 0,
@@ -862,6 +906,67 @@
 	},
 };
 
+static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = {
+	F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0),
+	F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+	F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+	F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
+	.cmd_rcgr = 0x26010,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_0,
+	.freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src,
+	.enable_safe_config = true,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gcc_sdcc1_ice_core_clk_src",
+		.parent_names = gcc_parent_names_0,
+		.num_parents = 4,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_ops,
+		VDD_CX_FMAX_MAP3(
+			MIN, 75000000,
+			LOW, 150000000,
+			NOMINAL, 300000000),
+	},
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = {
+	F(144000, P_BI_TCXO, 16, 3, 25),
+	F(400000, P_BI_TCXO, 12, 1, 4),
+	F(20000000, P_GPLL0_OUT_EVEN, 5, 1, 3),
+	F(25000000, P_GPLL0_OUT_EVEN, 6, 1, 2),
+	F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0),
+	F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0),
+	F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+	.cmd_rcgr = 0x26028,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_7,
+	.freq_tbl = ftbl_gcc_sdcc1_apps_clk_src,
+	.enable_safe_config = true,
+	.clkr.hw.init = &(struct clk_init_data){
+		.name = "gcc_sdcc1_apps_clk_src",
+		.parent_names = gcc_parent_names_11,
+		.num_parents = 5,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_ops,
+		VDD_CX_FMAX_MAP4(
+			MIN, 19200000,
+			LOWER, 50000000,
+			LOW, 100000000,
+			NOMINAL, 384000000),
+	},
+};
+
 static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
 	F(400000, P_BI_TCXO, 12, 1, 4),
 	F(9600000, P_BI_TCXO, 2, 0, 0),
@@ -904,17 +1009,28 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src_sdm670[] = {
+	F(400000, P_BI_TCXO, 12, 1, 4),
+	F(9600000, P_BI_TCXO, 2, 0, 0),
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0),
+	F(33333333, P_GPLL0_OUT_EVEN, 9, 0, 0),
+	F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
+	F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
 	.cmd_rcgr = 0x1600c,
 	.mnd_width = 8,
 	.hid_width = 5,
-	.parent_map = gcc_parent_map_3,
+	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_sdcc4_apps_clk_src,
 	.enable_safe_config = true,
 	.clkr.hw.init = &(struct clk_init_data){
 		.name = "gcc_sdcc4_apps_clk_src",
-		.parent_names = gcc_parent_names_3,
-		.num_parents = 3,
+		.parent_names = gcc_parent_names_0,
+		.num_parents = 4,
 		.flags = CLK_SET_RATE_PARENT,
 		.ops = &clk_rcg2_ops,
 		VDD_CX_FMAX_MAP4(
@@ -2700,6 +2816,55 @@
 	},
 };
 
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+	.halt_reg = 0x2600c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2600c,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ice_core_clk",
+			.parent_names = (const char *[]){
+				"gcc_sdcc1_ice_core_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+	.halt_reg = 0x26008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x26008,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+	.halt_reg = 0x26004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x26004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_sdcc1_apps_clk",
+			.parent_names = (const char *[]){
+				"gcc_sdcc1_apps_clk_src",
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch gcc_sdcc2_ahb_clk = {
 	.halt_reg = 0x14008,
 	.halt_check = BRANCH_HALT,
@@ -3824,6 +3989,12 @@
 	[GPLL0] = &gpll0.clkr,
 	[GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
 	[GPLL4] = &gpll4.clkr,
+	[GCC_SDCC1_AHB_CLK] = NULL,
+	[GCC_SDCC1_APPS_CLK] = NULL,
+	[GCC_SDCC1_ICE_CORE_CLK] = NULL,
+	[GCC_SDCC1_APPS_CLK_SRC] = NULL,
+	[GCC_SDCC1_ICE_CORE_CLK_SRC] = NULL,
+	[GPLL6] = NULL,
 };
 
 static const struct qcom_reset_map gcc_sdm845_resets[] = {
@@ -3853,6 +4024,7 @@
 	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
 	[GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
 	[GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
+	[GCC_SDCC1_BCR] = { 0x26000 },
 };
 
 /* List of RCG clocks and corresponding flags requested for DFS Mode */
@@ -3899,6 +4071,7 @@
 static const struct of_device_id gcc_sdm845_match_table[] = {
 	{ .compatible = "qcom,gcc-sdm845" },
 	{ .compatible = "qcom,gcc-sdm845-v2" },
+	{ .compatible = "qcom,gcc-sdm670" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
@@ -4009,6 +4182,86 @@
 		ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2;
 }
 
+static void gcc_sdm845_fixup_sdm670(void)
+{
+	gcc_sdm845_fixup_sdm845v2();
+
+	gcc_sdm845_clocks[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr;
+	gcc_sdm845_clocks[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr;
+	gcc_sdm845_clocks[GCC_SDCC1_ICE_CORE_CLK] =
+					&gcc_sdcc1_ice_core_clk.clkr;
+	gcc_sdm845_clocks[GCC_SDCC1_APPS_CLK_SRC] =
+					&gcc_sdcc1_apps_clk_src.clkr;
+	gcc_sdm845_clocks[GCC_SDCC1_ICE_CORE_CLK_SRC] =
+					&gcc_sdcc1_ice_core_clk_src.clkr;
+	gcc_sdm845_clocks[GPLL6] = &gpll6.clkr;
+	gcc_sdm845_clocks[GCC_AGGRE_UFS_CARD_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_AGGRE_USB3_SEC_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_AGGRE_NOC_PCIE_TBU_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_CFG_NOC_USB3_SEC_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_0_AUX_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_0_AUX_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_0_CFG_AHB_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_0_CLKREF_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_0_MSTR_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_0_PIPE_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_0_SLV_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_0_SLV_Q2A_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_1_AUX_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_1_AUX_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_1_CFG_AHB_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_1_CLKREF_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_1_MSTR_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_1_PIPE_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_1_SLV_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_1_SLV_Q2A_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_PHY_AUX_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_PHY_REFGEN_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_PCIE_PHY_REFGEN_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_AHB_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_AXI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_AXI_HW_CTL_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_AXI_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_CLKREF_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_RX_SYMBOL_0_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_RX_SYMBOL_1_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_TX_SYMBOL_0_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_UFS_PHY_RX_SYMBOL_1_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_USB30_SEC_MASTER_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_USB30_SEC_MASTER_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_USB30_SEC_MOCK_UTMI_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_USB30_SEC_SLEEP_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_USB3_SEC_CLKREF_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_USB3_SEC_PHY_AUX_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_USB3_SEC_PHY_AUX_CLK_SRC] = NULL;
+	gcc_sdm845_clocks[GCC_USB3_SEC_PHY_COM_AUX_CLK] = NULL;
+	gcc_sdm845_clocks[GCC_USB3_SEC_PHY_PIPE_CLK] = NULL;
+
+	gcc_cpuss_rbcpr_clk_src.freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src_sdm670;
+	gcc_cpuss_rbcpr_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+					50000000;
+	gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+					50000000;
+	gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
+					100000000;
+	gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] =
+					201500000;
+	gcc_sdcc4_apps_clk_src.freq_tbl = ftbl_gcc_sdcc4_apps_clk_src_sdm670;
+	gcc_sdcc4_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] =
+					33333333;
+}
+
 static int gcc_sdm845_fixup(struct platform_device *pdev)
 {
 	const char *compat = NULL;
@@ -4020,6 +4273,8 @@
 
 	if (!strcmp(compat, "qcom,gcc-sdm845-v2"))
 		gcc_sdm845_fixup_sdm845v2();
+	else if (!strcmp(compat, "qcom,gcc-sdm670"))
+		gcc_sdm845_fixup_sdm670();
 
 	return 0;
 }
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index cf4a8a5..db0dad1 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -224,6 +224,12 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src_sdm670[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 gpu_cc_gmu_clk_src = {
 	.cmd_rcgr = 0x1120,
 	.mnd_width = 0,
@@ -279,6 +285,18 @@
 	{ }
 };
 
+static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src_sdm670[] = {
+	F(180000000, P_CRC_DIV,  1, 0, 0),
+	F(267000000, P_CRC_DIV,  1, 0, 0),
+	F(355000000, P_CRC_DIV,  1, 0, 0),
+	F(430000000, P_CRC_DIV,  1, 0, 0),
+	F(565000000, P_CRC_DIV,  1, 0, 0),
+	F(650000000, P_CRC_DIV,  1, 0, 0),
+	F(750000000, P_CRC_DIV,  1, 0, 0),
+	F(780000000, P_CRC_DIV,  1, 0, 0),
+	{ }
+};
+
 static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = {
 	.cmd_rcgr = 0x101c,
 	.mnd_width = 0,
@@ -585,6 +603,7 @@
 static const struct of_device_id gpu_cc_sdm845_match_table[] = {
 	{ .compatible = "qcom,gpucc-sdm845" },
 	{ .compatible = "qcom,gpucc-sdm845-v2" },
+	{ .compatible = "qcom,gpucc-sdm670" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table);
@@ -592,6 +611,7 @@
 static const struct of_device_id gpu_cc_gfx_sdm845_match_table[] = {
 	{ .compatible = "qcom,gfxcc-sdm845" },
 	{ .compatible = "qcom,gfxcc-sdm845-v2" },
+	{ .compatible = "qcom,gfxcc-sdm670" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, gpu_cc_gfx_sdm845_match_table);
@@ -605,6 +625,15 @@
 	gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 500000000;
 }
 
+static void gpu_cc_sdm845_fixup_sdm670(struct regmap *regmap)
+{
+	gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr;
+	clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+
+	gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm670;
+	gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 0;
+}
+
 static void gpu_cc_gfx_sdm845_fixup_sdm845v2(void)
 {
 	gpu_cc_gx_gfx3d_clk_src.freq_tbl =
@@ -624,6 +653,28 @@
 				710000000;
 }
 
+static void gpu_cc_gfx_sdm845_fixup_sdm670(void)
+{
+	gpu_cc_gx_gfx3d_clk_src.freq_tbl =
+				ftbl_gpu_cc_gx_gfx3d_clk_src_sdm670;
+	gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_MIN] =
+				180000000;
+	gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOWER] =
+				267000000;
+	gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW] =
+				355000000;
+	gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW_L1] =
+				430000000;
+	gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL] =
+				565000000;
+	gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL_L1] =
+				650000000;
+	gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH] =
+				750000000;
+	gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH_L1] =
+				780000000;
+}
+
 static int gpu_cc_gfx_sdm845_fixup(struct platform_device *pdev)
 {
 	const char *compat = NULL;
@@ -635,6 +686,8 @@
 
 	if (!strcmp(compat, "qcom,gfxcc-sdm845-v2"))
 		gpu_cc_gfx_sdm845_fixup_sdm845v2();
+	else if (!strcmp(compat, "qcom,gfxcc-sdm670"))
+		gpu_cc_gfx_sdm845_fixup_sdm670();
 
 	return 0;
 }
@@ -651,6 +704,8 @@
 
 	if (!strcmp(compat, "qcom,gpucc-sdm845-v2"))
 		gpu_cc_sdm845_fixup_sdm845v2(regmap);
+	else if (!strcmp(compat, "qcom,gpucc-sdm670"))
+		gpu_cc_sdm845_fixup_sdm670(regmap);
 
 	return 0;
 }
diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c
index ba4e591..3311e9f 100644
--- a/drivers/clk/qcom/videocc-sdm845.c
+++ b/drivers/clk/qcom/videocc-sdm845.c
@@ -328,6 +328,7 @@
 static const struct of_device_id video_cc_sdm845_match_table[] = {
 	{ .compatible = "qcom,video_cc-sdm845" },
 	{ .compatible = "qcom,video_cc-sdm845-v2" },
+	{ .compatible = "qcom,video_cc-sdm670" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, video_cc_sdm845_match_table);
@@ -340,6 +341,12 @@
 		404000000;
 }
 
+static void video_cc_sdm845_fixup_sdm670(void)
+{
+	video_cc_sdm845_fixup_sdm845v2();
+
+}
+
 static int video_cc_sdm845_fixup(struct platform_device *pdev)
 {
 	const char *compat = NULL;
@@ -351,6 +358,8 @@
 
 	if (!strcmp(compat, "qcom,video_cc-sdm845-v2"))
 		video_cc_sdm845_fixup_sdm845v2();
+	else if (!strcmp(compat, "qcom,video_cc-sdm670"))
+		video_cc_sdm845_fixup_sdm670();
 
 	return 0;
 }
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index a6edf2f..c59e980 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -455,15 +455,11 @@
 	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
 	struct cpufreq_interactive_tunables *tunables =
 		ppol->policy->governor_data;
-	u64 now;
-	u64 now_idle;
-	unsigned int delta_idle;
-	unsigned int delta_time;
-	u64 active_time;
+	u64 now_idle, now, active_time, delta_idle, delta_time;
 
 	now_idle = get_cpu_idle_time(cpu, &now, tunables->io_is_busy);
-	delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle);
-	delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp);
+	delta_idle = (now_idle - pcpu->time_in_idle);
+	delta_time = (now - pcpu->time_in_idle_timestamp);
 
 	if (delta_time <= delta_idle)
 		active_time = 0;
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 4e3ca4f..5d2e918 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1346,6 +1346,8 @@
 	struct power_params *pwr_params;
 
 	pwr_params = &cpu->levels[idx].pwr;
+	sched_set_cpu_cstate(dev->cpu, idx + 1,
+			pwr_params->energy_overhead, pwr_params->latency_us);
 
 	cpu_prepare(cpu, idx, true);
 	cluster_prepare(cpu->parent, cpumask, idx, true, start_time);
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 586f954..40be374 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -546,7 +546,8 @@
 	struct dax_dev *dax_dev = to_dax_dev(dev);
 	struct dax_region *dax_region = dax_dev->region;
 
-	ida_simple_remove(&dax_region->ida, dax_dev->id);
+	if (dax_dev->id >= 0)
+		ida_simple_remove(&dax_region->ida, dax_dev->id);
 	ida_simple_remove(&dax_minor_ida, MINOR(dev->devt));
 	dax_region_put(dax_region);
 	iput(dax_dev->inode);
@@ -581,7 +582,7 @@
 }
 
 struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region,
-		struct resource *res, int count)
+		int id, struct resource *res, int count)
 {
 	struct device *parent = dax_region->dev;
 	struct dax_dev *dax_dev;
@@ -608,10 +609,16 @@
 	if (i < count)
 		goto err_id;
 
-	dax_dev->id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL);
-	if (dax_dev->id < 0) {
-		rc = dax_dev->id;
-		goto err_id;
+	if (id < 0) {
+		id = ida_simple_get(&dax_region->ida, 0, 0, GFP_KERNEL);
+		dax_dev->id = id;
+		if (id < 0) {
+			rc = id;
+			goto err_id;
+		}
+	} else {
+		/* region provider owns @id lifetime */
+		dax_dev->id = -1;
 	}
 
 	minor = ida_simple_get(&dax_minor_ida, 0, 0, GFP_KERNEL);
@@ -650,7 +657,7 @@
 	dev->parent = parent;
 	dev->groups = dax_attribute_groups;
 	dev->release = dax_dev_release;
-	dev_set_name(dev, "dax%d.%d", dax_region->id, dax_dev->id);
+	dev_set_name(dev, "dax%d.%d", dax_region->id, id);
 	rc = device_add(dev);
 	if (rc) {
 		kill_dax_dev(dax_dev);
@@ -669,7 +676,8 @@
  err_inode:
 	ida_simple_remove(&dax_minor_ida, minor);
  err_minor:
-	ida_simple_remove(&dax_region->ida, dax_dev->id);
+	if (dax_dev->id >= 0)
+		ida_simple_remove(&dax_region->ida, dax_dev->id);
  err_id:
 	kfree(dax_dev);
 
diff --git a/drivers/dax/dax.h b/drivers/dax/dax.h
index ddd829a..b5ed850 100644
--- a/drivers/dax/dax.h
+++ b/drivers/dax/dax.h
@@ -21,5 +21,5 @@
 		int region_id, struct resource *res, unsigned int align,
 		void *addr, unsigned long flags);
 struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region,
-		struct resource *res, int count);
+		int id, struct resource *res, int count);
 #endif /* __DAX_H__ */
diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c
index 73c6ce9..eebb357 100644
--- a/drivers/dax/pmem.c
+++ b/drivers/dax/pmem.c
@@ -58,13 +58,12 @@
 
 static int dax_pmem_probe(struct device *dev)
 {
-	int rc;
 	void *addr;
 	struct resource res;
 	struct dax_dev *dax_dev;
+	int rc, id, region_id;
 	struct nd_pfn_sb *pfn_sb;
 	struct dax_pmem *dax_pmem;
-	struct nd_region *nd_region;
 	struct nd_namespace_io *nsio;
 	struct dax_region *dax_region;
 	struct nd_namespace_common *ndns;
@@ -122,14 +121,17 @@
 	/* adjust the dax_region resource to the start of data */
 	res.start += le64_to_cpu(pfn_sb->dataoff);
 
-	nd_region = to_nd_region(dev->parent);
-	dax_region = alloc_dax_region(dev, nd_region->id, &res,
+	rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", &region_id, &id);
+	if (rc != 2)
+		return -EINVAL;
+
+	dax_region = alloc_dax_region(dev, region_id, &res,
 			le32_to_cpu(pfn_sb->align), addr, PFN_DEV|PFN_MAP);
 	if (!dax_region)
 		return -ENOMEM;
 
 	/* TODO: support for subdividing a dax region... */
-	dax_dev = devm_create_dax_dev(dax_region, &res, 1);
+	dax_dev = devm_create_dax_dev(dax_region, id, &res, 1);
 
 	/* child dax_dev instances now own the lifetime of the dax_region */
 	dax_region_put(dax_region);
diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c
index e1afa60..81d98d1 100644
--- a/drivers/devfreq/governor_memlat.c
+++ b/drivers/devfreq/governor_memlat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -244,7 +244,11 @@
 					hw->core_stats[i].mem_count,
 					hw->core_stats[i].freq, ratio);
 
-		if (ratio && ratio <= node->ratio_ceil
+		if (!hw->core_stats[i].inst_count
+		    || !hw->core_stats[i].freq)
+			continue;
+
+		if (ratio <= node->ratio_ceil
 		    && hw->core_stats[i].freq > max_freq) {
 			lat_dev = i;
 			max_freq = hw->core_stats[i].freq;
diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h
index 8e67895..abcc51b 100644
--- a/drivers/dma/ioat/hw.h
+++ b/drivers/dma/ioat/hw.h
@@ -64,6 +64,8 @@
 #define PCI_DEVICE_ID_INTEL_IOAT_BDX8	0x6f2e
 #define PCI_DEVICE_ID_INTEL_IOAT_BDX9	0x6f2f
 
+#define PCI_DEVICE_ID_INTEL_IOAT_SKX	0x2021
+
 #define IOAT_VER_1_2            0x12    /* Version 1.2 */
 #define IOAT_VER_2_0            0x20    /* Version 2.0 */
 #define IOAT_VER_3_0            0x30    /* Version 3.0 */
diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
index d235fbe..0dea6d55 100644
--- a/drivers/dma/ioat/init.c
+++ b/drivers/dma/ioat/init.c
@@ -106,6 +106,8 @@
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX8) },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX9) },
 
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SKX) },
+
 	/* I/OAT v3.3 platforms */
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD0) },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD1) },
@@ -243,10 +245,15 @@
 	}
 }
 
+static inline bool is_skx_ioat(struct pci_dev *pdev)
+{
+	return (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SKX) ? true : false;
+}
+
 static bool is_xeon_cb32(struct pci_dev *pdev)
 {
 	return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) ||
-		is_hsw_ioat(pdev) || is_bdx_ioat(pdev);
+		is_hsw_ioat(pdev) || is_bdx_ioat(pdev) || is_skx_ioat(pdev);
 }
 
 bool is_bwd_ioat(struct pci_dev *pdev)
@@ -1350,6 +1357,8 @@
 
 	device->version = readb(device->reg_base + IOAT_VER_OFFSET);
 	if (device->version >= IOAT_VER_3_0) {
+		if (is_skx_ioat(pdev))
+			device->version = IOAT_VER_3_2;
 		err = ioat3_dma_probe(device, ioat_dca_enabled);
 
 		if (device->version >= IOAT_VER_3_3)
diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c
index 3f24aeb..2403475 100644
--- a/drivers/dma/ti-dma-crossbar.c
+++ b/drivers/dma/ti-dma-crossbar.c
@@ -149,6 +149,7 @@
 	match = of_match_node(ti_am335x_master_match, dma_node);
 	if (!match) {
 		dev_err(&pdev->dev, "DMA master is not supported\n");
+		of_node_put(dma_node);
 		return -EINVAL;
 	}
 
@@ -339,6 +340,7 @@
 	match = of_match_node(ti_dra7_master_match, dma_node);
 	if (!match) {
 		dev_err(&pdev->dev, "DMA master is not supported\n");
+		of_node_put(dma_node);
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 961d47f..8214127 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -210,7 +210,14 @@
 void adreno_flush(struct msm_gpu *gpu)
 {
 	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
-	uint32_t wptr = get_wptr(gpu->rb);
+	uint32_t wptr;
+
+	/*
+	 * Mask wptr value that we calculate to fit in the HW range. This is
+	 * to account for the possibility that the last command fit exactly into
+	 * the ringbuffer and rb->next hasn't wrapped to zero yet
+	 */
+	wptr = get_wptr(gpu->rb) & ((gpu->rb->size / 4) - 1);
 
 	/* ensure writes to ringbuffer have hit system memory: */
 	mb();
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index c695dda..cc75fb5 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -109,7 +109,8 @@
 			pagefault_disable();
 		}
 
-		if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
+		if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) ||
+			!(submit_bo.flags & MSM_SUBMIT_BO_FLAGS)) {
 			DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
 			ret = -EINVAL;
 			goto out_unlock;
@@ -293,7 +294,7 @@
 {
 	uint32_t i, last_offset = 0;
 	uint32_t *ptr;
-	int ret;
+	int ret = 0;
 
 	if (offset % 4) {
 		DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
@@ -320,12 +321,13 @@
 
 		ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc));
 		if (ret)
-			return -EFAULT;
+			goto out;
 
 		if (submit_reloc.submit_offset % 4) {
 			DRM_ERROR("non-aligned reloc offset: %u\n",
 					submit_reloc.submit_offset);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 
 		/* offset in dwords: */
@@ -334,12 +336,13 @@
 		if ((off >= (obj->base.size / 4)) ||
 				(off < last_offset)) {
 			DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 
 		ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid);
 		if (ret)
-			return ret;
+			goto out;
 
 		if (valid)
 			continue;
@@ -356,9 +359,10 @@
 		last_offset = off;
 	}
 
+out:
 	msm_gem_put_vaddr_locked(&obj->base);
 
-	return 0;
+	return ret;
 }
 
 static void submit_cleanup(struct msm_gem_submit *submit)
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
index f326cf6..67b34e0 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -23,7 +23,8 @@
 	struct msm_ringbuffer *ring;
 	int ret;
 
-	size = ALIGN(size, 4);   /* size should be dword aligned */
+	if (WARN_ON(!is_power_of_2(size)))
+		return ERR_PTR(-EINVAL);
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 	if (!ring) {
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 0071352..8a46d66 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -2520,7 +2520,8 @@
 				phys->split_role == ENC_ROLE_SLAVE) &&
 				phys->split_role != ENC_ROLE_SKIP)
 			set_bit(i, sde_enc->frame_busy_mask);
-
+		if (phys->hw_ctl->ops.reg_dma_flush)
+			phys->hw_ctl->ops.reg_dma_flush(phys->hw_ctl);
 		if (!phys->ops.needs_single_flush ||
 				!phys->ops.needs_single_flush(phys))
 			_sde_encoder_trigger_flush(&sde_enc->base, phys, 0x0);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 0e1ab51..ccc4443 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -2944,33 +2944,25 @@
 
 	rc = sde_hardware_format_caps(sde_cfg, hw_rev);
 
-	switch (hw_rev) {
-	case SDE_HW_VER_170:
-	case SDE_HW_VER_171:
-	case SDE_HW_VER_172:
+	if (IS_MSM8996_TARGET(hw_rev)) {
 		/* update msm8996 target here */
 		sde_cfg->perf.min_prefill_lines = 21;
-		break;
-	case SDE_HW_VER_300:
-	case SDE_HW_VER_301:
+	} else if (IS_MSM8998_TARGET(hw_rev)) {
 		/* update msm8998 target here */
 		sde_cfg->has_wb_ubwc = true;
 		sde_cfg->perf.min_prefill_lines = 25;
 		sde_cfg->vbif_qos_nlvl = 4;
 		sde_cfg->ts_prefill_rev = 1;
-		sde_cfg->perf.min_prefill_lines = 25;
-		break;
-	case SDE_HW_VER_400:
+	} else if (IS_SDM845_TARGET(hw_rev)) {
 		/* update sdm845 target here */
 		sde_cfg->has_wb_ubwc = true;
 		sde_cfg->perf.min_prefill_lines = 24;
 		sde_cfg->vbif_qos_nlvl = 8;
 		sde_cfg->ts_prefill_rev = 2;
-		sde_cfg->perf.min_prefill_lines = 24;
-		break;
-	default:
+	} else {
+		SDE_ERROR("unsupported chipset id:%X\n", hw_rev);
 		sde_cfg->perf.min_prefill_lines = 0xffff;
-		break;
+		rc = -ENODEV;
 	}
 
 	return rc;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index fa10a88..48c3db7 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -45,7 +45,10 @@
 #define SDE_HW_VER_300	SDE_HW_VER(3, 0, 0) /* 8998 v1.0 */
 #define SDE_HW_VER_301	SDE_HW_VER(3, 0, 1) /* 8998 v1.1 */
 #define SDE_HW_VER_400	SDE_HW_VER(4, 0, 0) /* sdm845 v1.0 */
+#define SDE_HW_VER_401	SDE_HW_VER(4, 0, 1) /* sdm845 v2.0 */
 
+#define IS_MSM8996_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_170)
+#define IS_MSM8998_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_300)
 #define IS_SDM845_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400)
 
 #define SDE_HW_BLK_NAME_LEN	16
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 606fdeb..621a172 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -39,7 +39,7 @@
 #define CTL_FLUSH_MASK_ROT              BIT(27)
 #define CTL_FLUSH_MASK_CTL              BIT(17)
 
-#define SDE_REG_RESET_TIMEOUT_COUNT    20
+#define SDE_REG_RESET_TIMEOUT_US        2000
 
 static struct sde_ctl_cfg *_ctl_offset(enum sde_ctl ctl,
 		struct sde_mdss_cfg *m,
@@ -113,10 +113,6 @@
 
 static inline void sde_hw_ctl_trigger_flush(struct sde_hw_ctl *ctx)
 {
-	struct sde_hw_reg_dma_ops *ops = sde_reg_dma_get_ops();
-
-	if (ops && ops->last_command)
-		ops->last_command(ctx, DMA_CTL_QUEUE0);
 
 	SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
 }
@@ -302,14 +298,13 @@
 	return 0;
 }
 
-static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 count)
+static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 timeout_us)
 {
 	struct sde_hw_blk_reg_map *c = &ctx->hw;
+	ktime_t timeout;
 	u32 status;
 
-	/* protect to do at least one iteration */
-	if (!count)
-		count = 1;
+	timeout = ktime_add_us(ktime_get(), timeout_us);
 
 	/*
 	 * it takes around 30us to have mdp finish resetting its ctl path
@@ -317,10 +312,10 @@
 	 */
 	do {
 		status = SDE_REG_READ(c, CTL_SW_RESET);
-		status &= 0x01;
+		status &= 0x1;
 		if (status)
 			usleep_range(20, 50);
-	} while (status && --count > 0);
+	} while (status && ktime_compare_safe(ktime_get(), timeout) < 0);
 
 	return status;
 }
@@ -331,7 +326,7 @@
 
 	pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx);
 	SDE_REG_WRITE(c, CTL_SW_RESET, 0x1);
-	if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_COUNT))
+	if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_US))
 		return -EINVAL;
 
 	return 0;
@@ -348,7 +343,7 @@
 		return 0;
 
 	pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx);
-	if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_COUNT)) {
+	if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_US)) {
 		pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx);
 		return -EINVAL;
 	}
@@ -547,6 +542,14 @@
 	SDE_REG_WRITE(c, CTL_ROT_TOP, val);
 }
 
+static void sde_hw_reg_dma_flush(struct sde_hw_ctl *ctx)
+{
+	struct sde_hw_reg_dma_ops *ops = sde_reg_dma_get_ops();
+
+	if (ops && ops->last_command)
+		ops->last_command(ctx, DMA_CTL_QUEUE0);
+}
+
 static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
 		unsigned long cap)
 {
@@ -568,6 +571,8 @@
 	ops->get_bitmask_intf = sde_hw_ctl_get_bitmask_intf;
 	ops->get_bitmask_cdm = sde_hw_ctl_get_bitmask_cdm;
 	ops->get_bitmask_wb = sde_hw_ctl_get_bitmask_wb;
+	ops->reg_dma_flush = sde_hw_reg_dma_flush;
+
 	if (cap & BIT(SDE_CTL_SBUF)) {
 		ops->get_bitmask_rot = sde_hw_ctl_get_bitmask_rot;
 		ops->setup_sbuf_cfg = sde_hw_ctl_setup_sbuf_cfg;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index a111916..5d3ced3 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -206,6 +206,13 @@
 
 	void (*setup_sbuf_cfg)(struct sde_hw_ctl *ctx,
 		struct sde_ctl_sbuf_cfg *cfg);
+
+	/**
+	 * Flush the reg dma by sending last command.
+	 * @ctx       : ctl path ctx pointer
+	 */
+	void (*reg_dma_flush)(struct sde_hw_ctl *ctx);
+
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 9199048..4487d78 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -50,7 +50,6 @@
 			(cfg)->dma_buf->index)
 
 #define REG_DMA_DECODE_SEL 0x180AC060
-#define REG_DMA_LAST_CMD 0x180AC004
 #define SINGLE_REG_WRITE_OPCODE (BIT(28))
 #define REL_ADDR_OPCODE (BIT(27))
 #define HW_INDEX_REG_WRITE_OPCODE (BIT(28) | BIT(29))
@@ -471,7 +470,8 @@
 			cfg->dma_buf->iova);
 	SDE_REG_WRITE(&hw, reg_dma_ctl_queue_off[cfg->ctl->idx] + 0x4,
 			cmd1);
-	SDE_REG_WRITE(&cfg->ctl->hw, REG_DMA_CTL_TRIGGER_OFF,
+	if (cfg->last_command)
+		SDE_REG_WRITE(&cfg->ctl->hw, REG_DMA_CTL_TRIGGER_OFF,
 			queue_sel[cfg->queue_select]);
 
 	return 0;
@@ -754,8 +754,8 @@
 
 	loc =  (u32 *)((u8 *)cfg->dma_buf->vaddr +
 			cfg->dma_buf->index);
-	loc[0] = REG_DMA_LAST_CMD;
-	loc[1] = BIT(0);
+	loc[0] = REG_DMA_DECODE_SEL;
+	loc[1] = 0;
 	cfg->dma_buf->index = sizeof(u32) * 2;
 	cfg->dma_buf->ops_completed = REG_WRITE_OP | DECODE_SEL_OP;
 	cfg->dma_buf->next_op_allowed = REG_WRITE_OP;
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 3dbfdfc..1a6585a 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -2047,7 +2047,7 @@
 	} else {
 		sde_kms->reg_dma_len = msm_iomap_size(dev->platformdev,
 								"regdma_phys");
-		rc =  sde_dbg_reg_register_base("vbif_nrt",
+		rc =  sde_dbg_reg_register_base("reg_dma",
 				sde_kms->reg_dma,
 				sde_kms->reg_dma_len);
 		if (rc)
diff --git a/drivers/gpu/drm/msm/sde/sde_reg_dma.c b/drivers/gpu/drm/msm/sde/sde_reg_dma.c
index cc87aeb..e38524f 100644
--- a/drivers/gpu/drm/msm/sde/sde_reg_dma.c
+++ b/drivers/gpu/drm/msm/sde/sde_reg_dma.c
@@ -12,6 +12,7 @@
 
 #include "sde_reg_dma.h"
 #include "sde_hw_reg_dma_v1.h"
+#include "sde_dbg.h"
 
 static int default_check_support(enum sde_reg_dma_features feature,
 		     enum sde_reg_dma_blk blk,
@@ -98,6 +99,9 @@
 		rc = init_v1(&reg_dma);
 		if (rc)
 			DRM_DEBUG("init v1 dma ops failed\n");
+		else
+			sde_dbg_reg_register_base("reg_dma", addr,
+					reg_dma.caps->len);
 		break;
 	default:
 		break;
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 7e58c2f..768dfbd 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -3067,9 +3067,7 @@
 	memset(&dbg->dbgbus_sde, 0, sizeof(dbg->dbgbus_sde));
 	memset(&dbg->dbgbus_vbif_rt, 0, sizeof(dbg->dbgbus_vbif_rt));
 
-	switch (hwversion) {
-	case SDE_HW_VER_300:
-	case SDE_HW_VER_301:
+	if (IS_MSM8998_TARGET(hwversion)) {
 		dbg->dbgbus_sde.entries = dbg_bus_sde_8998;
 		dbg->dbgbus_sde.cmn.entries_size = ARRAY_SIZE(dbg_bus_sde_8998);
 		dbg->dbgbus_sde.cmn.flags = DBGBUS_FLAGS_DSPP;
@@ -3077,9 +3075,7 @@
 		dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
 		dbg->dbgbus_vbif_rt.cmn.entries_size =
 				ARRAY_SIZE(vbif_dbg_bus_msm8998);
-		break;
-
-	case SDE_HW_VER_400:
+	} else if (IS_SDM845_TARGET(hwversion)) {
 		dbg->dbgbus_sde.entries = dbg_bus_sde_sdm845;
 		dbg->dbgbus_sde.cmn.entries_size =
 				ARRAY_SIZE(dbg_bus_sde_sdm845);
@@ -3089,10 +3085,8 @@
 		dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
 		dbg->dbgbus_vbif_rt.cmn.entries_size =
 				ARRAY_SIZE(vbif_dbg_bus_msm8998);
-		break;
-	default:
-		pr_err("unsupported chipset id %u\n", hwversion);
-		break;
+	} else {
+		pr_err("unsupported chipset id %X\n", hwversion);
 	}
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
index 1e1de6b..5893be9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
@@ -27,7 +27,7 @@
 		u8 type[3];
 	} pior;
 
-	struct nv50_disp_chan *chan[17];
+	struct nv50_disp_chan *chan[21];
 };
 
 int nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
index c794b2c..6d8f212 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
@@ -129,7 +129,7 @@
 
 	if (bar->bar[0].mem) {
 		addr = nvkm_memory_addr(bar->bar[0].mem) >> 12;
-		nvkm_wr32(device, 0x001714, 0xc0000000 | addr);
+		nvkm_wr32(device, 0x001714, 0x80000000 | addr);
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 73c971e..ae125d0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -285,7 +285,6 @@
 
 	drm_kms_helper_poll_fini(ddev);
 	drm_mode_config_cleanup(ddev);
-	drm_vblank_cleanup(ddev);
 
 	drm_dev_unref(ddev);
 
@@ -305,7 +304,7 @@
 		return -ENODEV;
 	}
 
-	/* Allocate and initialize the DRM and R-Car device structures. */
+	/* Allocate and initialize the R-Car device structure. */
 	rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
 	if (rcdu == NULL)
 		return -ENOMEM;
@@ -315,6 +314,15 @@
 	rcdu->dev = &pdev->dev;
 	rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data;
 
+	platform_set_drvdata(pdev, rcdu);
+
+	/* I/O resources */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(rcdu->mmio))
+		return PTR_ERR(rcdu->mmio);
+
+	/* DRM/KMS objects */
 	ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev);
 	if (IS_ERR(ddev))
 		return PTR_ERR(ddev);
@@ -322,24 +330,6 @@
 	rcdu->ddev = ddev;
 	ddev->dev_private = rcdu;
 
-	platform_set_drvdata(pdev, rcdu);
-
-	/* I/O resources */
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
-	if (IS_ERR(rcdu->mmio)) {
-		ret = PTR_ERR(rcdu->mmio);
-		goto error;
-	}
-
-	/* Initialize vertical blanking interrupts handling. Start with vblank
-	 * disabled for all CRTCs.
-	 */
-	ret = drm_vblank_init(ddev, (1 << rcdu->info->num_crtcs) - 1);
-	if (ret < 0)
-		goto error;
-
-	/* DRM/KMS objects */
 	ret = rcar_du_modeset_init(rcdu);
 	if (ret < 0) {
 		if (ret != -EPROBE_DEFER)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 392c7e6..cfc302c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -567,6 +567,13 @@
 	if (ret < 0)
 		return ret;
 
+	/* Initialize vertical blanking interrupts handling. Start with vblank
+	 * disabled for all CRTCs.
+	 */
+	ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
+	if (ret < 0)
+		return ret;
+
 	/* Initialize the groups. */
 	num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index c7b53d9..fefb9d9 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -519,7 +519,7 @@
 			   struct vmw_sw_context *sw_context,
 			   SVGA3dCmdHeader *header)
 {
-	return capable(CAP_SYS_ADMIN) ? : -EINVAL;
+	return -EINVAL;
 }
 
 static int vmw_cmd_ok(struct vmw_private *dev_priv,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 6a0dbce..d16e42d 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1333,8 +1333,7 @@
 
 	}
 
-	if (nopreempt == false &&
-		ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) {
+	if (nopreempt == false) {
 		int r = 0;
 
 		if (gpudev->preemption_init)
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 45ea99a..36bd656 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -528,6 +528,7 @@
 	ADRENO_DEVICE_ISDB_ENABLED = 12,
 	ADRENO_DEVICE_CACHE_FLUSH_TS_SUSPENDED = 13,
 	ADRENO_DEVICE_HARD_RESET = 14,
+	ADRENO_DEVICE_PREEMPTION_EXECUTION = 15,
 };
 
 /**
@@ -1550,11 +1551,23 @@
 	smp_wmb();
 }
 
-static inline bool adreno_is_preemption_enabled(
+static inline bool adreno_is_preemption_execution_enabled(
+				struct adreno_device *adreno_dev)
+{
+	return test_bit(ADRENO_DEVICE_PREEMPTION_EXECUTION, &adreno_dev->priv);
+}
+
+static inline bool adreno_is_preemption_setup_enabled(
 				struct adreno_device *adreno_dev)
 {
 	return test_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv);
 }
+
+static inline bool adreno_is_preemption_enabled(
+				struct adreno_device *adreno_dev)
+{
+	return 0;
+}
 /**
  * adreno_ctx_get_rb() - Return the ringbuffer that a context should
  * use based on priority
@@ -1578,7 +1591,7 @@
 	 * ringbuffer
 	 */
 
-	if (!adreno_is_preemption_enabled(adreno_dev))
+	if (!adreno_is_preemption_execution_enabled(adreno_dev))
 		return &(adreno_dev->ringbuffers[0]);
 
 	/*
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 5f070bc..12824b0 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -567,7 +567,7 @@
 		kgsl_regrmw(device, A6XX_PC_DBG_ECO_CNTL, 0, (1 << 8));
 
 	/* Enable the GMEM save/restore feature for preemption */
-	if (adreno_is_preemption_enabled(adreno_dev))
+	if (adreno_is_preemption_setup_enabled(adreno_dev))
 		kgsl_regwrite(device, A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE,
 			0x1);
 
@@ -773,7 +773,7 @@
 	struct adreno_ringbuffer *rb = adreno_dev->cur_rb;
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 
-	if (!adreno_is_preemption_enabled(adreno_dev))
+	if (!adreno_is_preemption_execution_enabled(adreno_dev))
 		return 0;
 
 	cmds = adreno_ringbuffer_allocspace(rb, 42);
@@ -2295,7 +2295,7 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 
-	if (adreno_is_preemption_enabled(adreno_dev))
+	if (adreno_is_preemption_execution_enabled(adreno_dev))
 		a6xx_preemption_trigger(adreno_dev);
 
 	adreno_dispatcher_schedule(device);
diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c
index a982436..1d5f4a5 100644
--- a/drivers/gpu/msm/adreno_a6xx_preempt.c
+++ b/drivers/gpu/msm/adreno_a6xx_preempt.c
@@ -360,7 +360,7 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 
-	if (!adreno_is_preemption_enabled(adreno_dev))
+	if (!adreno_is_preemption_execution_enabled(adreno_dev))
 		return;
 
 	mutex_lock(&device->mutex);
@@ -453,7 +453,7 @@
 	struct adreno_ringbuffer *rb;
 	unsigned int i;
 
-	if (!adreno_is_preemption_enabled(adreno_dev))
+	if (!adreno_is_preemption_execution_enabled(adreno_dev))
 		return;
 
 	/* Force the state to be clear */
@@ -631,7 +631,7 @@
 	struct kgsl_device *device = context->device;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	if (!adreno_is_preemption_enabled(adreno_dev))
+	if (!adreno_is_preemption_setup_enabled(adreno_dev))
 		return;
 
 	gpumem_free_entry(context->user_ctxt_record);
@@ -642,7 +642,7 @@
 	struct kgsl_device *device = context->device;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
-	if (!adreno_is_preemption_enabled(adreno_dev))
+	if (!adreno_is_preemption_setup_enabled(adreno_dev))
 		return 0;
 
 	context->user_ctxt_record = gpumem_alloc_entry(context->dev_priv,
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 8fd8b88..25aeaef 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2139,7 +2139,7 @@
 	 * Deleting uninitialized timer will block for ever on kernel debug
 	 * disable build. Hence skip del timer if it is not initialized.
 	 */
-	if (adreno_is_preemption_enabled(adreno_dev))
+	if (adreno_is_preemption_execution_enabled(adreno_dev))
 		del_timer_sync(&adreno_dev->preempt.timer);
 
 	mutex_lock(&device->mutex);
diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c
index 7c7bfa5..8b283ae 100644
--- a/drivers/gpu/msm/adreno_ioctl.c
+++ b/drivers/gpu/msm/adreno_ioctl.c
@@ -96,7 +96,7 @@
 	int levels_to_copy;
 
 	if (!adreno_is_a5xx(adreno_dev) ||
-		!adreno_is_preemption_enabled(adreno_dev))
+		!adreno_is_preemption_execution_enabled(adreno_dev))
 		return -EOPNOTSUPP;
 
 	if (read->size_user < size_level)
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index a9d4413..8b87ee2 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -284,7 +284,7 @@
 	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
 	int i;
 
-	if (nopreempt == false && ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION))
+	if (nopreempt == false)
 		adreno_dev->num_ringbuffers = gpudev->num_prio_levels;
 	else
 		adreno_dev->num_ringbuffers = 1;
@@ -473,11 +473,11 @@
 		total_sizedwords += 4;
 
 	if (gpudev->preemption_pre_ibsubmit &&
-				adreno_is_preemption_enabled(adreno_dev))
+			adreno_is_preemption_execution_enabled(adreno_dev))
 		total_sizedwords += 22;
 
 	if (gpudev->preemption_post_ibsubmit &&
-				adreno_is_preemption_enabled(adreno_dev))
+			adreno_is_preemption_execution_enabled(adreno_dev))
 		total_sizedwords += 5;
 
 	/*
@@ -523,7 +523,7 @@
 	*ringcmds++ = cp_packet(adreno_dev, CP_NOP, 1);
 	*ringcmds++ = KGSL_CMD_IDENTIFIER;
 
-	if (adreno_is_preemption_enabled(adreno_dev) &&
+	if (adreno_is_preemption_execution_enabled(adreno_dev) &&
 				gpudev->preemption_pre_ibsubmit)
 		ringcmds += gpudev->preemption_pre_ibsubmit(
 					adreno_dev, rb, ringcmds, context);
@@ -660,7 +660,7 @@
 		ringcmds += cp_secure_mode(adreno_dev, ringcmds, 0);
 
 	if (gpudev->preemption_post_ibsubmit &&
-				adreno_is_preemption_enabled(adreno_dev))
+			adreno_is_preemption_execution_enabled(adreno_dev))
 		ringcmds += gpudev->preemption_post_ibsubmit(adreno_dev,
 			ringcmds);
 
@@ -864,9 +864,10 @@
 			dwords += 2;
 	}
 
-	if (adreno_is_preemption_enabled(adreno_dev))
+	if (adreno_is_preemption_execution_enabled(adreno_dev)) {
 		if (gpudev->preemption_yield_enable)
 			dwords += 8;
+	}
 
 	if (gpudev->set_marker)
 		dwords += 4;
@@ -927,9 +928,10 @@
 	if (gpudev->set_marker)
 		cmds += gpudev->set_marker(cmds, 0);
 
-	if (adreno_is_preemption_enabled(adreno_dev))
+	if (adreno_is_preemption_execution_enabled(adreno_dev)) {
 		if (gpudev->preemption_yield_enable)
 			cmds += gpudev->preemption_yield_enable(cmds);
+	}
 
 	if (kernel_profiling) {
 		cmds += _get_alwayson_counter(adreno_dev, cmds,
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 0840aba..f608927 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -837,7 +837,8 @@
 
 	snapshot_frozen_objsize = 0;
 
-	setup_fault_process(device, snapshot,
+	if (!IS_ERR(context))
+		setup_fault_process(device, snapshot,
 			context ? context->proc_priv : NULL);
 
 	/* Add GPU specific sections - registers mainly, but other stuff too */
diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c
index 3977302..b06aa98 100644
--- a/drivers/gpu/msm/adreno_sysfs.c
+++ b/drivers/gpu/msm/adreno_sysfs.c
@@ -205,13 +205,14 @@
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 
-	if (test_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv) == val)
+	if (test_bit(ADRENO_DEVICE_PREEMPTION_EXECUTION,
+		&adreno_dev->priv) == val)
 		return 0;
 
 	mutex_lock(&device->mutex);
 
 	kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
-	change_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv);
+	change_bit(ADRENO_DEVICE_PREEMPTION_EXECUTION, &adreno_dev->priv);
 	adreno_dev->cur_rb = &(adreno_dev->ringbuffers[0]);
 	kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
 
@@ -222,7 +223,7 @@
 
 static unsigned int _preemption_show(struct adreno_device *adreno_dev)
 {
-	return adreno_is_preemption_enabled(adreno_dev);
+	return adreno_is_preemption_execution_enabled(adreno_dev);
 }
 
 static int _hwcg_store(struct adreno_device *adreno_dev,
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 2ddb082..9b04543 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1364,7 +1364,7 @@
 		/* Wait for the NMI to be handled */
 		wmb();
 		udelay(100);
-		kgsl_device_snapshot(device, NULL);
+		kgsl_device_snapshot(device, ERR_PTR(-EINVAL));
 
 		adreno_write_gmureg(adreno_dev,
 				ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 7cbda72..e704db7 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -182,7 +182,8 @@
 	context = kgsl_context_get(device, header->current_context);
 
 	/* Get the current PT base */
-	 header->ptbase = kgsl_mmu_get_current_ttbr0(&device->mmu);
+	if (!IS_ERR(priv))
+		header->ptbase = kgsl_mmu_get_current_ttbr0(&device->mmu);
 
 	/* And the PID for the task leader */
 	if (context) {
@@ -633,8 +634,10 @@
 	snapshot->size += sizeof(*header);
 
 	/* Build the Linux specific header */
+	/* Context err is implied a GMU fault, so limit dump */
 	kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
-			snapshot, snapshot_os, NULL);
+			snapshot, snapshot_os,
+			IS_ERR(context) ? context : NULL);
 
 	/* Get the device specific sections */
 	if (device->ftbl->snapshot)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index d7f6cf0..d42ace8 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2485,6 +2485,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_PETZL, USB_DEVICE_ID_PETZL_HEADLAMP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
 #if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index cfca43f..08fd3f8 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -819,6 +819,9 @@
 #define USB_VENDOR_ID_PETALYNX		0x18b1
 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE	0x0037
 
+#define USB_VENDOR_ID_PETZL		0x2122
+#define USB_DEVICE_ID_PETZL_HEADLAMP	0x1234
+
 #define USB_VENDOR_ID_PHILIPS		0x0471
 #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
 
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 01e3a37..d118ffe 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -2342,8 +2342,9 @@
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	if (cmd.port_num < rdma_start_port(ib_dev) ||
-	    cmd.port_num > rdma_end_port(ib_dev))
+	if ((cmd.attr_mask & IB_QP_PORT) &&
+	    (cmd.port_num < rdma_start_port(ib_dev) ||
+	     cmd.port_num > rdma_end_port(ib_dev)))
 		return -EINVAL;
 
 	INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index f2a885e..8059b7e 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -1680,9 +1680,19 @@
 		size += ret;
 	}
 
+	if (mlx4_is_master(mdev->dev) && flow_type == MLX4_FS_REGULAR &&
+	    flow_attr->num_of_specs == 1) {
+		struct _rule_hw *rule_header = (struct _rule_hw *)(ctrl + 1);
+		enum ib_flow_spec_type header_spec =
+			((union ib_flow_spec *)(flow_attr + 1))->type;
+
+		if (header_spec == IB_FLOW_SPEC_ETH)
+			mlx4_handle_eth_header_mcast_prio(ctrl, rule_header);
+	}
+
 	ret = mlx4_cmd_imm(mdev->dev, mailbox->dma, reg_id, size >> 2, 0,
 			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
-			   MLX4_CMD_WRAPPED);
+			   MLX4_CMD_NATIVE);
 	if (ret == -ENOMEM)
 		pr_err("mcg table is full. Fail to register network rule.\n");
 	else if (ret == -ENXIO)
@@ -1699,7 +1709,7 @@
 	int err;
 	err = mlx4_cmd(dev, reg_id, 0, 0,
 		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
-		       MLX4_CMD_WRAPPED);
+		       MLX4_CMD_NATIVE);
 	if (err)
 		pr_err("Fail to detach network rule. registration id = 0x%llx\n",
 		       reg_id);
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index cdd638c..a2c5579 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -319,6 +319,14 @@
 	QCOM_SMMUV500,
 };
 
+struct arm_smmu_device;
+struct arm_smmu_arch_ops {
+	int (*init)(struct arm_smmu_device *smmu);
+	void (*device_reset)(struct arm_smmu_device *smmu);
+	phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
+					 dma_addr_t iova);
+};
+
 struct arm_smmu_impl_def_reg {
 	u32 offset;
 	u32 value;
@@ -392,7 +400,6 @@
 	int				regulator_defer;
 };
 
-struct arm_smmu_arch_ops;
 struct arm_smmu_device {
 	struct device			*dev;
 
@@ -554,6 +561,9 @@
 static int arm_smmu_assign_table(struct arm_smmu_domain *smmu_domain);
 static void arm_smmu_unassign_table(struct arm_smmu_domain *smmu_domain);
 
+static int arm_smmu_arch_init(struct arm_smmu_device *smmu);
+static void arm_smmu_arch_device_reset(struct arm_smmu_device *smmu);
+
 static uint64_t arm_smmu_iova_to_pte(struct iommu_domain *domain,
 				    dma_addr_t iova);
 
@@ -617,76 +627,6 @@
 		mutex_unlock(&smmu_domain->assign_lock);
 }
 
-/*
- * init()
- * Hook for additional device tree parsing at probe time.
- *
- * device_reset()
- * Hook for one-time architecture-specific register settings.
- *
- * iova_to_phys_hard()
- * Provides debug information. May be called from the context fault irq handler.
- *
- * init_context_bank()
- * Hook for architecture-specific settings which require knowledge of the
- * dynamically allocated context bank number.
- *
- * device_group()
- * Hook for checking whether a device is compatible with a said group.
- */
-struct arm_smmu_arch_ops {
-	int (*init)(struct arm_smmu_device *smmu);
-	void (*device_reset)(struct arm_smmu_device *smmu);
-	phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
-					 dma_addr_t iova);
-	void (*init_context_bank)(struct arm_smmu_domain *smmu_domain,
-					struct device *dev);
-	int (*device_group)(struct device *dev, struct iommu_group *group);
-};
-
-static int arm_smmu_arch_init(struct arm_smmu_device *smmu)
-{
-	if (!smmu->arch_ops)
-		return 0;
-	if (!smmu->arch_ops->init)
-		return 0;
-	return smmu->arch_ops->init(smmu);
-}
-
-static void arm_smmu_arch_device_reset(struct arm_smmu_device *smmu)
-{
-	if (!smmu->arch_ops)
-		return;
-	if (!smmu->arch_ops->device_reset)
-		return;
-	return smmu->arch_ops->device_reset(smmu);
-}
-
-static void arm_smmu_arch_init_context_bank(
-		struct arm_smmu_domain *smmu_domain, struct device *dev)
-{
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-
-	if (!smmu->arch_ops)
-		return;
-	if (!smmu->arch_ops->init_context_bank)
-		return;
-	return smmu->arch_ops->init_context_bank(smmu_domain, dev);
-}
-
-static int arm_smmu_arch_device_group(struct device *dev,
-					struct iommu_group *group)
-{
-	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
-	struct arm_smmu_device *smmu = fwspec_smmu(fwspec);
-
-	if (!smmu->arch_ops)
-		return 0;
-	if (!smmu->arch_ops->device_group)
-		return 0;
-	return smmu->arch_ops->device_group(dev, group);
-}
-
 static struct device_node *dev_get_dev_node(struct device *dev)
 {
 	if (dev_is_pci(dev)) {
@@ -1814,8 +1754,6 @@
 		arm_smmu_init_context_bank(smmu_domain,
 						&smmu_domain->pgtbl_cfg);
 
-		arm_smmu_arch_init_context_bank(smmu_domain, dev);
-
 		/*
 		 * Request context fault interrupt. Do this last to avoid the
 		 * handler seeing a half-initialised domain state.
@@ -2721,20 +2659,13 @@
 		group = smmu->s2crs[idx].group;
 	}
 
-	if (!group) {
-		if (dev_is_pci(dev))
-			group = pci_device_group(dev);
-		else
-			group = generic_device_group(dev);
+	if (group)
+		return group;
 
-		if (IS_ERR(group))
-			return NULL;
-	}
-
-	if (arm_smmu_arch_device_group(dev, group)) {
-		iommu_group_put(group);
-		return ERR_PTR(-EINVAL);
-	}
+	if (dev_is_pci(dev))
+		group = pci_device_group(dev);
+	else
+		group = generic_device_group(dev);
 
 	return group;
 }
@@ -4011,6 +3942,24 @@
 	return 0;
 }
 
+static int arm_smmu_arch_init(struct arm_smmu_device *smmu)
+{
+	if (!smmu->arch_ops)
+		return 0;
+	if (!smmu->arch_ops->init)
+		return 0;
+	return smmu->arch_ops->init(smmu);
+}
+
+static void arm_smmu_arch_device_reset(struct arm_smmu_device *smmu)
+{
+	if (!smmu->arch_ops)
+		return;
+	if (!smmu->arch_ops->device_reset)
+		return;
+	return smmu->arch_ops->device_reset(smmu);
+}
+
 struct arm_smmu_match_data {
 	enum arm_smmu_arch_version version;
 	enum arm_smmu_implementation model;
@@ -4335,19 +4284,10 @@
 
 #define TBU_DBG_TIMEOUT_US		30000
 
-
-struct actlr_setting {
-	struct arm_smmu_smr smr;
-	u32 actlr;
-};
-
 struct qsmmuv500_archdata {
 	struct list_head		tbus;
 	void __iomem			*tcu_base;
 	u32				version;
-
-	struct actlr_setting		*actlrs;
-	u32				actlr_tbl_size;
 };
 #define get_qsmmuv500_archdata(smmu)				\
 	((struct qsmmuv500_archdata *)(smmu->archdata))
@@ -4368,14 +4308,6 @@
 	u32				halt_count;
 };
 
-struct qsmmuv500_group_iommudata {
-	bool has_actlr;
-	u32 actlr;
-};
-#define to_qsmmuv500_group_iommudata(group)				\
-	((struct qsmmuv500_group_iommudata *)				\
-		(iommu_group_get_iommudata(group)))
-
 static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu)
 {
 	unsigned long flags;
@@ -4629,79 +4561,6 @@
 	return qsmmuv500_iova_to_phys(domain, iova, sid);
 }
 
-static void qsmmuv500_release_group_iommudata(void *data)
-{
-	kfree(data);
-}
-
-/* If a device has a valid actlr, it must match */
-static int qsmmuv500_device_group(struct device *dev,
-				struct iommu_group *group)
-{
-	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
-	struct arm_smmu_device *smmu = fwspec_smmu(fwspec);
-	struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-	struct qsmmuv500_group_iommudata *iommudata;
-	u32 actlr, i, j, idx;
-	struct arm_smmu_smr *smr, *smr2;
-
-	iommudata = to_qsmmuv500_group_iommudata(group);
-	if (!iommudata) {
-		iommudata = kzalloc(sizeof(*iommudata), GFP_KERNEL);
-		if (!iommudata)
-			return -ENOMEM;
-
-		iommu_group_set_iommudata(group, iommudata,
-				qsmmuv500_release_group_iommudata);
-	}
-
-	for_each_cfg_sme(fwspec, i, idx) {
-		smr = &smmu->smrs[idx];
-		for (j = 0; j < data->actlr_tbl_size; j++) {
-			smr2 = &data->actlrs[j].smr;
-			actlr = data->actlrs[j].actlr;
-
-			/* Continue if table entry does not match */
-			if ((smr->id ^ smr2->id) & ~(smr->mask | smr2->mask))
-				continue;
-
-			if (!iommudata->has_actlr) {
-				iommudata->actlr = actlr;
-				iommudata->has_actlr = true;
-			} else if (iommudata->actlr != actlr) {
-				return -EINVAL;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static void qsmmuv500_init_cb(struct arm_smmu_domain *smmu_domain,
-				struct device *dev)
-{
-	struct arm_smmu_device *smmu = smmu_domain->smmu;
-	struct qsmmuv500_group_iommudata *iommudata =
-		to_qsmmuv500_group_iommudata(dev->iommu_group);
-	void __iomem *cb_base;
-	const struct iommu_gather_ops *tlb;
-
-	if (!iommudata->has_actlr)
-		return;
-
-	tlb = smmu_domain->pgtbl_cfg.tlb;
-	cb_base = ARM_SMMU_CB_BASE(smmu) +
-			ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx);
-
-	writel_relaxed(iommudata->actlr, cb_base + ARM_SMMU_CB_ACTLR);
-
-	/*
-	 * Flush the context bank after modifying ACTLR to ensure there
-	 * are no cache entries with stale state
-	 */
-	tlb->tlb_flush_all(smmu_domain);
-}
-
 static int qsmmuv500_tbu_register(struct device *dev, void *cookie)
 {
 	struct arm_smmu_device *smmu = cookie;
@@ -4721,38 +4580,6 @@
 	return 0;
 }
 
-static int qsmmuv500_read_actlr_tbl(struct arm_smmu_device *smmu)
-{
-	int len, i;
-	struct device *dev = smmu->dev;
-	struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
-	struct actlr_setting *actlrs;
-	const __be32 *cell;
-
-	cell = of_get_property(dev->of_node, "qcom,actlr", NULL);
-	if (!cell)
-		return 0;
-
-	len = of_property_count_elems_of_size(dev->of_node, "qcom,actlr",
-						sizeof(u32) * 3);
-	if (len < 0)
-		return 0;
-
-	actlrs = devm_kzalloc(dev, sizeof(*actlrs) * len, GFP_KERNEL);
-	if (!actlrs)
-		return -ENOMEM;
-
-	for (i = 0; i < len; i++) {
-		actlrs[i].smr.id = of_read_number(cell++, 1);
-		actlrs[i].smr.mask = of_read_number(cell++, 1);
-		actlrs[i].actlr = of_read_number(cell++, 1);
-	}
-
-	data->actlrs = actlrs;
-	data->actlr_tbl_size = len;
-	return 0;
-}
-
 static int qsmmuv500_arch_init(struct arm_smmu_device *smmu)
 {
 	struct resource *res;
@@ -4760,8 +4587,6 @@
 	struct qsmmuv500_archdata *data;
 	struct platform_device *pdev;
 	int ret;
-	u32 val;
-	void __iomem *reg;
 
 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
@@ -4778,23 +4603,6 @@
 	data->version = readl_relaxed(data->tcu_base + TCU_HW_VERSION_HLOS1);
 	smmu->archdata = data;
 
-	ret = qsmmuv500_read_actlr_tbl(smmu);
-	if (ret)
-		return ret;
-
-	reg = ARM_SMMU_GR0(smmu);
-	val = readl_relaxed(reg + ARM_SMMU_GR0_sACR);
-	val &= ~ARM_MMU500_ACR_CACHE_LOCK;
-	writel_relaxed(val, reg + ARM_SMMU_GR0_sACR);
-	val = readl_relaxed(reg + ARM_SMMU_GR0_sACR);
-	/*
-	 * Modifiying the nonsecure copy of the sACR register is only
-	 * allowed if permission is given in the secure sACR register.
-	 * Attempt to detect if we were able to update the value.
-	 */
-	WARN_ON(val & ARM_MMU500_ACR_CACHE_LOCK);
-
-
 	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
 	if (ret)
 		return ret;
@@ -4810,8 +4618,6 @@
 struct arm_smmu_arch_ops qsmmuv500_arch_ops = {
 	.init = qsmmuv500_arch_init,
 	.iova_to_phys_hard = qsmmuv500_iova_to_phys_hard,
-	.init_context_bank = qsmmuv500_init_cb,
-	.device_group = qsmmuv500_device_group,
 };
 
 static const struct of_device_id qsmmuv500_tbu_of_match[] = {
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index e23001b..5c88ba7 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -56,13 +56,13 @@
 static struct rb_node *
 __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
 {
-	if ((*limit_pfn != iovad->dma_32bit_pfn) ||
+	if ((*limit_pfn > iovad->dma_32bit_pfn) ||
 		(iovad->cached32_node == NULL))
 		return rb_last(&iovad->rbroot);
 	else {
 		struct rb_node *prev_node = rb_prev(iovad->cached32_node);
 		struct iova *curr_iova =
-			container_of(iovad->cached32_node, struct iova, node);
+			rb_entry(iovad->cached32_node, struct iova, node);
 		*limit_pfn = curr_iova->pfn_lo - 1;
 		return prev_node;
 	}
@@ -86,11 +86,11 @@
 	if (!iovad->cached32_node)
 		return;
 	curr = iovad->cached32_node;
-	cached_iova = container_of(curr, struct iova, node);
+	cached_iova = rb_entry(curr, struct iova, node);
 
 	if (free->pfn_lo >= cached_iova->pfn_lo) {
 		struct rb_node *node = rb_next(&free->node);
-		struct iova *iova = container_of(node, struct iova, node);
+		struct iova *iova = rb_entry(node, struct iova, node);
 
 		/* only cache if it's below 32bit pfn */
 		if (node && iova->pfn_lo < iovad->dma_32bit_pfn)
@@ -100,6 +100,34 @@
 	}
 }
 
+/* Insert the iova into domain rbtree by holding writer lock */
+static void
+iova_insert_rbtree(struct rb_root *root, struct iova *iova,
+		   struct rb_node *start)
+{
+	struct rb_node **new, *parent = NULL;
+
+	new = (start) ? &start : &(root->rb_node);
+	/* Figure out where to put new node */
+	while (*new) {
+		struct iova *this = rb_entry(*new, struct iova, node);
+
+		parent = *new;
+
+		if (iova->pfn_lo < this->pfn_lo)
+			new = &((*new)->rb_left);
+		else if (iova->pfn_lo > this->pfn_lo)
+			new = &((*new)->rb_right);
+		else {
+			WARN_ON(1); /* this should not happen */
+			return;
+		}
+	}
+	/* Add new node and rebalance tree. */
+	rb_link_node(&iova->node, parent, new);
+	rb_insert_color(&iova->node, root);
+}
+
 /*
  * Computes the padding size required, to make the start address
  * naturally aligned on the power-of-two order of its size
@@ -125,7 +153,7 @@
 	curr = __get_cached_rbnode(iovad, &limit_pfn);
 	prev = curr;
 	while (curr) {
-		struct iova *curr_iova = container_of(curr, struct iova, node);
+		struct iova *curr_iova = rb_entry(curr, struct iova, node);
 
 		if (limit_pfn < curr_iova->pfn_lo)
 			goto move_left;
@@ -138,7 +166,7 @@
 				break;	/* found a free slot */
 		}
 adjust_limit_pfn:
-		limit_pfn = curr_iova->pfn_lo - 1;
+		limit_pfn = curr_iova->pfn_lo ? (curr_iova->pfn_lo - 1) : 0;
 move_left:
 		prev = curr;
 		curr = rb_prev(curr);
@@ -157,36 +185,8 @@
 	new->pfn_lo = limit_pfn - (size + pad_size) + 1;
 	new->pfn_hi = new->pfn_lo + size - 1;
 
-	/* Insert the new_iova into domain rbtree by holding writer lock */
-	/* Add new node and rebalance tree. */
-	{
-		struct rb_node **entry, *parent = NULL;
-
-		/* If we have 'prev', it's a valid place to start the
-		   insertion. Otherwise, start from the root. */
-		if (prev)
-			entry = &prev;
-		else
-			entry = &iovad->rbroot.rb_node;
-
-		/* Figure out where to put new node */
-		while (*entry) {
-			struct iova *this = container_of(*entry,
-							struct iova, node);
-			parent = *entry;
-
-			if (new->pfn_lo < this->pfn_lo)
-				entry = &((*entry)->rb_left);
-			else if (new->pfn_lo > this->pfn_lo)
-				entry = &((*entry)->rb_right);
-			else
-				BUG(); /* this should not happen */
-		}
-
-		/* Add new node and rebalance tree. */
-		rb_link_node(&new->node, parent, entry);
-		rb_insert_color(&new->node, &iovad->rbroot);
-	}
+	/* If we have 'prev', it's a valid place to start the insertion. */
+	iova_insert_rbtree(&iovad->rbroot, new, prev);
 	__cached_rbnode_insert_update(iovad, saved_pfn, new);
 
 	spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
@@ -195,28 +195,6 @@
 	return 0;
 }
 
-static void
-iova_insert_rbtree(struct rb_root *root, struct iova *iova)
-{
-	struct rb_node **new = &(root->rb_node), *parent = NULL;
-	/* Figure out where to put new node */
-	while (*new) {
-		struct iova *this = container_of(*new, struct iova, node);
-
-		parent = *new;
-
-		if (iova->pfn_lo < this->pfn_lo)
-			new = &((*new)->rb_left);
-		else if (iova->pfn_lo > this->pfn_lo)
-			new = &((*new)->rb_right);
-		else
-			BUG(); /* this should not happen */
-	}
-	/* Add new node and rebalance tree. */
-	rb_link_node(&iova->node, parent, new);
-	rb_insert_color(&iova->node, root);
-}
-
 static struct kmem_cache *iova_cache;
 static unsigned int iova_cache_users;
 static DEFINE_MUTEX(iova_cache_mutex);
@@ -311,7 +289,7 @@
 	assert_spin_locked(&iovad->iova_rbtree_lock);
 
 	while (node) {
-		struct iova *iova = container_of(node, struct iova, node);
+		struct iova *iova = rb_entry(node, struct iova, node);
 
 		/* If pfn falls within iova's range, return iova */
 		if ((pfn >= iova->pfn_lo) && (pfn <= iova->pfn_hi)) {
@@ -463,7 +441,7 @@
 	spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
 	node = rb_first(&iovad->rbroot);
 	while (node) {
-		struct iova *iova = container_of(node, struct iova, node);
+		struct iova *iova = rb_entry(node, struct iova, node);
 
 		rb_erase(node, &iovad->rbroot);
 		free_iova_mem(iova);
@@ -477,7 +455,7 @@
 __is_range_overlap(struct rb_node *node,
 	unsigned long pfn_lo, unsigned long pfn_hi)
 {
-	struct iova *iova = container_of(node, struct iova, node);
+	struct iova *iova = rb_entry(node, struct iova, node);
 
 	if ((pfn_lo <= iova->pfn_hi) && (pfn_hi >= iova->pfn_lo))
 		return 1;
@@ -506,7 +484,7 @@
 
 	iova = alloc_and_init_iova(pfn_lo, pfn_hi);
 	if (iova)
-		iova_insert_rbtree(&iovad->rbroot, iova);
+		iova_insert_rbtree(&iovad->rbroot, iova, NULL);
 
 	return iova;
 }
@@ -541,7 +519,7 @@
 	spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
 	for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) {
 		if (__is_range_overlap(node, pfn_lo, pfn_hi)) {
-			iova = container_of(node, struct iova, node);
+			iova = rb_entry(node, struct iova, node);
 			__adjust_overlap_range(iova, &pfn_lo, &pfn_hi);
 			if ((pfn_lo >= iova->pfn_lo) &&
 				(pfn_hi <= iova->pfn_hi))
@@ -578,7 +556,7 @@
 
 	spin_lock_irqsave(&from->iova_rbtree_lock, flags);
 	for (node = rb_first(&from->rbroot); node; node = rb_next(node)) {
-		struct iova *iova = container_of(node, struct iova, node);
+		struct iova *iova = rb_entry(node, struct iova, node);
 		struct iova *new_iova;
 
 		new_iova = reserve_iova(to, iova->pfn_lo, iova->pfn_hi);
@@ -613,11 +591,11 @@
 	rb_erase(&iova->node, &iovad->rbroot);
 
 	if (prev) {
-		iova_insert_rbtree(&iovad->rbroot, prev);
+		iova_insert_rbtree(&iovad->rbroot, prev, NULL);
 		iova->pfn_lo = pfn_lo;
 	}
 	if (next) {
-		iova_insert_rbtree(&iovad->rbroot, next);
+		iova_insert_rbtree(&iovad->rbroot, next, NULL);
 		iova->pfn_hi = pfn_hi;
 	}
 	spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c
index 54a5e87..efbcf84 100644
--- a/drivers/irqchip/irq-keystone.c
+++ b/drivers/irqchip/irq-keystone.c
@@ -19,9 +19,9 @@
 #include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/interrupt.h>
 #include <linux/irqdomain.h>
 #include <linux/irqchip.h>
-#include <linux/irqchip/chained_irq.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/mfd/syscon.h>
@@ -39,6 +39,7 @@
 	struct irq_domain	*irqd;
 	struct regmap		*devctrl_regs;
 	u32			devctrl_offset;
+	raw_spinlock_t		wa_lock;
 };
 
 static inline u32 keystone_irq_readl(struct keystone_irq_device *kirq)
@@ -83,17 +84,15 @@
 	/* nothing to do here */
 }
 
-static void keystone_irq_handler(struct irq_desc *desc)
+static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq)
 {
-	unsigned int irq = irq_desc_get_irq(desc);
-	struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc);
+	struct keystone_irq_device *kirq = keystone_irq;
+	unsigned long wa_lock_flags;
 	unsigned long pending;
 	int src, virq;
 
 	dev_dbg(kirq->dev, "start irq %d\n", irq);
 
-	chained_irq_enter(irq_desc_get_chip(desc), desc);
-
 	pending = keystone_irq_readl(kirq);
 	keystone_irq_writel(kirq, pending);
 
@@ -111,13 +110,15 @@
 			if (!virq)
 				dev_warn(kirq->dev, "spurious irq detected hwirq %d, virq %d\n",
 					 src, virq);
+			raw_spin_lock_irqsave(&kirq->wa_lock, wa_lock_flags);
 			generic_handle_irq(virq);
+			raw_spin_unlock_irqrestore(&kirq->wa_lock,
+						   wa_lock_flags);
 		}
 	}
 
-	chained_irq_exit(irq_desc_get_chip(desc), desc);
-
 	dev_dbg(kirq->dev, "end irq %d\n", irq);
+	return IRQ_HANDLED;
 }
 
 static int keystone_irq_map(struct irq_domain *h, unsigned int virq,
@@ -182,9 +183,16 @@
 		return -ENODEV;
 	}
 
+	raw_spin_lock_init(&kirq->wa_lock);
+
 	platform_set_drvdata(pdev, kirq);
 
-	irq_set_chained_handler_and_data(kirq->irq, keystone_irq_handler, kirq);
+	ret = request_irq(kirq->irq, keystone_irq_handler,
+			  0, dev_name(dev), kirq);
+	if (ret) {
+		irq_domain_remove(kirq->irqd);
+		return ret;
+	}
 
 	/* clear all source bits */
 	keystone_irq_writel(kirq, ~0x0);
@@ -199,6 +207,8 @@
 	struct keystone_irq_device *kirq = platform_get_drvdata(pdev);
 	int hwirq;
 
+	free_irq(kirq->irq, kirq);
+
 	for (hwirq = 0; hwirq < KEYSTONE_N_IRQ; hwirq++)
 		irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq));
 
diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index 1730470..05fa9f7 100644
--- a/drivers/irqchip/irq-mxs.c
+++ b/drivers/irqchip/irq-mxs.c
@@ -131,12 +131,16 @@
 	.irq_ack = icoll_ack_irq,
 	.irq_mask = icoll_mask_irq,
 	.irq_unmask = icoll_unmask_irq,
+	.flags = IRQCHIP_MASK_ON_SUSPEND |
+		 IRQCHIP_SKIP_SET_WAKE,
 };
 
 static struct irq_chip asm9260_icoll_chip = {
 	.irq_ack = icoll_ack_irq,
 	.irq_mask = asm9260_mask_irq,
 	.irq_unmask = asm9260_unmask_irq,
+	.flags = IRQCHIP_MASK_ON_SUSPEND |
+		 IRQCHIP_SKIP_SET_WAKE,
 };
 
 asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 9b856e1..e4c43a1 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1379,6 +1379,7 @@
 			if (arg) {
 				if (copy_from_user(bname, argp, sizeof(bname) - 1))
 					return -EFAULT;
+				bname[sizeof(bname)-1] = 0;
 			} else
 				return -EINVAL;
 			ret = mutex_lock_interruptible(&dev->mtx);
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index c151c6d..f63a110 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -2611,10 +2611,9 @@
 	char newname[10];
 
 	if (p) {
-		/* Slave-Name MUST not be empty */
-		if (!strlen(p + 1))
+		/* Slave-Name MUST not be empty or overflow 'newname' */
+		if (strscpy(newname, p + 1, sizeof(newname)) <= 0)
 			return NULL;
-		strcpy(newname, p + 1);
 		*p = 0;
 		/* Master must already exist */
 		if (!(n = isdn_net_findif(parm)))
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 9c1e8ad..bf3fbd0 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -2364,7 +2364,7 @@
 		       id);
 		return NULL;
 	} else {
-		rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
+		rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_ATOMIC);
 		if (!rs)
 			return NULL;
 		rs->state = CCPResetIdle;
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 3989bc6..9f340bf 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -115,11 +115,14 @@
 	/* Submit next message */
 	msg_submit(chan);
 
+	if (!mssg)
+		return;
+
 	/* Notify the client */
-	if (mssg && chan->cl->tx_done)
+	if (chan->cl->tx_done)
 		chan->cl->tx_done(chan->cl, mssg, r);
 
-	if (chan->cl->tx_block)
+	if (r != -ETIME && chan->cl->tx_block)
 		complete(&chan->tx_complete);
 }
 
@@ -272,7 +275,7 @@
 
 	msg_submit(chan);
 
-	if (chan->cl->tx_block && chan->active_req) {
+	if (chan->cl->tx_block) {
 		unsigned long wait;
 		int ret;
 
@@ -283,8 +286,8 @@
 
 		ret = wait_for_completion_timeout(&chan->tx_complete, wait);
 		if (ret == 0) {
-			t = -EIO;
-			tx_tick(chan, -EIO);
+			t = -ETIME;
+			tx_tick(chan, t);
 		}
 	}
 
@@ -293,8 +296,9 @@
 EXPORT_SYMBOL_GPL(mbox_send_message);
 
 /**
- * mbox_send_controller_data-	For client to submit a message to be
- *				sent only to the controller.
+ * mbox_write_controller_data -	For client to submit a message to be
+ *				written to the controller but not sent to
+ *				the remote processor.
  * @chan: Mailbox channel assigned to this client.
  * @mssg: Client specific message typecasted.
  *
@@ -305,7 +309,7 @@
  *	or transmission over chan (blocking mode).
  *	Negative value denotes failure.
  */
-int mbox_send_controller_data(struct mbox_chan *chan, void *mssg)
+int mbox_write_controller_data(struct mbox_chan *chan, void *mssg)
 {
 	unsigned long flags;
 	int err;
@@ -314,12 +318,12 @@
 		return -EINVAL;
 
 	spin_lock_irqsave(&chan->lock, flags);
-	err = chan->mbox->ops->send_controller_data(chan, mssg);
+	err = chan->mbox->ops->write_controller_data(chan, mssg);
 	spin_unlock_irqrestore(&chan->lock, flags);
 
 	return err;
 }
-EXPORT_SYMBOL(mbox_send_controller_data);
+EXPORT_SYMBOL(mbox_write_controller_data);
 
 bool mbox_controller_is_idle(struct mbox_chan *chan)
 {
diff --git a/drivers/mailbox/qcom-rpmh-mailbox.c b/drivers/mailbox/qcom-rpmh-mailbox.c
index ab75d67..7bf8a18 100644
--- a/drivers/mailbox/qcom-rpmh-mailbox.c
+++ b/drivers/mailbox/qcom-rpmh-mailbox.c
@@ -1075,7 +1075,7 @@
 
 static const struct mbox_chan_ops mbox_ops = {
 	.send_data = chan_tcs_write,
-	.send_controller_data = chan_tcs_ctrl_write,
+	.write_controller_data = chan_tcs_ctrl_write,
 	.startup = chan_init,
 	.shutdown = chan_shutdown,
 };
@@ -1178,11 +1178,10 @@
 		if (tcs->num_tcs <= 0 || tcs->type == CONTROL_TCS)
 			continue;
 
-		if (tcs->num_tcs > MAX_TCS_PER_TYPE)
-			return -EINVAL;
-
-		if (st + tcs->num_tcs > max_tcs &&
-				st + tcs->num_tcs >= sizeof(tcs->tcs_mask))
+		if (tcs->num_tcs > MAX_TCS_PER_TYPE ||
+			st + tcs->num_tcs > max_tcs ||
+			st + tcs->num_tcs >=
+				BITS_PER_BYTE * sizeof(tcs->tcs_mask))
 			return -EINVAL;
 
 		tcs->tcs_mask = ((1 << tcs->num_tcs) - 1) << st;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 8f117d6..383f19c 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5843,6 +5843,8 @@
 	pr_debug("%d stripes handled\n", handled);
 
 	spin_unlock_irq(&conf->device_lock);
+
+	async_tx_issue_pending_all();
 	blk_finish_plug(&plug);
 
 	pr_debug("--- raid5worker inactive\n");
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
index 0a06033..2e71850 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -211,7 +211,7 @@
 	}
 
 	if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
-		ret = s5c73m3_af_run(state, ~af_lock);
+		ret = s5c73m3_af_run(state, !af_lock);
 
 	return ret;
 }
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index 800c9ea..48fa1c0 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -9,3 +9,4 @@
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/
diff --git a/drivers/media/platform/msm/camera/cam_fd/Makefile b/drivers/media/platform/msm/camera/cam_fd/Makefile
new file mode 100644
index 0000000..f8177e8
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/Makefile
@@ -0,0 +1,14 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd/fd_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw_mgr/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_dev.o cam_fd_context.o
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
new file mode 100644
index 0000000..4c29ffd
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
@@ -0,0 +1,236 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_debug_util.h"
+#include "cam_fd_context.h"
+
+/* Functions in Available state */
+static int __cam_fd_ctx_acquire_dev_in_available(struct cam_context *ctx,
+	struct cam_acquire_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_acquire_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in Acquire dev, rc=%d", rc);
+		return rc;
+	}
+
+	ctx->state = CAM_CTX_ACQUIRED;
+
+	return rc;
+}
+
+/* Functions in Acquired state */
+static int __cam_fd_ctx_release_dev_in_acquired(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_release_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in Release dev, rc=%d", rc);
+		return rc;
+	}
+
+	ctx->state = CAM_CTX_AVAILABLE;
+
+	return rc;
+}
+
+static int __cam_fd_ctx_config_dev_in_acquired(struct cam_context *ctx,
+	struct cam_config_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_prepare_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in Prepare dev, rc=%d", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __cam_fd_ctx_start_dev_in_acquired(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_start_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in Start dev, rc=%d", rc);
+		return rc;
+	}
+
+	ctx->state = CAM_CTX_ACTIVATED;
+
+	return rc;
+}
+
+/* Functions in Activated state */
+static int __cam_fd_ctx_stop_dev_in_activated(struct cam_context *ctx,
+	struct cam_start_stop_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_stop_dev_to_hw(ctx);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in Stop dev, rc=%d", rc);
+		return rc;
+	}
+
+	ctx->state = CAM_CTX_ACQUIRED;
+
+	return rc;
+}
+
+static int __cam_fd_ctx_release_dev_in_activated(struct cam_context *ctx,
+	struct cam_release_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = __cam_fd_ctx_stop_dev_in_activated(ctx, NULL);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in Stop dev, rc=%d", rc);
+		return rc;
+	}
+
+	rc = __cam_fd_ctx_release_dev_in_acquired(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in Release dev, rc=%d", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __cam_fd_ctx_config_dev_in_activated(
+	struct cam_context *ctx, struct cam_config_dev_cmd *cmd)
+{
+	int rc;
+
+	rc = cam_context_prepare_dev_to_hw(ctx, cmd);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in Prepare dev, rc=%d", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __cam_fd_ctx_handle_irq_in_activated(void *context,
+	uint32_t evt_id, void *evt_data)
+{
+	int rc;
+
+	rc = cam_context_buf_done_from_hw(context, evt_data, evt_id);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in buf done, rc=%d", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+/* top state machine */
+static struct cam_ctx_ops
+	cam_fd_ctx_state_machine[CAM_CTX_STATE_MAX] = {
+	/* Uninit */
+	{
+		.ioctl_ops = {},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Available */
+	{
+		.ioctl_ops = {
+			.acquire_dev = __cam_fd_ctx_acquire_dev_in_available,
+		},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Acquired */
+	{
+		.ioctl_ops = {
+			.release_dev = __cam_fd_ctx_release_dev_in_acquired,
+			.config_dev = __cam_fd_ctx_config_dev_in_acquired,
+			.start_dev = __cam_fd_ctx_start_dev_in_acquired,
+		},
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Ready */
+	{
+		.ioctl_ops = { },
+		.crm_ops = {},
+		.irq_ops = NULL,
+	},
+	/* Activated */
+	{
+		.ioctl_ops = {
+			.stop_dev = __cam_fd_ctx_stop_dev_in_activated,
+			.release_dev = __cam_fd_ctx_release_dev_in_activated,
+			.config_dev = __cam_fd_ctx_config_dev_in_activated,
+		},
+		.crm_ops = {},
+		.irq_ops = __cam_fd_ctx_handle_irq_in_activated,
+	},
+};
+
+
+int cam_fd_context_init(struct cam_fd_context *fd_ctx,
+	struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf)
+{
+	int rc;
+
+	if (!base_ctx || !fd_ctx) {
+		CAM_ERR(CAM_FD, "Invalid Context %pK %pK", base_ctx, fd_ctx);
+		return -EINVAL;
+	}
+
+	memset(fd_ctx, 0, sizeof(*fd_ctx));
+
+	rc = cam_context_init(base_ctx, NULL, hw_intf, fd_ctx->req_base,
+		CAM_CTX_REQ_MAX);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Camera Context Base init failed, rc=%d", rc);
+		return rc;
+	}
+
+	fd_ctx->base = base_ctx;
+	base_ctx->ctx_priv = fd_ctx;
+	base_ctx->state_machine = cam_fd_ctx_state_machine;
+
+	return rc;
+}
+
+int cam_fd_context_deinit(struct cam_fd_context *fd_ctx)
+{
+	int rc = 0;
+
+	if (!fd_ctx || !fd_ctx->base) {
+		CAM_ERR(CAM_FD, "Invalid inputs %pK", fd_ctx);
+		return -EINVAL;
+	}
+
+	rc = cam_context_deinit(fd_ctx->base);
+	if (rc)
+		CAM_ERR(CAM_FD, "Error in base deinit, rc=%d", rc);
+
+	memset(fd_ctx, 0, sizeof(*fd_ctx));
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h
new file mode 100644
index 0000000..6aa5edb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_FD_CONTEXT_H_
+#define _CAM_FD_CONTEXT_H_
+
+#include "cam_context.h"
+#include "cam_context_utils.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_req_mgr_interface.h"
+
+/**
+ * struct cam_fd_context - Face Detection context information
+ *
+ * @base     : Base context pointer for this FD context
+ * @req_base : List of base requests for this FD context
+ */
+struct cam_fd_context {
+	struct cam_context       *base;
+	struct cam_ctx_request    req_base[CAM_CTX_REQ_MAX];
+};
+
+int cam_fd_context_init(struct cam_fd_context *fd_ctx,
+	struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf);
+int cam_fd_context_deinit(struct cam_fd_context *ctx);
+
+#endif /* _CAM_FD_CONTEXT_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c
new file mode 100644
index 0000000..27f5518
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c
@@ -0,0 +1,205 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_subdev.h"
+#include "cam_node.h"
+#include "cam_fd_context.h"
+#include "cam_fd_hw_mgr.h"
+#include "cam_fd_hw_mgr_intf.h"
+
+#define CAM_FD_DEV_NAME "cam-fd"
+
+/**
+ * struct cam_fd_dev - FD device information
+ *
+ * @sd:         Subdev information
+ * @base_ctx:   List of base contexts
+ * @fd_ctx:     List of FD contexts
+ * @lock:       Mutex handle
+ * @open_cnt:   FD subdev open count
+ * @probe_done: Whether FD probe is completed
+ */
+struct cam_fd_dev {
+	struct cam_subdev     sd;
+	struct cam_context    base_ctx[CAM_CTX_MAX];
+	struct cam_fd_context fd_ctx[CAM_CTX_MAX];
+	struct mutex          lock;
+	uint32_t              open_cnt;
+	bool                  probe_done;
+};
+
+static struct cam_fd_dev g_fd_dev;
+
+static int cam_fd_dev_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct cam_fd_dev *fd_dev = &g_fd_dev;
+
+	if (!fd_dev->probe_done) {
+		CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev);
+		return -ENODEV;
+	}
+
+	mutex_lock(&fd_dev->lock);
+	fd_dev->open_cnt++;
+	CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt);
+	mutex_unlock(&fd_dev->lock);
+
+	return 0;
+}
+
+static int cam_fd_dev_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct cam_fd_dev *fd_dev = &g_fd_dev;
+
+	if (!fd_dev->probe_done) {
+		CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev);
+		return -ENODEV;
+	}
+
+	mutex_lock(&fd_dev->lock);
+	fd_dev->open_cnt--;
+	CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt);
+	mutex_unlock(&fd_dev->lock);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops cam_fd_subdev_internal_ops = {
+	.open = cam_fd_dev_open,
+	.close = cam_fd_dev_close,
+};
+
+static int cam_fd_dev_probe(struct platform_device *pdev)
+{
+	int rc;
+	int i;
+	struct cam_hw_mgr_intf hw_mgr_intf;
+	struct cam_node *node;
+
+	g_fd_dev.sd.internal_ops = &cam_fd_subdev_internal_ops;
+
+	/* Initialze the v4l2 subdevice first. (create cam_node) */
+	rc = cam_subdev_probe(&g_fd_dev.sd, pdev, CAM_FD_DEV_NAME,
+		CAM_FD_DEVICE_TYPE);
+	if (rc) {
+		CAM_ERR(CAM_FD, "FD cam_subdev_probe failed, rc=%d", rc);
+		return rc;
+	}
+	node = (struct cam_node *) g_fd_dev.sd.token;
+
+	rc = cam_fd_hw_mgr_init(pdev->dev.of_node, &hw_mgr_intf);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in initializing FD HW manager, rc=%d",
+			rc);
+		goto unregister_subdev;
+	}
+
+	for (i = 0; i < CAM_CTX_MAX; i++) {
+		rc = cam_fd_context_init(&g_fd_dev.fd_ctx[i],
+			&g_fd_dev.base_ctx[i], &node->hw_mgr_intf);
+		if (rc) {
+			CAM_ERR(CAM_FD, "FD context init failed i=%d, rc=%d",
+				i, rc);
+			goto deinit_ctx;
+		}
+	}
+
+	rc = cam_node_init(node, &hw_mgr_intf, g_fd_dev.base_ctx, CAM_CTX_MAX,
+		CAM_FD_DEV_NAME);
+	if (rc) {
+		CAM_ERR(CAM_FD, "FD node init failed, rc=%d", rc);
+		goto deinit_ctx;
+	}
+
+	mutex_init(&g_fd_dev.lock);
+	g_fd_dev.probe_done = true;
+
+	CAM_DBG(CAM_FD, "Camera FD probe complete");
+
+	return 0;
+
+deinit_ctx:
+	for (--i; i >= 0; i--) {
+		if (cam_fd_context_deinit(&g_fd_dev.fd_ctx[i]))
+			CAM_ERR(CAM_FD, "FD context %d deinit failed", i);
+	}
+unregister_subdev:
+	if (cam_subdev_remove(&g_fd_dev.sd))
+		CAM_ERR(CAM_FD, "Failed in subdev remove");
+
+	return rc;
+}
+
+static int cam_fd_dev_remove(struct platform_device *pdev)
+{
+	int i, rc;
+
+	for (i = 0; i < CAM_CTX_MAX; i++) {
+		rc = cam_fd_context_deinit(&g_fd_dev.fd_ctx[i]);
+		if (rc)
+			CAM_ERR(CAM_FD, "FD context %d deinit failed, rc=%d",
+				i, rc);
+	}
+
+	rc = cam_fd_hw_mgr_deinit(pdev->dev.of_node);
+	if (rc)
+		CAM_ERR(CAM_FD, "Failed in hw mgr deinit, rc=%d", rc);
+
+	rc = cam_subdev_remove(&g_fd_dev.sd);
+	if (rc)
+		CAM_ERR(CAM_FD, "Unregister failed, rc=%d", rc);
+
+	mutex_destroy(&g_fd_dev.lock);
+	g_fd_dev.probe_done = false;
+
+	return rc;
+}
+
+static const struct of_device_id cam_fd_dt_match[] = {
+	{
+		.compatible = "qcom,cam-fd"
+	},
+	{}
+};
+
+static struct platform_driver cam_fd_driver = {
+	.probe = cam_fd_dev_probe,
+	.remove = cam_fd_dev_remove,
+	.driver = {
+		.name = "cam_fd",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_fd_dt_match,
+	},
+};
+
+static int __init cam_fd_dev_init_module(void)
+{
+	return platform_driver_register(&cam_fd_driver);
+}
+
+static void __exit cam_fd_dev_exit_module(void)
+{
+	platform_driver_unregister(&cam_fd_driver);
+}
+
+module_init(cam_fd_dev_init_module);
+module_exit(cam_fd_dev_exit_module);
+MODULE_DESCRIPTION("MSM FD driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/Makefile b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/Makefile
new file mode 100644
index 0000000..e7478cb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/Makefile
@@ -0,0 +1,14 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd/fd_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_hw_mgr.o
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
new file mode 100644
index 0000000..d226e17
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
@@ -0,0 +1,1663 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_cpas.h>
+#include <media/cam_req_mgr.h>
+
+#include "cam_io_util.h"
+#include "cam_soc_util.h"
+#include "cam_mem_mgr_api.h"
+#include "cam_smmu_api.h"
+#include "cam_packet_util.h"
+#include "cam_fd_context.h"
+#include "cam_fd_hw_intf.h"
+#include "cam_fd_hw_core.h"
+#include "cam_fd_hw_soc.h"
+#include "cam_fd_hw_mgr_intf.h"
+#include "cam_fd_hw_mgr.h"
+
+static struct cam_fd_hw_mgr g_fd_hw_mgr;
+
+static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet)
+{
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	int i, rc;
+
+	if (!packet)
+		return -EINVAL;
+
+	CAM_DBG(CAM_FD, "Packet request=%d, op_code=0x%x, size=%d, flags=%d",
+		packet->header.request_id, packet->header.op_code,
+		packet->header.size, packet->header.flags);
+	CAM_DBG(CAM_FD,
+		"Packet cmdbuf(offset=%d, num=%d) io(offset=%d, num=%d)",
+		packet->cmd_buf_offset, packet->num_cmd_buf,
+		packet->io_configs_offset, packet->num_io_configs);
+	CAM_DBG(CAM_FD,
+		"Packet Patch(offset=%d, num=%d) kmd(offset=%d, num=%d)",
+		packet->patch_offset, packet->num_patches,
+		packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index);
+
+	if (cam_packet_util_validate_packet(packet)) {
+		CAM_ERR(CAM_FD, "invalid packet:%d %d %d %d %d",
+			packet->kmd_cmd_buf_index,
+			packet->num_cmd_buf, packet->cmd_buf_offset,
+			packet->io_configs_offset, packet->header.size);
+		return -EINVAL;
+	}
+
+	/* All buffers must come through io config, do not support patching */
+	if (packet->num_patches || !packet->num_io_configs) {
+		CAM_ERR(CAM_FD, "wrong number of cmd/patch info: %u %u",
+			packet->num_cmd_buf, packet->num_patches);
+		return -EINVAL;
+	}
+
+	/* KMD Buf index can never be greater than or equal to num cmd bufs */
+	if (packet->kmd_cmd_buf_index >= packet->num_cmd_buf) {
+		CAM_ERR(CAM_FD, "Invalid kmd index %d (%d)",
+			packet->kmd_cmd_buf_index, packet->num_cmd_buf);
+		return -EINVAL;
+	}
+
+	if ((packet->header.op_code & 0xff) !=
+		CAM_PACKET_OPCODES_FD_FRAME_UPDATE) {
+		CAM_ERR(CAM_FD, "Invalid op_code %u",
+			packet->header.op_code & 0xff);
+		return -EINVAL;
+	}
+
+	cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *)&packet->payload +
+		packet->cmd_buf_offset);
+
+	for (i = 0; i < packet->num_cmd_buf; i++) {
+		/*
+		 * We can allow 0 length cmd buffer. This can happen in case
+		 * umd gives an empty cmd buffer as kmd buffer
+		 */
+		if (!cmd_desc[i].length)
+			continue;
+
+		if ((cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_GENERIC) &&
+			(cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_CDM)) {
+			CAM_ERR(CAM_FD, "Invalid meta_data [%d] %u", i,
+				cmd_desc[i].meta_data);
+			return -EINVAL;
+		}
+
+		CAM_DBG(CAM_FD,
+			"CmdBuf[%d] hdl=%d, offset=%d, size=%d, len=%d, type=%d, meta_data=%d",
+			i,
+			cmd_desc[i].mem_handle, cmd_desc[i].offset,
+			cmd_desc[i].size, cmd_desc[i].length, cmd_desc[i].type,
+			cmd_desc[i].meta_data);
+
+		rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]);
+		if (rc) {
+			CAM_ERR(CAM_FD, "Invalid cmd buffer %d", i);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int cam_fd_mgr_util_put_ctx(
+	struct list_head *src_list,
+	struct cam_fd_hw_mgr_ctx **fd_ctx)
+{
+	int rc = 0;
+	struct cam_fd_hw_mgr_ctx *ctx_ptr = NULL;
+
+	mutex_lock(&g_fd_hw_mgr.ctx_mutex);
+	ctx_ptr = *fd_ctx;
+	if (ctx_ptr)
+		list_add_tail(&ctx_ptr->list, src_list);
+	*fd_ctx = NULL;
+	mutex_unlock(&g_fd_hw_mgr.ctx_mutex);
+
+	return rc;
+}
+
+static int cam_fd_mgr_util_get_ctx(
+	struct list_head *src_list,
+	struct cam_fd_hw_mgr_ctx **fd_ctx)
+{
+	int rc = 0;
+	struct cam_fd_hw_mgr_ctx *ctx_ptr = NULL;
+
+	mutex_lock(&g_fd_hw_mgr.ctx_mutex);
+	if (!list_empty(src_list)) {
+		ctx_ptr = list_first_entry(src_list,
+			struct cam_fd_hw_mgr_ctx, list);
+		list_del_init(&ctx_ptr->list);
+	} else {
+		CAM_ERR(CAM_FD, "No more free fd hw mgr ctx");
+		rc = -1;
+	}
+	*fd_ctx = ctx_ptr;
+	mutex_unlock(&g_fd_hw_mgr.ctx_mutex);
+
+	return rc;
+}
+
+static int cam_fd_mgr_util_put_frame_req(
+	struct list_head *src_list,
+	struct cam_fd_mgr_frame_request **frame_req)
+{
+	int rc = 0;
+	struct cam_fd_mgr_frame_request *req_ptr = NULL;
+
+	mutex_lock(&g_fd_hw_mgr.frame_req_mutex);
+	req_ptr = *frame_req;
+	if (req_ptr)
+		list_add_tail(&req_ptr->list, src_list);
+	*frame_req = NULL;
+	mutex_unlock(&g_fd_hw_mgr.frame_req_mutex);
+
+	return rc;
+}
+
+static int cam_fd_mgr_util_get_frame_req(
+	struct list_head *src_list,
+	struct cam_fd_mgr_frame_request **frame_req)
+{
+	int rc = 0;
+	struct cam_fd_mgr_frame_request *req_ptr = NULL;
+
+	mutex_lock(&g_fd_hw_mgr.frame_req_mutex);
+	if (!list_empty(src_list)) {
+		req_ptr = list_first_entry(src_list,
+			struct cam_fd_mgr_frame_request, list);
+		list_del_init(&req_ptr->list);
+	} else {
+		CAM_DBG(CAM_FD, "Frame req not available");
+		rc = -EPERM;
+	}
+	*frame_req = req_ptr;
+	mutex_unlock(&g_fd_hw_mgr.frame_req_mutex);
+
+	return rc;
+}
+
+static int cam_fd_mgr_util_get_device(struct cam_fd_hw_mgr *hw_mgr,
+	struct cam_fd_hw_mgr_ctx *hw_ctx, struct cam_fd_device **hw_device)
+{
+	if (!hw_mgr || !hw_ctx || !hw_device) {
+		CAM_ERR(CAM_FD, "Invalid input %pK %pK %pK", hw_mgr, hw_ctx,
+			hw_device);
+		return -EINVAL;
+	}
+
+	if ((hw_ctx->device_index < 0) ||
+		(hw_ctx->device_index >= CAM_FD_HW_MAX)) {
+		CAM_ERR(CAM_FD, "Invalid device indx %d", hw_ctx->device_index);
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_FD, "ctx index=%d, hw_ctx=%d", hw_ctx->ctx_index,
+		hw_ctx->device_index);
+
+	*hw_device = &hw_mgr->hw_device[hw_ctx->device_index];
+
+	return 0;
+}
+
+static int cam_fd_mgr_util_release_device(struct cam_fd_hw_mgr *hw_mgr,
+	struct cam_fd_hw_mgr_ctx *hw_ctx)
+{
+	struct cam_fd_device *hw_device;
+	struct cam_fd_hw_release_args hw_release_args;
+	int rc;
+
+	rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in getting device %d", rc);
+		return rc;
+	}
+
+	if (hw_device->hw_intf->hw_ops.release) {
+		hw_release_args.hw_ctx = hw_ctx;
+		hw_release_args.ctx_hw_private = hw_ctx->ctx_hw_private;
+		rc = hw_device->hw_intf->hw_ops.release(
+			hw_device->hw_intf->hw_priv, &hw_release_args,
+			sizeof(hw_release_args));
+		if (rc) {
+			CAM_ERR(CAM_FD, "Failed in HW release %d", rc);
+			return rc;
+		}
+	} else {
+		CAM_ERR(CAM_FD, "Invalid release function");
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	hw_device->num_ctxts--;
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	hw_ctx->device_index = -1;
+
+	return rc;
+}
+
+static int cam_fd_mgr_util_select_device(struct cam_fd_hw_mgr *hw_mgr,
+	struct cam_fd_hw_mgr_ctx *hw_ctx,
+	struct cam_fd_acquire_dev_info *fd_acquire_args)
+{
+	int i, rc;
+	struct cam_fd_hw_reserve_args hw_reserve_args;
+	struct cam_fd_device *hw_device = NULL;
+
+	if (!hw_mgr || !hw_ctx || !fd_acquire_args) {
+		CAM_ERR(CAM_FD, "Invalid input %pK %pK %pK", hw_mgr, hw_ctx,
+			fd_acquire_args);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+
+	/* Check if a device is free which can satisfy the requirements */
+	for (i = 0; i < hw_mgr->num_devices; i++) {
+		hw_device = &hw_mgr->hw_device[i];
+		CAM_DBG(CAM_FD,
+			"[%d] : num_ctxts=%d, modes=%d, raw_results=%d",
+			i, hw_device->num_ctxts,
+			hw_device->hw_caps.supported_modes,
+			hw_device->hw_caps.raw_results_available);
+		if ((hw_device->num_ctxts == 0) &&
+			(fd_acquire_args->mode &
+			hw_device->hw_caps.supported_modes) &&
+			(!fd_acquire_args->get_raw_results ||
+			hw_device->hw_caps.raw_results_available)) {
+			CAM_DBG(CAM_FD, "Found dedicated HW Index=%d", i);
+			hw_device->num_ctxts++;
+			break;
+		}
+	}
+
+	/*
+	 * We couldn't find a free HW which meets requirement, now check if
+	 * there is a HW which meets acquire requirements
+	 */
+	if (i == hw_mgr->num_devices) {
+		for (i = 0; i < hw_mgr->num_devices; i++) {
+			hw_device = &hw_mgr->hw_device[i];
+			if ((fd_acquire_args->mode &
+				hw_device->hw_caps.supported_modes) &&
+				(!fd_acquire_args->get_raw_results ||
+				hw_device->hw_caps.raw_results_available)) {
+				hw_device->num_ctxts++;
+				CAM_DBG(CAM_FD, "Found sharing HW Index=%d", i);
+				break;
+			}
+		}
+	}
+
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	if ((i == hw_mgr->num_devices) || !hw_device) {
+		CAM_ERR(CAM_FD, "Couldn't acquire HW %d %d",
+			fd_acquire_args->mode,
+			fd_acquire_args->get_raw_results);
+		return -EBUSY;
+	}
+
+	CAM_DBG(CAM_FD, "Device index %d selected for this acquire", i);
+
+	/* Check if we can reserve this HW */
+	if (hw_device->hw_intf->hw_ops.reserve) {
+		hw_reserve_args.hw_ctx = hw_ctx;
+		hw_reserve_args.mode = fd_acquire_args->mode;
+		rc = hw_device->hw_intf->hw_ops.reserve(
+			hw_device->hw_intf->hw_priv, &hw_reserve_args,
+			sizeof(hw_reserve_args));
+		if (rc) {
+			CAM_ERR(CAM_FD, "Failed in HW reserve %d", rc);
+			return rc;
+		}
+		hw_ctx->ctx_hw_private = hw_reserve_args.ctx_hw_private;
+	} else {
+		CAM_ERR(CAM_FD, "Invalid reserve function");
+		return -EPERM;
+	}
+
+	/* Update required info in hw context */
+	hw_ctx->device_index = i;
+
+	CAM_DBG(CAM_FD, "ctx index=%d, hw_ctx=%d", hw_ctx->ctx_index,
+		hw_ctx->device_index);
+
+	return 0;
+}
+
+static int cam_fd_mgr_util_pdev_get_hw_intf(struct device_node *of_node,
+	int i, struct cam_hw_intf **device_hw_intf)
+{
+	struct device_node *device_node = NULL;
+	struct platform_device *child_pdev = NULL;
+	struct cam_hw_intf *hw_intf = NULL;
+	const char *name = NULL;
+	int rc;
+
+	rc = of_property_read_string_index(of_node, "compat-hw-name", i, &name);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Getting dev object name failed %d %d", i, rc);
+		goto put_node;
+	}
+
+	device_node = of_find_node_by_name(NULL, name);
+	if (!device_node) {
+		CAM_ERR(CAM_FD, "Cannot find node in dtsi %s", name);
+		return -ENODEV;
+	}
+
+	child_pdev = of_find_device_by_node(device_node);
+	if (!child_pdev) {
+		CAM_ERR(CAM_FD, "Failed to find device on bus %s",
+			device_node->name);
+		rc = -ENODEV;
+		goto put_node;
+	}
+
+	hw_intf = (struct cam_hw_intf *)platform_get_drvdata(child_pdev);
+	if (!hw_intf) {
+		CAM_ERR(CAM_FD, "No driver data for child device");
+		rc = -ENODEV;
+		goto put_node;
+	}
+
+	CAM_DBG(CAM_FD, "child type %d index %d child_intf %pK",
+		hw_intf->hw_type, hw_intf->hw_idx, hw_intf);
+
+	if (hw_intf->hw_idx >= CAM_FD_HW_MAX) {
+		CAM_ERR(CAM_FD, "hw_idx invalid %d", hw_intf->hw_idx);
+		rc = -ENODEV;
+		goto put_node;
+	}
+
+	rc = 0;
+	*device_hw_intf = hw_intf;
+
+put_node:
+	of_node_put(device_node);
+
+	return rc;
+}
+
+static int cam_fd_packet_generic_blob_handler(void *user_data,
+	uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
+{
+	struct cam_fd_hw_cmd_prestart_args *prestart_args =
+		(struct cam_fd_hw_cmd_prestart_args *)user_data;
+
+	if (!blob_data || (blob_size == 0)) {
+		CAM_ERR(CAM_FD, "Invalid blob info %pK %d", blob_data,
+			blob_size);
+		return -EINVAL;
+	}
+
+	if (!prestart_args) {
+		CAM_ERR(CAM_FD, "Invalid user data");
+		return -EINVAL;
+	}
+
+	switch (blob_type) {
+	case CAM_FD_BLOB_TYPE_RAW_RESULTS_REQUIRED: {
+		uint32_t *get_raw_results = (uint32_t *)blob_data;
+
+		if (sizeof(uint32_t) != blob_size) {
+			CAM_ERR(CAM_FD, "Invalid blob size %d %d",
+				sizeof(uint32_t), blob_size);
+			return -EINVAL;
+		}
+
+		prestart_args->get_raw_results = *get_raw_results;
+		break;
+	}
+	case CAM_FD_BLOB_TYPE_SOC_CLOCK_BW_REQUEST: {
+		struct cam_fd_soc_clock_bw_request *clk_req =
+			(struct cam_fd_soc_clock_bw_request *)blob_data;
+
+		if (sizeof(struct cam_fd_soc_clock_bw_request) != blob_size) {
+			CAM_ERR(CAM_FD, "Invalid blob size %d %d",
+				sizeof(struct cam_fd_soc_clock_bw_request),
+				blob_size);
+			return -EINVAL;
+		}
+
+		CAM_DBG(CAM_FD, "SOC Clk Request clock=%lld, bw=%lld",
+			clk_req->clock_rate, clk_req->bandwidth);
+
+		break;
+	}
+	default:
+		CAM_WARN(CAM_FD, "Unknown blob type %d", blob_type);
+		break;
+	}
+
+	return 0;
+}
+
+static int cam_fd_mgr_util_parse_generic_cmd_buffer(
+	struct cam_fd_hw_mgr_ctx *hw_ctx, struct cam_packet *packet,
+	struct cam_fd_hw_cmd_prestart_args *prestart_args)
+{
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	int i, rc = 0;
+
+	cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *)&packet->payload +
+		packet->cmd_buf_offset);
+
+	for (i = 0; i < packet->num_cmd_buf; i++) {
+		if (!cmd_desc[i].length)
+			continue;
+
+		if (cmd_desc[i].meta_data == CAM_FD_CMD_BUFFER_ID_CDM)
+			continue;
+
+		rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]);
+		if (rc)
+			return rc;
+
+		rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[i],
+			cam_fd_packet_generic_blob_handler, prestart_args);
+		if (rc)
+			CAM_ERR(CAM_FD, "Failed in processing blobs %d", rc);
+
+		break;
+	}
+
+	return rc;
+}
+
+static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl,
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_fd_hw_io_buffer *input_buf,
+	struct cam_fd_hw_io_buffer *output_buf, uint32_t io_buf_size)
+{
+	int rc = -EINVAL;
+	uint32_t i, j, plane, num_out_buf, num_in_buf;
+	struct cam_buf_io_cfg *io_cfg;
+	uint64_t io_addr[CAM_PACKET_MAX_PLANES];
+	uint64_t cpu_addr[CAM_PACKET_MAX_PLANES];
+	size_t size;
+
+	/* Get IO Buf information */
+	num_out_buf = 0;
+	num_in_buf  = 0;
+	io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *)
+		&prepare->packet->payload + prepare->packet->io_configs_offset);
+
+	for (i = 0; i < prepare->packet->num_io_configs; i++) {
+		CAM_DBG(CAM_FD,
+			"IOConfig[%d] : handle[%d] Dir[%d] Res[%d] Fence[%d], Format[%d]",
+			i, io_cfg[i].mem_handle[0], io_cfg[i].direction,
+			io_cfg[i].resource_type,
+			io_cfg[i].fence, io_cfg[i].format);
+
+		if ((num_in_buf >= io_buf_size) ||
+			(num_out_buf >= io_buf_size)) {
+			CAM_ERR(CAM_FD, "Invalid number of buffers %d %d %d",
+				num_in_buf, num_out_buf, io_buf_size);
+			return -EINVAL;
+		}
+
+		memset(io_addr, 0x0, sizeof(io_addr));
+		for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) {
+			if (!io_cfg[i].mem_handle[plane])
+				break;
+
+			rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[plane],
+				iommu_hdl, &io_addr[plane], &size);
+			if ((rc) || (io_addr[plane] >> 32)) {
+				CAM_ERR(CAM_FD, "Invalid io addr for %d %d",
+					plane, rc);
+				return -ENOMEM;
+			}
+
+			/*
+			 * Buffers may be accessed by CPU as well, we do not
+			 * know at this point, so get both and send to HW layer
+			 */
+			rc = cam_mem_get_cpu_buf(io_cfg[i].mem_handle[plane],
+				&cpu_addr[plane], &size);
+			if (rc) {
+				CAM_ERR(CAM_FD, "unable to get buf address");
+				return rc;
+			}
+
+			io_addr[plane] += io_cfg[i].offsets[plane];
+			cpu_addr[plane] += io_cfg[i].offsets[plane];
+
+			CAM_DBG(CAM_FD, "IO Address[%d][%d] : %pK, %pK",
+				io_cfg[i].direction, plane, io_addr[plane],
+				cpu_addr[plane]);
+		}
+
+		switch (io_cfg[i].direction) {
+		case CAM_BUF_INPUT: {
+			prepare->in_map_entries[num_in_buf].resource_handle =
+				io_cfg[i].resource_type;
+			prepare->in_map_entries[num_in_buf].sync_id =
+				io_cfg[i].fence;
+
+			input_buf[num_in_buf].valid = true;
+			for (j = 0; j < plane; j++) {
+				input_buf[num_in_buf].io_addr[j] = io_addr[j];
+				input_buf[num_in_buf].cpu_addr[j] = cpu_addr[j];
+			}
+			input_buf[num_in_buf].num_buf = plane;
+			input_buf[num_in_buf].io_cfg = &io_cfg[i];
+
+			num_in_buf++;
+			break;
+		}
+		case CAM_BUF_OUTPUT: {
+			prepare->out_map_entries[num_out_buf].resource_handle =
+				io_cfg[i].resource_type;
+			prepare->out_map_entries[num_out_buf].sync_id =
+				io_cfg[i].fence;
+
+			output_buf[num_out_buf].valid = true;
+			for (j = 0; j < plane; j++) {
+				output_buf[num_out_buf].io_addr[j] = io_addr[j];
+				output_buf[num_out_buf].cpu_addr[j] =
+					cpu_addr[j];
+			}
+			output_buf[num_out_buf].num_buf = plane;
+			output_buf[num_out_buf].io_cfg = &io_cfg[i];
+
+			num_out_buf++;
+			break;
+		}
+		default:
+			CAM_ERR(CAM_FD, "Unsupported io direction %d",
+				io_cfg[i].direction);
+			return -EINVAL;
+		}
+	}
+
+	prepare->num_in_map_entries  = num_in_buf;
+	prepare->num_out_map_entries = num_out_buf;
+
+	return 0;
+}
+
+static int cam_fd_mgr_util_prepare_hw_update_entries(
+	struct cam_fd_hw_mgr *hw_mgr,
+	struct cam_hw_prepare_update_args *prepare,
+	struct cam_fd_hw_cmd_prestart_args *prestart_args,
+	struct cam_kmd_buf_info *kmd_buf_info)
+{
+	int i, rc;
+	struct cam_hw_update_entry *hw_entry;
+	uint32_t num_ent;
+	struct cam_fd_hw_mgr_ctx *hw_ctx =
+		(struct cam_fd_hw_mgr_ctx *)prepare->ctxt_to_hw_map;
+	struct cam_fd_device *hw_device;
+	uint32_t kmd_buf_max_size, kmd_buf_used_bytes = 0;
+	uint32_t *kmd_buf_addr;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+
+	rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in getting device %d", rc);
+		return rc;
+	}
+
+	kmd_buf_addr = (uint32_t *)((uint8_t *)kmd_buf_info->cpu_addr +
+		kmd_buf_info->used_bytes);
+	kmd_buf_max_size = kmd_buf_info->size - kmd_buf_info->used_bytes;
+
+	prestart_args->cmd_buf_addr = kmd_buf_addr;
+	prestart_args->size  = kmd_buf_max_size;
+	prestart_args->pre_config_buf_size = 0;
+	prestart_args->post_config_buf_size = 0;
+
+	if (hw_device->hw_intf->hw_ops.process_cmd) {
+		rc = hw_device->hw_intf->hw_ops.process_cmd(
+			hw_device->hw_intf->hw_priv, CAM_FD_HW_CMD_PRESTART,
+			prestart_args,
+			sizeof(struct cam_fd_hw_cmd_prestart_args));
+		if (rc) {
+			CAM_ERR(CAM_FD, "Failed in CMD_PRESTART %d", rc);
+			return rc;
+		}
+	}
+
+	kmd_buf_used_bytes += prestart_args->pre_config_buf_size;
+	kmd_buf_used_bytes += prestart_args->post_config_buf_size;
+
+	/* HW layer is expected to add commands */
+	if (!kmd_buf_used_bytes || (kmd_buf_used_bytes > kmd_buf_max_size)) {
+		CAM_ERR(CAM_FD, "Invalid kmd used bytes %d (%d)",
+			kmd_buf_used_bytes, kmd_buf_max_size);
+		return -ENOMEM;
+	}
+
+	hw_entry = prepare->hw_update_entries;
+	num_ent = 0;
+
+	if (prestart_args->pre_config_buf_size) {
+		if ((num_ent + 1) >= prepare->max_hw_update_entries) {
+			CAM_ERR(CAM_FD, "Insufficient  HW entries :%d %d",
+				num_ent, prepare->max_hw_update_entries);
+			return -EINVAL;
+		}
+
+		hw_entry[num_ent].handle = kmd_buf_info->handle;
+		hw_entry[num_ent].len  = prestart_args->pre_config_buf_size;
+		hw_entry[num_ent].offset = kmd_buf_info->offset;
+
+		kmd_buf_info->used_bytes += prestart_args->pre_config_buf_size;
+		kmd_buf_info->offset += prestart_args->pre_config_buf_size;
+		num_ent++;
+	}
+
+	/*
+	 * set the cmd_desc to point the first command descriptor in the
+	 * packet and update hw entries with CDM command buffers
+	 */
+	cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *)
+		&prepare->packet->payload + prepare->packet->cmd_buf_offset);
+
+	for (i = 0; i < prepare->packet->num_cmd_buf; i++) {
+		if (!cmd_desc[i].length)
+			continue;
+
+		if (cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_CDM)
+			continue;
+
+		if (num_ent + 1 >= prepare->max_hw_update_entries) {
+			CAM_ERR(CAM_FD, "Insufficient  HW entries :%d %d",
+				num_ent, prepare->max_hw_update_entries);
+			return -EINVAL;
+		}
+
+		hw_entry[num_ent].handle = cmd_desc[i].mem_handle;
+		hw_entry[num_ent].len = cmd_desc[i].length;
+		hw_entry[num_ent].offset = cmd_desc[i].offset;
+		num_ent++;
+	}
+
+	if (prestart_args->post_config_buf_size) {
+		if (num_ent + 1 >= prepare->max_hw_update_entries) {
+			CAM_ERR(CAM_FD, "Insufficient  HW entries :%d %d",
+				num_ent, prepare->max_hw_update_entries);
+			return -EINVAL;
+		}
+
+		hw_entry[num_ent].handle = kmd_buf_info->handle;
+		hw_entry[num_ent].len    = prestart_args->post_config_buf_size;
+		hw_entry[num_ent].offset = kmd_buf_info->offset;
+
+		kmd_buf_info->used_bytes += prestart_args->post_config_buf_size;
+		kmd_buf_info->offset     += prestart_args->post_config_buf_size;
+
+		num_ent++;
+	}
+
+	prepare->num_hw_update_entries = num_ent;
+
+	CAM_DBG(CAM_FD, "FinalConfig : hw_entries=%d, Sync(in=%d, out=%d)",
+		prepare->num_hw_update_entries, prepare->num_in_map_entries,
+		prepare->num_out_map_entries);
+
+	return rc;
+}
+
+static int cam_fd_mgr_util_submit_frame(void *priv, void *data)
+{
+	struct cam_fd_device *hw_device;
+	struct cam_fd_hw_mgr *hw_mgr;
+	struct cam_fd_mgr_frame_request *frame_req;
+	struct cam_fd_hw_mgr_ctx *hw_ctx;
+	struct cam_fd_hw_cmd_start_args start_args;
+	int rc;
+
+	if (!priv) {
+		CAM_ERR(CAM_FD, "Invalid data");
+		return -EINVAL;
+	}
+
+	hw_mgr = (struct cam_fd_hw_mgr *)priv;
+	mutex_lock(&hw_mgr->frame_req_mutex);
+
+	/* Check if we have any frames pending in high priority list */
+	if (!list_empty(&hw_mgr->frame_pending_list_high)) {
+		CAM_DBG(CAM_FD, "Pending frames in high priority list");
+		frame_req = list_first_entry(&hw_mgr->frame_pending_list_high,
+			struct cam_fd_mgr_frame_request, list);
+	} else if (!list_empty(&hw_mgr->frame_pending_list_normal)) {
+		CAM_DBG(CAM_FD, "Pending frames in normal priority list");
+		frame_req = list_first_entry(&hw_mgr->frame_pending_list_normal,
+			struct cam_fd_mgr_frame_request, list);
+	} else {
+		mutex_unlock(&hw_mgr->frame_req_mutex);
+		CAM_DBG(CAM_FD, "No pending frames");
+		return 0;
+	}
+
+	CAM_DBG(CAM_FD, "FrameSubmit : Frame[%lld]", frame_req->request_id);
+	hw_ctx = frame_req->hw_ctx;
+	rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device);
+	if (rc) {
+		mutex_unlock(&hw_mgr->frame_req_mutex);
+		CAM_ERR(CAM_FD, "Error in getting device %d", rc);
+		return rc;
+	}
+
+	mutex_lock(&hw_device->lock);
+	if (hw_device->ready_to_process == false) {
+		mutex_unlock(&hw_device->lock);
+		mutex_unlock(&hw_mgr->frame_req_mutex);
+		return -EBUSY;
+	}
+
+	list_del_init(&frame_req->list);
+	mutex_unlock(&hw_mgr->frame_req_mutex);
+
+	if (hw_device->hw_intf->hw_ops.start) {
+		start_args.hw_ctx = hw_ctx;
+		start_args.ctx_hw_private = hw_ctx->ctx_hw_private;
+		start_args.hw_req_private = &frame_req->hw_req_private;
+		start_args.hw_update_entries = frame_req->hw_update_entries;
+		start_args.num_hw_update_entries =
+			frame_req->num_hw_update_entries;
+
+		rc = hw_device->hw_intf->hw_ops.start(
+			hw_device->hw_intf->hw_priv, &start_args,
+			sizeof(start_args));
+		if (rc) {
+			CAM_ERR(CAM_FD, "Failed in HW Start %d", rc);
+			mutex_unlock(&hw_device->lock);
+			goto put_req_into_free_list;
+		}
+	} else {
+		CAM_ERR(CAM_FD, "Invalid hw_ops.start");
+		mutex_unlock(&hw_device->lock);
+		rc = -EPERM;
+		goto put_req_into_free_list;
+	}
+
+	hw_device->ready_to_process = false;
+	mutex_unlock(&hw_device->lock);
+
+	rc = cam_fd_mgr_util_put_frame_req(
+		&hw_mgr->frame_processing_list, &frame_req);
+	if (rc) {
+		CAM_ERR(CAM_FD,
+			"Failed in putting frame req in processing list");
+		goto stop_unlock;
+	}
+
+	return rc;
+
+stop_unlock:
+	if (hw_device->hw_intf->hw_ops.stop) {
+		struct cam_fd_hw_stop_args stop_args;
+
+		stop_args.hw_ctx = hw_ctx;
+		stop_args.ctx_hw_private = hw_ctx->ctx_hw_private;
+		stop_args.hw_req_private = &frame_req->hw_req_private;
+		if (hw_device->hw_intf->hw_ops.stop(
+			hw_device->hw_intf->hw_priv, &stop_args,
+			sizeof(stop_args)))
+			CAM_ERR(CAM_FD, "Failed in HW Stop %d", rc);
+	}
+put_req_into_free_list:
+	cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, &frame_req);
+
+	return rc;
+}
+
+static int cam_fd_mgr_util_schedule_frame_worker_task(
+	struct cam_fd_hw_mgr *hw_mgr)
+{
+	int32_t rc = 0;
+	struct crm_workq_task *task;
+	struct cam_fd_mgr_work_data *work_data;
+
+	task = cam_req_mgr_workq_get_task(hw_mgr->work);
+	if (!task) {
+		CAM_ERR(CAM_FD, "no empty task available");
+		return -ENOMEM;
+	}
+
+	work_data = (struct cam_fd_mgr_work_data *)task->payload;
+	work_data->type = CAM_FD_WORK_FRAME;
+
+	task->process_cb = cam_fd_mgr_util_submit_frame;
+	rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0);
+
+	return rc;
+}
+
+static int32_t cam_fd_mgr_workq_irq_cb(void *priv, void *data)
+{
+	struct cam_fd_device *hw_device = NULL;
+	struct cam_fd_hw_mgr *hw_mgr;
+	struct cam_fd_mgr_work_data *work_data;
+	struct cam_fd_mgr_frame_request *frame_req = NULL;
+	enum cam_fd_hw_irq_type irq_type;
+	bool frame_abort = true;
+	int rc;
+
+	if (!data || !priv) {
+		CAM_ERR(CAM_FD, "Invalid data %pK %pK", data, priv);
+		return -EINVAL;
+	}
+
+	hw_mgr = (struct cam_fd_hw_mgr *)priv;
+	work_data = (struct cam_fd_mgr_work_data *)data;
+	irq_type = work_data->irq_type;
+
+	CAM_DBG(CAM_FD, "FD IRQ type=%d", irq_type);
+
+	if (irq_type == CAM_FD_IRQ_HALT_DONE) {
+		/* HALT would be followed by a RESET, ignore this */
+		CAM_DBG(CAM_FD, "HALT IRQ callback");
+		return 0;
+	}
+
+	/* Get the frame from processing list */
+	rc = cam_fd_mgr_util_get_frame_req(&hw_mgr->frame_processing_list,
+		&frame_req);
+	if (rc || !frame_req) {
+		/*
+		 * This can happen if reset is triggered while no frames
+		 * were pending, so not an error, just continue to check if
+		 * there are any pending frames and submit
+		 */
+		CAM_DBG(CAM_FD, "No Frame in processing list, rc=%d", rc);
+		goto submit_next_frame;
+	}
+
+	if (!frame_req->hw_ctx) {
+		CAM_ERR(CAM_FD, "Invalid Frame request %lld",
+			frame_req->request_id);
+		goto put_req_in_free_list;
+	}
+
+	rc = cam_fd_mgr_util_get_device(hw_mgr, frame_req->hw_ctx, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in getting device %d", rc);
+		goto put_req_in_free_list;
+	}
+
+	/* Read frame results first */
+	if (irq_type == CAM_FD_IRQ_FRAME_DONE) {
+		struct cam_fd_hw_frame_done_args frame_done_args;
+
+		CAM_DBG(CAM_FD, "FrameDone : Frame[%lld]",
+			frame_req->request_id);
+
+		frame_done_args.hw_ctx = frame_req->hw_ctx;
+		frame_done_args.ctx_hw_private =
+			frame_req->hw_ctx->ctx_hw_private;
+		frame_done_args.request_id = frame_req->request_id;
+		frame_done_args.hw_req_private = &frame_req->hw_req_private;
+
+		if (hw_device->hw_intf->hw_ops.process_cmd) {
+			rc = hw_device->hw_intf->hw_ops.process_cmd(
+				hw_device->hw_intf->hw_priv,
+				CAM_FD_HW_CMD_FRAME_DONE,
+				&frame_done_args, sizeof(frame_done_args));
+			if (rc) {
+				CAM_ERR(CAM_FD, "Failed in CMD_PRESTART %d",
+					rc);
+				frame_abort = true;
+				goto notify_context;
+			}
+		}
+
+		frame_abort = false;
+	}
+
+notify_context:
+	/* Do a callback to inform frame done or stop done */
+	if (frame_req->hw_ctx->event_cb) {
+		struct cam_hw_done_event_data buf_data;
+
+		CAM_DBG(CAM_FD, "FrameHALT : Frame[%lld]",
+			frame_req->request_id);
+
+		buf_data.num_handles = frame_req->num_hw_update_entries;
+		buf_data.request_id = frame_req->request_id;
+
+		rc = frame_req->hw_ctx->event_cb(frame_req->hw_ctx->cb_priv,
+			frame_abort, &buf_data);
+		if (rc)
+			CAM_ERR(CAM_FD, "Error in event cb handling %d", rc);
+	}
+
+	/*
+	 * Now we can set hw device is free to process further frames.
+	 * Note - Do not change state to IDLE until we read the frame results,
+	 * Otherwise, other thread may schedule frame processing before
+	 * reading current frame's results. Also, we need to set to IDLE state
+	 * in case some error happens after getting this irq callback
+	 */
+	mutex_lock(&hw_device->lock);
+	hw_device->ready_to_process = true;
+	CAM_DBG(CAM_FD, "ready_to_process=%d", hw_device->ready_to_process);
+	mutex_unlock(&hw_device->lock);
+
+put_req_in_free_list:
+	rc = cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list,
+		&frame_req);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in putting frame req in free list");
+		/* continue */
+	}
+
+submit_next_frame:
+	/* Check if there are any frames pending for processing and submit */
+	rc = cam_fd_mgr_util_submit_frame(hw_mgr, NULL);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error while submit frame, rc=%d", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int cam_fd_mgr_irq_cb(void *data, enum cam_fd_hw_irq_type irq_type)
+{
+	struct cam_fd_hw_mgr *hw_mgr = &g_fd_hw_mgr;
+	int rc = 0;
+	unsigned long flags;
+	struct crm_workq_task *task;
+	struct cam_fd_mgr_work_data *work_data;
+
+	spin_lock_irqsave(&hw_mgr->hw_mgr_slock, flags);
+	task = cam_req_mgr_workq_get_task(hw_mgr->work);
+	if (!task) {
+		CAM_ERR(CAM_FD, "no empty task available");
+		spin_unlock_irqrestore(&hw_mgr->hw_mgr_slock, flags);
+		return -ENOMEM;
+	}
+
+	work_data = (struct cam_fd_mgr_work_data *)task->payload;
+	work_data->type = CAM_FD_WORK_IRQ;
+	work_data->irq_type = irq_type;
+
+	task->process_cb = cam_fd_mgr_workq_irq_cb;
+	rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0);
+	if (rc)
+		CAM_ERR(CAM_FD, "Failed in enqueue work task, rc=%d", rc);
+
+	spin_unlock_irqrestore(&hw_mgr->hw_mgr_slock, flags);
+
+	return rc;
+}
+
+static int cam_fd_mgr_hw_get_caps(void *hw_mgr_priv, void *hw_get_caps_args)
+{
+	int rc = 0;
+	struct cam_fd_hw_mgr *hw_mgr = hw_mgr_priv;
+	struct cam_query_cap_cmd *query = hw_get_caps_args;
+	struct cam_fd_query_cap_cmd query_fd;
+
+	if (copy_from_user(&query_fd, (void __user *)query->caps_handle,
+		sizeof(struct cam_fd_query_cap_cmd))) {
+		CAM_ERR(CAM_FD, "Failed in copy from user, rc=%d", rc);
+		return -EFAULT;
+	}
+
+	query_fd  = hw_mgr->fd_caps;
+
+	CAM_DBG(CAM_FD,
+		"IOMMU device(%d, %d), CDM(%d, %d), versions %d.%d, %d.%d",
+		query_fd.device_iommu.secure, query_fd.device_iommu.non_secure,
+		query_fd.cdm_iommu.secure, query_fd.cdm_iommu.non_secure,
+		query_fd.hw_caps.core_version.major,
+		query_fd.hw_caps.core_version.minor,
+		query_fd.hw_caps.wrapper_version.major,
+		query_fd.hw_caps.wrapper_version.minor);
+
+	if (copy_to_user((void __user *)query->caps_handle, &query_fd,
+		sizeof(struct cam_fd_query_cap_cmd)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int cam_fd_mgr_hw_acquire(void *hw_mgr_priv, void *hw_acquire_args)
+{
+	struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv;
+	struct cam_hw_acquire_args *acquire_args =
+		(struct cam_hw_acquire_args *)hw_acquire_args;
+	struct cam_fd_hw_mgr_ctx *hw_ctx;
+	struct cam_fd_acquire_dev_info fd_acquire_args;
+	int rc;
+
+	if (!acquire_args || acquire_args->num_acq <= 0) {
+		CAM_ERR(CAM_FD, "Invalid acquire args %pK", acquire_args);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&fd_acquire_args,
+		(void __user *)acquire_args->acquire_info,
+		sizeof(struct cam_fd_acquire_dev_info))) {
+		CAM_ERR(CAM_FD, "Copy from user failed");
+		return -EFAULT;
+	}
+
+	CAM_DBG(CAM_FD, "Acquire : mode=%d, get_raw_results=%d, priority=%d",
+		fd_acquire_args.mode, fd_acquire_args.get_raw_results,
+		fd_acquire_args.priority);
+
+	/* get a free fd hw mgr ctx */
+	rc = cam_fd_mgr_util_get_ctx(&hw_mgr->free_ctx_list, &hw_ctx);
+	if (rc || !hw_ctx) {
+		CAM_ERR(CAM_FD, "Get hw context failed, rc=%d, hw_ctx=%pK",
+			rc, hw_ctx);
+		return -EINVAL;
+	}
+
+	if (fd_acquire_args.get_raw_results && !hw_mgr->raw_results_available) {
+		CAM_ERR(CAM_FD, "HW cannot support raw results %d (%d)",
+			fd_acquire_args.get_raw_results,
+			hw_mgr->raw_results_available);
+		goto put_ctx;
+	}
+
+	if (!(fd_acquire_args.mode & hw_mgr->supported_modes)) {
+		CAM_ERR(CAM_FD, "HW cannot support requested mode 0x%x (0x%x)",
+			fd_acquire_args.mode, hw_mgr->supported_modes);
+		rc = -EPERM;
+		goto put_ctx;
+	}
+
+	rc = cam_fd_mgr_util_select_device(hw_mgr, hw_ctx, &fd_acquire_args);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in selecting device, rc=%d", rc);
+		goto put_ctx;
+	}
+
+	hw_ctx->ctx_in_use = true;
+	hw_ctx->hw_mgr = hw_mgr;
+	hw_ctx->get_raw_results = fd_acquire_args.get_raw_results;
+	hw_ctx->mode = fd_acquire_args.mode;
+
+	/* Save incoming cam core info into hw ctx*/
+	hw_ctx->cb_priv = acquire_args->context_data;
+	hw_ctx->event_cb = acquire_args->event_cb;
+
+	/* Update out args */
+	acquire_args->ctxt_to_hw_map = hw_ctx;
+
+	cam_fd_mgr_util_put_ctx(&hw_mgr->used_ctx_list, &hw_ctx);
+
+	return 0;
+put_ctx:
+	list_del_init(&hw_ctx->list);
+	cam_fd_mgr_util_put_ctx(&hw_mgr->free_ctx_list, &hw_ctx);
+	return rc;
+}
+
+static int cam_fd_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args)
+{
+	struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv;
+	struct cam_hw_release_args *release_args = hw_release_args;
+	struct cam_fd_hw_mgr_ctx *hw_ctx;
+	int rc;
+
+	if (!hw_mgr_priv || !hw_release_args) {
+		CAM_ERR(CAM_FD, "Invalid arguments %pK, %pK",
+			hw_mgr_priv, hw_release_args);
+		return -EINVAL;
+	}
+
+	hw_ctx = (struct cam_fd_hw_mgr_ctx *)release_args->ctxt_to_hw_map;
+	if (!hw_ctx || !hw_ctx->ctx_in_use) {
+		CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx);
+		return -EPERM;
+	}
+
+	rc = cam_fd_mgr_util_release_device(hw_mgr, hw_ctx);
+	if (rc)
+		CAM_ERR(CAM_FD, "Failed in release device, rc=%d", rc);
+
+	list_del_init(&hw_ctx->list);
+	cam_fd_mgr_util_put_ctx(&hw_mgr->free_ctx_list, &hw_ctx);
+
+	return 0;
+}
+
+static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args)
+{
+	int rc = 0;
+	struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv;
+	struct cam_hw_start_args *hw_mgr_start_args =
+		(struct cam_hw_start_args *)mgr_start_args;
+	struct cam_fd_hw_mgr_ctx *hw_ctx;
+	struct cam_fd_device *hw_device;
+	struct cam_fd_hw_init_args hw_init_args;
+
+	if (!hw_mgr_priv || !hw_mgr_start_args) {
+		CAM_ERR(CAM_FD, "Invalid arguments %pK %pK",
+			hw_mgr_priv, hw_mgr_start_args);
+		return -EINVAL;
+	}
+
+	hw_ctx = (struct cam_fd_hw_mgr_ctx *)hw_mgr_start_args->ctxt_to_hw_map;
+	if (!hw_ctx || !hw_ctx->ctx_in_use) {
+		CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx);
+		return -EPERM;
+	}
+
+	CAM_DBG(CAM_FD, "ctx index=%d, hw_ctx=%d", hw_ctx->ctx_index,
+		hw_ctx->device_index);
+
+	rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in getting device %d", rc);
+		return rc;
+	}
+
+	if (hw_device->hw_intf->hw_ops.init) {
+		hw_init_args.hw_ctx = hw_ctx;
+		hw_init_args.ctx_hw_private = hw_ctx->ctx_hw_private;
+		rc = hw_device->hw_intf->hw_ops.init(
+			hw_device->hw_intf->hw_priv, &hw_init_args,
+			sizeof(hw_init_args));
+		if (rc) {
+			CAM_ERR(CAM_FD, "Failed in HW Init %d", rc);
+			return rc;
+		}
+	} else {
+		CAM_ERR(CAM_FD, "Invalid init function");
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int cam_fd_mgr_hw_stop(void *hw_mgr_priv, void *mgr_stop_args)
+{
+	struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv;
+	struct cam_hw_stop_args *hw_mgr_stop_args =
+		(struct cam_hw_stop_args *)mgr_stop_args;
+	struct cam_fd_hw_mgr_ctx *hw_ctx;
+	struct cam_fd_device *hw_device;
+	struct cam_fd_hw_stop_args hw_stop_args;
+	struct cam_fd_hw_deinit_args hw_deinit_args;
+	int rc = 0;
+
+	if (!hw_mgr_priv || !hw_mgr_stop_args) {
+		CAM_ERR(CAM_FD, "Invalid arguments %pK %pK",
+			hw_mgr_priv, hw_mgr_stop_args);
+		return -EINVAL;
+	}
+
+	hw_ctx = (struct cam_fd_hw_mgr_ctx *)hw_mgr_stop_args->ctxt_to_hw_map;
+	if (!hw_ctx || !hw_ctx->ctx_in_use) {
+		CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx);
+		return -EPERM;
+	}
+	CAM_DBG(CAM_FD, "ctx index=%d, hw_ctx=%d", hw_ctx->ctx_index,
+		hw_ctx->device_index);
+
+	rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in getting device %d", rc);
+		return rc;
+	}
+
+	CAM_DBG(CAM_FD, "FD Device ready_to_process = %d",
+		hw_device->ready_to_process);
+
+	if ((hw_device->hw_intf->hw_ops.stop) &&
+		(hw_device->ready_to_process == false)) {
+		/*
+		 * Even if device is in processing state, we should submit
+		 * stop command only if this ctx is running on hw
+		 */
+		hw_stop_args.hw_ctx = hw_ctx;
+		rc = hw_device->hw_intf->hw_ops.stop(
+			hw_device->hw_intf->hw_priv, &hw_stop_args,
+			sizeof(hw_stop_args));
+		if (rc) {
+			CAM_ERR(CAM_FD, "Failed in HW Stop %d", rc);
+			return rc;
+		}
+	}
+
+	if (hw_device->hw_intf->hw_ops.deinit) {
+		hw_deinit_args.hw_ctx = hw_ctx;
+		hw_deinit_args.ctx_hw_private = hw_ctx->ctx_hw_private;
+		rc = hw_device->hw_intf->hw_ops.deinit(
+			hw_device->hw_intf->hw_priv, &hw_deinit_args,
+			sizeof(hw_deinit_args));
+		if (rc) {
+			CAM_ERR(CAM_FD, "Failed in HW DeInit %d", rc);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+static int cam_fd_mgr_hw_prepare_update(void *hw_mgr_priv,
+	void *hw_prepare_update_args)
+{
+	struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv;
+	struct cam_hw_prepare_update_args *prepare =
+		(struct cam_hw_prepare_update_args *) hw_prepare_update_args;
+	struct cam_fd_hw_mgr_ctx *hw_ctx;
+	struct cam_fd_device *hw_device;
+	struct cam_kmd_buf_info kmd_buf;
+	int rc;
+	struct cam_fd_hw_cmd_prestart_args prestart_args;
+	struct cam_fd_mgr_frame_request *frame_req;
+
+	if (!hw_mgr_priv || !hw_prepare_update_args) {
+		CAM_ERR(CAM_FD, "Invalid args %pK %pK",
+			hw_mgr_priv, hw_prepare_update_args);
+		return -EINVAL;
+	}
+
+	hw_ctx = (struct cam_fd_hw_mgr_ctx *)prepare->ctxt_to_hw_map;
+	if (!hw_ctx || !hw_ctx->ctx_in_use) {
+		CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx);
+		return -EPERM;
+	}
+
+	rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in getting device %d", rc);
+		goto error;
+	}
+
+	rc = cam_fd_mgr_util_packet_validate(prepare->packet);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in packet validation %d", rc);
+		goto error;
+	}
+
+	rc = cam_packet_util_get_kmd_buffer(prepare->packet, &kmd_buf);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in get kmd buf buffer %d", rc);
+		goto error;
+	}
+
+	CAM_DBG(CAM_FD,
+		"KMD Buf : hdl=%d, cpu_addr=%pK, offset=%d, size=%d, used=%d",
+		kmd_buf.handle, kmd_buf.cpu_addr, kmd_buf.offset,
+		kmd_buf.size, kmd_buf.used_bytes);
+
+	/* We do not expect any patching, but just do it anyway */
+	rc = cam_packet_util_process_patches(prepare->packet,
+		hw_mgr->device_iommu.non_secure);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Patch FD packet failed, rc=%d", rc);
+		return rc;
+	}
+
+	memset(&prestart_args, 0x0, sizeof(prestart_args));
+	prestart_args.ctx_hw_private = hw_ctx->ctx_hw_private;
+	prestart_args.hw_ctx = hw_ctx;
+	prestart_args.request_id = prepare->packet->header.request_id;
+
+	rc = cam_fd_mgr_util_parse_generic_cmd_buffer(hw_ctx, prepare->packet,
+		&prestart_args);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in parsing gerneric cmd buffer %d", rc);
+		goto error;
+	}
+
+	rc = cam_fd_mgr_util_prepare_io_buf_info(
+		hw_mgr->device_iommu.non_secure, prepare,
+		prestart_args.input_buf, prestart_args.output_buf,
+		CAM_FD_MAX_IO_BUFFERS);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in prepare IO Buf %d", rc);
+		goto error;
+	}
+
+	rc = cam_fd_mgr_util_prepare_hw_update_entries(hw_mgr, prepare,
+		&prestart_args, &kmd_buf);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in hw update entries %d", rc);
+		goto error;
+	}
+
+	/* get a free frame req from free list */
+	rc = cam_fd_mgr_util_get_frame_req(&hw_mgr->frame_free_list,
+		&frame_req);
+	if (rc || !frame_req) {
+		CAM_ERR(CAM_FD, "Get frame_req failed, rc=%d, hw_ctx=%pK",
+			rc, hw_ctx);
+		return -ENOMEM;
+	}
+
+	/* Setup frame request info and queue to pending list */
+	frame_req->hw_ctx = hw_ctx;
+	frame_req->request_id = prepare->packet->header.request_id;
+	/* This has to be passed to HW while calling hw_ops->start */
+	frame_req->hw_req_private = prestart_args.hw_req_private;
+
+	/*
+	 * Save the current frame_req into priv,
+	 * this will come as priv while hw_config
+	 */
+	prepare->priv = frame_req;
+
+	CAM_DBG(CAM_FD, "FramePrepare : Frame[%lld]", frame_req->request_id);
+
+	return 0;
+error:
+	return rc;
+}
+
+static int cam_fd_mgr_hw_config(void *hw_mgr_priv, void *hw_config_args)
+{
+	struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv;
+	struct cam_hw_config_args *config =
+		(struct cam_hw_config_args *) hw_config_args;
+	struct cam_fd_hw_mgr_ctx *hw_ctx;
+	struct cam_fd_mgr_frame_request *frame_req;
+	int rc;
+	int i;
+
+	if (!hw_mgr || !config) {
+		CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", hw_mgr, config);
+		return -EINVAL;
+	}
+
+	if (!config->num_hw_update_entries) {
+		CAM_ERR(CAM_FD, "No hw update enteries are available");
+		return -EINVAL;
+	}
+
+	hw_ctx = (struct cam_fd_hw_mgr_ctx *)config->ctxt_to_hw_map;
+	if (!hw_ctx || !hw_ctx->ctx_in_use) {
+		CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx);
+		return -EPERM;
+	}
+
+	frame_req = config->priv;
+	CAM_DBG(CAM_FD, "FrameHWConfig : Frame[%lld]", frame_req->request_id);
+
+	frame_req->num_hw_update_entries = config->num_hw_update_entries;
+	for (i = 0; i < config->num_hw_update_entries; i++) {
+		frame_req->hw_update_entries[i] = config->hw_update_entries[i];
+		CAM_DBG(CAM_FD, "PreStart HWEntry[%d] : %d %d %d %d %pK",
+			frame_req->hw_update_entries[i].handle,
+			frame_req->hw_update_entries[i].offset,
+			frame_req->hw_update_entries[i].len,
+			frame_req->hw_update_entries[i].flags,
+			frame_req->hw_update_entries[i].addr);
+	}
+
+	if (hw_ctx->priority == CAM_FD_PRIORITY_HIGH) {
+		CAM_DBG(CAM_FD, "Insert frame into prio0 queue");
+		rc = cam_fd_mgr_util_put_frame_req(
+			&hw_mgr->frame_pending_list_high, &frame_req);
+	} else {
+		CAM_DBG(CAM_FD, "Insert frame into prio1 queue");
+		rc = cam_fd_mgr_util_put_frame_req(
+			&hw_mgr->frame_pending_list_normal, &frame_req);
+	}
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in queuing frame req, rc=%d", rc);
+		goto put_free_list;
+	}
+
+	rc = cam_fd_mgr_util_schedule_frame_worker_task(hw_mgr);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Worker task scheduling failed %d", rc);
+		goto remove_and_put_free_list;
+	}
+
+	return 0;
+
+remove_and_put_free_list:
+
+	if (hw_ctx->priority == CAM_FD_PRIORITY_HIGH) {
+		CAM_DBG(CAM_FD, "Removing frame into prio0 queue");
+		cam_fd_mgr_util_get_frame_req(
+			&hw_mgr->frame_pending_list_high, &frame_req);
+	} else {
+		CAM_DBG(CAM_FD, "Removing frame into prio1 queue");
+		cam_fd_mgr_util_get_frame_req(
+			&hw_mgr->frame_pending_list_normal, &frame_req);
+	}
+put_free_list:
+	cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list,
+		&frame_req);
+
+	return rc;
+}
+
+int cam_fd_hw_mgr_deinit(struct device_node *of_node)
+{
+	CAM_DBG(CAM_FD, "HW Mgr Deinit");
+
+	cam_req_mgr_workq_destroy(&g_fd_hw_mgr.work);
+
+	cam_smmu_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_DETACH);
+	cam_smmu_destroy_handle(g_fd_hw_mgr.device_iommu.non_secure);
+	g_fd_hw_mgr.device_iommu.non_secure = -1;
+
+	mutex_destroy(&g_fd_hw_mgr.ctx_mutex);
+	mutex_destroy(&g_fd_hw_mgr.frame_req_mutex);
+	mutex_destroy(&g_fd_hw_mgr.hw_mgr_mutex);
+
+	return 0;
+}
+
+int cam_fd_hw_mgr_init(struct device_node *of_node,
+	struct cam_hw_mgr_intf *hw_mgr_intf)
+{
+	int count, i, rc = 0;
+	struct cam_hw_intf *hw_intf = NULL;
+	struct cam_fd_hw_mgr_ctx *hw_mgr_ctx;
+	struct cam_fd_device *hw_device;
+	struct cam_fd_mgr_frame_request *frame_req;
+
+	if (!of_node || !hw_mgr_intf) {
+		CAM_ERR(CAM_FD, "Invalid args of_node %pK hw_mgr_intf %pK",
+			of_node, hw_mgr_intf);
+		return -EINVAL;
+	}
+
+	memset(&g_fd_hw_mgr, 0x0, sizeof(g_fd_hw_mgr));
+	memset(hw_mgr_intf, 0x0, sizeof(*hw_mgr_intf));
+
+	mutex_init(&g_fd_hw_mgr.ctx_mutex);
+	mutex_init(&g_fd_hw_mgr.frame_req_mutex);
+	mutex_init(&g_fd_hw_mgr.hw_mgr_mutex);
+	spin_lock_init(&g_fd_hw_mgr.hw_mgr_slock);
+
+	count = of_property_count_strings(of_node, "compat-hw-name");
+	if (!count || (count > CAM_FD_HW_MAX)) {
+		CAM_ERR(CAM_FD, "Invalid compat names in dev tree %d", count);
+		return -EINVAL;
+	}
+	g_fd_hw_mgr.num_devices = count;
+
+	g_fd_hw_mgr.raw_results_available = false;
+	g_fd_hw_mgr.supported_modes = 0;
+
+	for (i = 0; i < count; i++) {
+		hw_device = &g_fd_hw_mgr.hw_device[i];
+
+		rc = cam_fd_mgr_util_pdev_get_hw_intf(of_node, i, &hw_intf);
+		if (rc) {
+			CAM_ERR(CAM_FD, "hw intf from pdev failed, rc=%d", rc);
+			return rc;
+		}
+
+		mutex_init(&hw_device->lock);
+
+		hw_device->valid = true;
+		hw_device->hw_intf = hw_intf;
+		hw_device->ready_to_process = true;
+
+		if (hw_device->hw_intf->hw_ops.process_cmd) {
+			struct cam_fd_hw_cmd_set_irq_cb irq_cb_args;
+
+			irq_cb_args.cam_fd_hw_mgr_cb = cam_fd_mgr_irq_cb;
+			irq_cb_args.data = hw_device;
+
+			rc = hw_device->hw_intf->hw_ops.process_cmd(
+				hw_device->hw_intf->hw_priv,
+				CAM_FD_HW_CMD_REGISTER_CALLBACK,
+				&irq_cb_args, sizeof(irq_cb_args));
+			if (rc) {
+				CAM_ERR(CAM_FD,
+					"Failed in REGISTER_CALLBACK %d", rc);
+				return rc;
+			}
+		}
+
+		if (hw_device->hw_intf->hw_ops.get_hw_caps) {
+			rc = hw_device->hw_intf->hw_ops.get_hw_caps(
+				hw_intf->hw_priv, &hw_device->hw_caps,
+				sizeof(hw_device->hw_caps));
+			if (rc) {
+				CAM_ERR(CAM_FD, "Failed in get_hw_caps %d", rc);
+				return rc;
+			}
+
+			g_fd_hw_mgr.raw_results_available |=
+				hw_device->hw_caps.raw_results_available;
+			g_fd_hw_mgr.supported_modes |=
+				hw_device->hw_caps.supported_modes;
+
+			CAM_DBG(CAM_FD,
+				"Device[mode=%d, raw=%d], Mgr[mode=%d, raw=%d]",
+				hw_device->hw_caps.supported_modes,
+				hw_device->hw_caps.raw_results_available,
+				g_fd_hw_mgr.supported_modes,
+				g_fd_hw_mgr.raw_results_available);
+		}
+	}
+
+	INIT_LIST_HEAD(&g_fd_hw_mgr.free_ctx_list);
+	INIT_LIST_HEAD(&g_fd_hw_mgr.used_ctx_list);
+	INIT_LIST_HEAD(&g_fd_hw_mgr.frame_free_list);
+	INIT_LIST_HEAD(&g_fd_hw_mgr.frame_pending_list_high);
+	INIT_LIST_HEAD(&g_fd_hw_mgr.frame_pending_list_normal);
+	INIT_LIST_HEAD(&g_fd_hw_mgr.frame_processing_list);
+
+	g_fd_hw_mgr.device_iommu.non_secure = -1;
+	g_fd_hw_mgr.device_iommu.secure = -1;
+	g_fd_hw_mgr.cdm_iommu.non_secure = -1;
+	g_fd_hw_mgr.cdm_iommu.secure = -1;
+
+	rc = cam_smmu_get_handle("fd",
+		&g_fd_hw_mgr.device_iommu.non_secure);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Get iommu handle failed, rc=%d", rc);
+		goto destroy_mutex;
+	}
+
+	rc = cam_smmu_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_ATTACH);
+	if (rc) {
+		CAM_ERR(CAM_FD, "FD attach iommu handle failed, rc=%d", rc);
+		goto destroy_smmu;
+	}
+
+	rc = cam_cdm_get_iommu_handle("fd", &g_fd_hw_mgr.cdm_iommu);
+	if (rc)
+		CAM_DBG(CAM_FD, "Failed to acquire the CDM iommu handles");
+
+	CAM_DBG(CAM_FD, "iommu handles : device(%d, %d), cdm(%d, %d)",
+		g_fd_hw_mgr.device_iommu.non_secure,
+		g_fd_hw_mgr.device_iommu.secure,
+		g_fd_hw_mgr.cdm_iommu.non_secure,
+		g_fd_hw_mgr.cdm_iommu.secure);
+
+	/* Init hw mgr contexts and add to free list */
+	for (i = 0; i < CAM_CTX_MAX; i++) {
+		hw_mgr_ctx = &g_fd_hw_mgr.ctx_pool[i];
+
+		memset(hw_mgr_ctx, 0x0, sizeof(*hw_mgr_ctx));
+		INIT_LIST_HEAD(&hw_mgr_ctx->list);
+
+		hw_mgr_ctx->ctx_index = i;
+		hw_mgr_ctx->device_index = -1;
+		hw_mgr_ctx->hw_mgr = &g_fd_hw_mgr;
+
+		list_add_tail(&hw_mgr_ctx->list, &g_fd_hw_mgr.free_ctx_list);
+	}
+
+	/* Init hw mgr frame requests and add to free list */
+	for (i = 0; i < CAM_CTX_REQ_MAX; i++) {
+		frame_req = &g_fd_hw_mgr.frame_req[i];
+
+		memset(frame_req, 0x0, sizeof(*frame_req));
+		INIT_LIST_HEAD(&frame_req->list);
+
+		list_add_tail(&frame_req->list, &g_fd_hw_mgr.frame_free_list);
+	}
+
+	rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK,
+		&g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc);
+		goto detach_smmu;
+	}
+
+	for (i = 0; i < CAM_FD_WORKQ_NUM_TASK; i++)
+		g_fd_hw_mgr.work->task.pool[i].payload =
+			&g_fd_hw_mgr.work_data[i];
+
+	/* Setup hw cap so that we can just return the info when requested */
+	memset(&g_fd_hw_mgr.fd_caps, 0, sizeof(g_fd_hw_mgr.fd_caps));
+	g_fd_hw_mgr.fd_caps.device_iommu = g_fd_hw_mgr.device_iommu;
+	g_fd_hw_mgr.fd_caps.cdm_iommu = g_fd_hw_mgr.cdm_iommu;
+	g_fd_hw_mgr.fd_caps.hw_caps = g_fd_hw_mgr.hw_device[0].hw_caps;
+
+	CAM_DBG(CAM_FD,
+		"IOMMU device(%d, %d), CDM(%d, %d) versions core[%d.%d], wrapper[%d.%d]",
+		g_fd_hw_mgr.fd_caps.device_iommu.secure,
+		g_fd_hw_mgr.fd_caps.device_iommu.non_secure,
+		g_fd_hw_mgr.fd_caps.cdm_iommu.secure,
+		g_fd_hw_mgr.fd_caps.cdm_iommu.non_secure,
+		g_fd_hw_mgr.fd_caps.hw_caps.core_version.major,
+		g_fd_hw_mgr.fd_caps.hw_caps.core_version.minor,
+		g_fd_hw_mgr.fd_caps.hw_caps.wrapper_version.major,
+		g_fd_hw_mgr.fd_caps.hw_caps.wrapper_version.minor);
+
+	hw_mgr_intf->hw_mgr_priv = &g_fd_hw_mgr;
+	hw_mgr_intf->hw_get_caps = cam_fd_mgr_hw_get_caps;
+	hw_mgr_intf->hw_acquire = cam_fd_mgr_hw_acquire;
+	hw_mgr_intf->hw_release = cam_fd_mgr_hw_release;
+	hw_mgr_intf->hw_start = cam_fd_mgr_hw_start;
+	hw_mgr_intf->hw_stop = cam_fd_mgr_hw_stop;
+	hw_mgr_intf->hw_prepare_update = cam_fd_mgr_hw_prepare_update;
+	hw_mgr_intf->hw_config = cam_fd_mgr_hw_config;
+	hw_mgr_intf->hw_read = NULL;
+	hw_mgr_intf->hw_write = NULL;
+	hw_mgr_intf->hw_close = NULL;
+
+	return rc;
+
+detach_smmu:
+	cam_smmu_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_DETACH);
+destroy_smmu:
+	cam_smmu_destroy_handle(g_fd_hw_mgr.device_iommu.non_secure);
+	g_fd_hw_mgr.device_iommu.non_secure = -1;
+destroy_mutex:
+	mutex_destroy(&g_fd_hw_mgr.ctx_mutex);
+	mutex_destroy(&g_fd_hw_mgr.frame_req_mutex);
+	mutex_destroy(&g_fd_hw_mgr.hw_mgr_mutex);
+
+	return rc;
+}
+
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h
new file mode 100644
index 0000000..135e006
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h
@@ -0,0 +1,182 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_FD_HW_MGR_H_
+#define _CAM_FD_HW_MGR_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <media/cam_fd.h>
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_cpas_api.h"
+#include "cam_debug_util.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_req_mgr_workq.h"
+#include "cam_fd_hw_intf.h"
+
+#define CAM_FD_HW_MAX            1
+#define CAM_FD_WORKQ_NUM_TASK    10
+
+struct cam_fd_hw_mgr;
+
+/**
+ * enum cam_fd_mgr_work_type - Type of worker task
+ *
+ * @CAM_FD_WORK_FRAME : Work type indicating frame task
+ * @CAM_FD_WORK_IRQ   : Work type indicating irq task
+ */
+enum cam_fd_mgr_work_type {
+	CAM_FD_WORK_FRAME,
+	CAM_FD_WORK_IRQ,
+};
+
+/**
+ * struct cam_fd_hw_mgr_ctx : FD HW Mgr context
+ *
+ * @list            : List pointer used to maintain this context
+ *                    in free, used list
+ * @ctx_index       : Index of this context
+ * @ctx_in_use      : Whether this context is in use
+ * @event_cb        : Event callback pointer to notify cam core context
+ * @cb_priv         : Event callback private pointer
+ * @hw_mgr          : Pointer to hw manager
+ * @get_raw_results : Whether this context needs raw results
+ * @mode            : Mode in which this context runs
+ * @device_index    : HW Device used by this context
+ * @ctx_hw_private  : HW layer's private context pointer for this context
+ * @priority        : Priority of this context
+ */
+struct cam_fd_hw_mgr_ctx {
+	struct list_head               list;
+	uint32_t                       ctx_index;
+	bool                           ctx_in_use;
+	cam_hw_event_cb_func           event_cb;
+	void                          *cb_priv;
+	struct cam_fd_hw_mgr          *hw_mgr;
+	bool                           get_raw_results;
+	enum cam_fd_hw_mode            mode;
+	int32_t                        device_index;
+	void                          *ctx_hw_private;
+	uint32_t                       priority;
+};
+
+/**
+ * struct cam_fd_device : FD HW Device
+ *
+ * @hw_caps          : This FD device's capabilities
+ * @hw_intf          : FD device's interface information
+ * @ready_to_process : Whether this device is ready to process next frame
+ * @num_ctxts        : Number of context currently running on this device
+ * @valid            : Whether this device is valid
+ * @lock             : Lock used for protectin
+ */
+struct cam_fd_device {
+	struct cam_fd_hw_caps    hw_caps;
+	struct cam_hw_intf      *hw_intf;
+	bool                     ready_to_process;
+	uint32_t                 num_ctxts;
+	bool                     valid;
+	struct mutex             lock;
+};
+
+/**
+ * struct cam_fd_mgr_frame_request : Frame request information maintained
+ *                                   in HW Mgr layer
+ *
+ * @list                  : List pointer used to maintain this request in
+ *                          free, pending, processing request lists
+ * @request_id            : Request ID corresponding to this request
+ * @hw_ctx                : HW context from which this request is coming
+ * @hw_req_private        : HW layer's private information specific to
+ *                          this request
+ * @hw_update_entries     : HW update entries corresponding to this request
+ *                          which needs to be submitted to HW through CDM
+ * @num_hw_update_entries : Number of HW update entries
+ */
+struct cam_fd_mgr_frame_request {
+	struct list_head               list;
+	uint64_t                       request_id;
+	struct cam_fd_hw_mgr_ctx      *hw_ctx;
+	struct cam_fd_hw_req_private   hw_req_private;
+	struct cam_hw_update_entry     hw_update_entries[CAM_FD_MAX_HW_ENTRIES];
+	uint32_t                       num_hw_update_entries;
+};
+
+/**
+ * struct cam_fd_mgr_work_data : HW Mgr work data information
+ *
+ * @type     : Type of work
+ * @irq_type : IRQ type when this work is queued because of irq callback
+ */
+struct cam_fd_mgr_work_data {
+	enum cam_fd_mgr_work_type      type;
+	enum cam_fd_hw_irq_type        irq_type;
+};
+
+/**
+ * struct cam_fd_hw_mgr : FD HW Mgr information
+ *
+ * @free_ctx_list             : List of free contexts available for acquire
+ * @used_ctx_list             : List of contexts that are acquired
+ * @frame_free_list           : List of free frame requests available
+ * @frame_pending_list_high   : List of high priority frame requests pending
+ *                              for processing
+ * @frame_pending_list_normal : List of normal priority frame requests pending
+ *                              for processing
+ * @frame_processing_list     : List of frame requests currently being
+ *                              processed currently. Generally maximum one
+ *                              request would be present in this list
+ * @hw_mgr_mutex              : Mutex to protect hw mgr data when accessed
+ *                              from multiple threads
+ * @hw_mgr_slock              : Spin lock to protect hw mgr data when accessed
+ *                              from multiple threads
+ * @ctx_mutex                 : Mutex to protect context list
+ * @frame_req_mutex           : Mutex to protect frame request list
+ * @device_iommu              : Device IOMMU information
+ * @cdm_iommu                 : CDM IOMMU information
+ * @hw_device                 : Underlying HW device information
+ * @num_devices               : Number of HW devices available
+ * @raw_results_available     : Whether raw results available in this driver
+ * @supported_modes           : Supported modes by this driver
+ * @ctx_pool                  : List of context
+ * @frame_req                 : List of frame requests
+ * @work                      : Worker handle
+ * @work_data                 : Worker data
+ * @fd_caps                   : FD driver capabilities
+ */
+struct cam_fd_hw_mgr {
+	struct list_head                   free_ctx_list;
+	struct list_head                   used_ctx_list;
+	struct list_head                   frame_free_list;
+	struct list_head                   frame_pending_list_high;
+	struct list_head                   frame_pending_list_normal;
+	struct list_head                   frame_processing_list;
+	struct mutex                       hw_mgr_mutex;
+	spinlock_t                         hw_mgr_slock;
+	struct mutex                       ctx_mutex;
+	struct mutex                       frame_req_mutex;
+	struct cam_iommu_handle            device_iommu;
+	struct cam_iommu_handle            cdm_iommu;
+	struct cam_fd_device               hw_device[CAM_FD_HW_MAX];
+	uint32_t                           num_devices;
+	bool                               raw_results_available;
+	uint32_t                           supported_modes;
+	struct cam_fd_hw_mgr_ctx           ctx_pool[CAM_CTX_MAX];
+	struct cam_fd_mgr_frame_request    frame_req[CAM_CTX_REQ_MAX];
+	struct cam_req_mgr_core_workq     *work;
+	struct cam_fd_mgr_work_data        work_data[CAM_FD_WORKQ_NUM_TASK];
+	struct cam_fd_query_cap_cmd        fd_caps;
+};
+
+#endif /* _CAM_FD_HW_MGR_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h
new file mode 100644
index 0000000..58cba4f
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_FD_HW_MGR_INTF_H_
+#define _CAM_FD_HW_MGR_INTF_H_
+
+#include <linux/of.h>
+
+#include "cam_debug_util.h"
+#include "cam_hw_mgr_intf.h"
+
+int cam_fd_hw_mgr_init(struct device_node *of_node,
+	struct cam_hw_mgr_intf *hw_mgr_intf);
+int cam_fd_hw_mgr_deinit(struct device_node *of_node);
+
+#endif /* _CAM_FD_HW_MGR_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/Makefile b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/Makefile
new file mode 100644
index 0000000..c3e706d
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/Makefile
@@ -0,0 +1,13 @@
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_utils
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_core
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_sync
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cdm
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd/fd_hw_mgr
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw
+ccflags-y += -Idrivers/media/platform/msm/camera
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_cpas/include
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_hw_dev.o cam_fd_hw_core.o cam_fd_hw_soc.o
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
new file mode 100644
index 0000000..51fcdcaa
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
@@ -0,0 +1,1125 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "cam_fd_hw_core.h"
+#include "cam_fd_hw_soc.h"
+
+#define CAM_FD_REG_VAL_PAIR_SIZE 256
+
+static uint32_t cam_fd_cdm_write_reg_val_pair(uint32_t *buffer,
+	uint32_t index, uint32_t reg_offset, uint32_t reg_value)
+{
+	buffer[index++] = reg_offset;
+	buffer[index++] = reg_value;
+
+	CAM_DBG(CAM_FD, "FD_CDM_CMD: Base[FD_CORE] Offset[0x%8x] Value[0x%8x]",
+		reg_offset, reg_value);
+
+	return index;
+}
+
+static void cam_fd_hw_util_cdm_callback(uint32_t handle, void *userdata,
+	enum cam_cdm_cb_status status, uint32_t cookie)
+{
+	CAM_DBG(CAM_FD, "CDM hdl=%x, udata=%pK, status=%d, cookie=%d",
+		handle, userdata, status, cookie);
+}
+
+static void cam_fd_hw_util_enable_power_on_settings(struct cam_hw_info *fd_hw)
+{
+	struct cam_hw_soc_info *soc_info = &fd_hw->soc_info;
+	struct cam_fd_hw_static_info *hw_static_info =
+		((struct cam_fd_core *)fd_hw->core_info)->hw_static_info;
+
+	if (hw_static_info->enable_errata_wa.single_irq_only == false) {
+		/* Enable IRQs here */
+		cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
+			hw_static_info->wrapper_regs.irq_mask,
+			hw_static_info->irq_mask);
+	}
+
+	/* QoS settings */
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
+		hw_static_info->wrapper_regs.vbif_req_priority,
+		hw_static_info->qos_priority);
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
+		hw_static_info->wrapper_regs.vbif_priority_level,
+		hw_static_info->qos_priority_level);
+}
+
+int cam_fd_hw_util_get_hw_caps(struct cam_hw_info *fd_hw,
+	struct cam_fd_hw_caps *hw_caps)
+{
+	struct cam_hw_soc_info *soc_info = &fd_hw->soc_info;
+	struct cam_fd_hw_static_info *hw_static_info =
+		((struct cam_fd_core *)fd_hw->core_info)->hw_static_info;
+	uint32_t reg_value;
+
+	if (!hw_static_info) {
+		CAM_ERR(CAM_FD, "Invalid hw info data");
+		return -EINVAL;
+	}
+
+	reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_CORE,
+		hw_static_info->core_regs.version);
+	hw_caps->core_version.major =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf00, 0x8);
+	hw_caps->core_version.minor =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf0, 0x4);
+	hw_caps->core_version.incr =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf, 0x0);
+
+	reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_WRAPPER,
+		hw_static_info->wrapper_regs.wrapper_version);
+	hw_caps->wrapper_version.major =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c);
+	hw_caps->wrapper_version.minor =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
+	hw_caps->wrapper_version.incr =
+		CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
+
+	hw_caps->raw_results_available =
+		hw_static_info->results.raw_results_available;
+	hw_caps->supported_modes = hw_static_info->supported_modes;
+
+	CAM_DBG(CAM_FD, "core:%d.%d.%d wrapper:%d.%d.%d intermediate:%d",
+		hw_caps->core_version.major, hw_caps->core_version.minor,
+		hw_caps->core_version.incr, hw_caps->wrapper_version.major,
+		hw_caps->wrapper_version.minor, hw_caps->wrapper_version.incr,
+		hw_caps->raw_results_available);
+
+	return 0;
+}
+
+static int cam_fd_hw_util_fdwrapper_sync_reset(struct cam_hw_info *fd_hw)
+{
+	struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info;
+	struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info;
+	struct cam_hw_soc_info *soc_info = &fd_hw->soc_info;
+	long time_left;
+
+	/* Before triggering reset to HW, clear the reset complete */
+	reinit_completion(&fd_core->reset_complete);
+
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE,
+		hw_static_info->core_regs.control, 0x1);
+
+	if (hw_static_info->enable_errata_wa.single_irq_only) {
+		cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
+			hw_static_info->wrapper_regs.irq_mask,
+			CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE));
+	}
+
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
+		hw_static_info->wrapper_regs.sw_reset, 0x1);
+
+	time_left = wait_for_completion_timeout(&fd_core->reset_complete,
+		msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT));
+	if (time_left <= 0) {
+		CAM_ERR(CAM_FD, "HW reset wait failed time_left=%d", time_left);
+		return -EPERM;
+	}
+
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE,
+		hw_static_info->core_regs.control, 0x0);
+
+	CAM_DBG(CAM_FD, "FD Wrapper SW Sync Reset complete");
+
+	return 0;
+}
+
+
+static int cam_fd_hw_util_fdwrapper_halt(struct cam_hw_info *fd_hw)
+{
+	struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info;
+	struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info;
+	struct cam_hw_soc_info *soc_info = &fd_hw->soc_info;
+	long time_left;
+
+	/* Before triggering halt to HW, clear halt complete */
+	reinit_completion(&fd_core->halt_complete);
+
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE,
+		hw_static_info->core_regs.control, 0x1);
+
+	if (hw_static_info->enable_errata_wa.single_irq_only) {
+		cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
+			hw_static_info->wrapper_regs.irq_mask,
+			CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE));
+	}
+
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
+		hw_static_info->wrapper_regs.hw_stop, 0x1);
+
+	time_left = wait_for_completion_timeout(&fd_core->halt_complete,
+		msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT));
+	if (time_left <= 0) {
+		CAM_ERR(CAM_FD, "HW halt wait failed time_left=%d", time_left);
+		return -EPERM;
+	}
+
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE,
+		hw_static_info->core_regs.control, 0x0);
+
+	CAM_DBG(CAM_FD, "FD Wrapper Halt complete");
+
+	return 0;
+}
+
+static int cam_fd_hw_util_processcmd_prestart(struct cam_hw_info *fd_hw,
+	struct cam_fd_hw_cmd_prestart_args *prestart_args)
+{
+	struct cam_hw_soc_info *soc_info = &fd_hw->soc_info;
+	struct cam_fd_hw_static_info *hw_static_info =
+		((struct cam_fd_core *)fd_hw->core_info)->hw_static_info;
+	struct cam_fd_ctx_hw_private *ctx_hw_private =
+		prestart_args->ctx_hw_private;
+	uint32_t size, size_required = 0;
+	uint32_t mem_base;
+	uint32_t *cmd_buf_addr = prestart_args->cmd_buf_addr;
+	uint32_t reg_val_pair[CAM_FD_REG_VAL_PAIR_SIZE];
+	uint32_t num_cmds = 0;
+	int i;
+	struct cam_fd_hw_io_buffer *io_buf;
+	struct cam_fd_hw_req_private *req_private;
+	uint32_t available_size = prestart_args->size;
+	bool work_buffer_configured = false;
+
+	if (!ctx_hw_private || !cmd_buf_addr) {
+		CAM_ERR(CAM_FD, "Invalid input prestart args %pK %pK",
+			ctx_hw_private, cmd_buf_addr);
+		return -EINVAL;
+	}
+
+	if (prestart_args->get_raw_results &&
+		!hw_static_info->results.raw_results_available) {
+		CAM_ERR(CAM_FD, "Raw results not supported %d %d",
+			prestart_args->get_raw_results,
+			hw_static_info->results.raw_results_available);
+		return -EINVAL;
+	}
+
+	req_private = &prestart_args->hw_req_private;
+	req_private->ctx_hw_private = prestart_args->ctx_hw_private;
+	req_private->request_id = prestart_args->request_id;
+	req_private->get_raw_results = prestart_args->get_raw_results;
+	req_private->fd_results = NULL;
+	req_private->raw_results = NULL;
+
+	/* Start preparing CDM register values that KMD has to insert */
+	num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, num_cmds,
+		hw_static_info->core_regs.control, 0x1);
+	num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, num_cmds,
+		hw_static_info->core_regs.control, 0x0);
+
+	for (i = 0; i < CAM_FD_MAX_IO_BUFFERS; i++) {
+		io_buf = &prestart_args->input_buf[i];
+
+		if (io_buf->valid == false)
+			break;
+
+		if (io_buf->io_cfg->direction != CAM_BUF_INPUT) {
+			CAM_ERR(CAM_FD, "Incorrect direction %d %d",
+				io_buf->io_cfg->direction, CAM_BUF_INPUT);
+			return -EINVAL;
+		}
+
+		switch (io_buf->io_cfg->resource_type) {
+		case CAM_FD_INPUT_PORT_ID_IMAGE: {
+			if ((num_cmds + 2) > CAM_FD_REG_VAL_PAIR_SIZE) {
+				CAM_ERR(CAM_FD,
+					"Invalid reg_val pair size %d, %d",
+					num_cmds, CAM_FD_REG_VAL_PAIR_SIZE);
+				return -EINVAL;
+			}
+
+			num_cmds = cam_fd_cdm_write_reg_val_pair(
+				reg_val_pair, num_cmds,
+				hw_static_info->core_regs.image_addr,
+				io_buf->io_addr[0]);
+			break;
+		}
+		default:
+			CAM_ERR(CAM_FD, "Invalid resource type %d",
+				io_buf->io_cfg->resource_type);
+			return -EINVAL;
+		}
+	}
+
+	for (i = 0; i < CAM_FD_MAX_IO_BUFFERS; i++) {
+		io_buf = &prestart_args->output_buf[i];
+
+		if (io_buf->valid == false)
+			break;
+
+		if (io_buf->io_cfg->direction != CAM_BUF_OUTPUT) {
+			CAM_ERR(CAM_FD, "Incorrect direction %d %d",
+				io_buf->io_cfg->direction, CAM_BUF_INPUT);
+			return -EINVAL;
+		}
+
+		switch (io_buf->io_cfg->resource_type) {
+		case CAM_FD_OUTPUT_PORT_ID_RESULTS: {
+			uint32_t face_results_offset;
+
+			size_required = hw_static_info->results.max_faces *
+				hw_static_info->results.per_face_entries * 4;
+
+			if (io_buf->io_cfg->planes[0].plane_stride <
+				size_required) {
+				CAM_ERR(CAM_FD, "Invalid results size %d %d",
+					io_buf->io_cfg->planes[0].plane_stride,
+					size_required);
+				return -EINVAL;
+			}
+
+			req_private->fd_results =
+				(struct cam_fd_results *)io_buf->cpu_addr[0];
+
+			face_results_offset =
+				(uint8_t *)&req_private->fd_results->faces[0] -
+				(uint8_t *)req_private->fd_results;
+
+			if (hw_static_info->ro_mode_supported) {
+				if ((num_cmds + 4) > CAM_FD_REG_VAL_PAIR_SIZE) {
+					CAM_ERR(CAM_FD,
+						"Invalid reg_val size %d, %d",
+						num_cmds,
+						CAM_FD_REG_VAL_PAIR_SIZE);
+					return -EINVAL;
+				}
+				/*
+				 * Face data actually starts 16bytes later in
+				 * the io buffer  Check cam_fd_results.
+				 */
+				num_cmds = cam_fd_cdm_write_reg_val_pair(
+					reg_val_pair, num_cmds,
+					hw_static_info->core_regs.result_addr,
+					io_buf->io_addr[0] +
+					face_results_offset);
+				num_cmds = cam_fd_cdm_write_reg_val_pair(
+					reg_val_pair, num_cmds,
+					hw_static_info->core_regs.ro_mode,
+					0x1);
+
+				req_private->ro_mode_enabled = true;
+			} else {
+				req_private->ro_mode_enabled = false;
+			}
+			break;
+		}
+		case CAM_FD_OUTPUT_PORT_ID_RAW_RESULTS: {
+			size_required =
+				hw_static_info->results.raw_results_entries *
+				sizeof(uint32_t);
+
+			if (io_buf->io_cfg->planes[0].plane_stride <
+				size_required) {
+				CAM_ERR(CAM_FD, "Invalid results size %d %d",
+					io_buf->io_cfg->planes[0].plane_stride,
+					size_required);
+				return -EINVAL;
+			}
+
+			req_private->raw_results =
+				(uint32_t *)io_buf->cpu_addr[0];
+			break;
+		}
+		case CAM_FD_OUTPUT_PORT_ID_WORK_BUFFER: {
+			if ((num_cmds + 2) > CAM_FD_REG_VAL_PAIR_SIZE) {
+				CAM_ERR(CAM_FD,
+					"Invalid reg_val pair size %d, %d",
+					num_cmds, CAM_FD_REG_VAL_PAIR_SIZE);
+				return -EINVAL;
+			}
+
+			num_cmds = cam_fd_cdm_write_reg_val_pair(
+				reg_val_pair, num_cmds,
+				hw_static_info->core_regs.work_addr,
+				io_buf->io_addr[0]);
+
+			work_buffer_configured = true;
+			break;
+		}
+		default:
+			CAM_ERR(CAM_FD, "Invalid resource type %d",
+				io_buf->io_cfg->resource_type);
+			return -EINVAL;
+		}
+	}
+
+	if (!req_private->fd_results || !work_buffer_configured) {
+		CAM_ERR(CAM_FD, "Invalid IO Buffers results=%pK work=%d",
+			req_private->fd_results, work_buffer_configured);
+		return -EINVAL;
+	}
+
+	/* First insert CHANGE_BASE command */
+	size = ctx_hw_private->cdm_ops->cdm_required_size_changebase();
+	/* since cdm returns dwords, we need to convert it into bytes */
+	if ((size * 4) > available_size) {
+		CAM_ERR(CAM_FD, "buf size:%d is not sufficient, expected: %d",
+			prestart_args->size, size);
+		return -EINVAL;
+	}
+
+	mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info,
+		((struct cam_fd_soc_private *)soc_info->soc_private)->
+		regbase_index[CAM_FD_REG_CORE]);
+
+	ctx_hw_private->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base);
+	cmd_buf_addr += size;
+	available_size -= (size * 4);
+
+	size = ctx_hw_private->cdm_ops->cdm_required_size_reg_random(
+		num_cmds/2);
+	/* cdm util returns dwords, need to convert to bytes */
+	if ((size * 4) > available_size) {
+		CAM_ERR(CAM_FD, "Insufficient size:%d , expected size:%d",
+			available_size, size);
+		return -ENOMEM;
+	}
+	ctx_hw_private->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmds/2,
+		reg_val_pair);
+	cmd_buf_addr += size;
+	available_size -= (size * 4);
+
+	/* Update pre_config_buf_size in bytes */
+	prestart_args->pre_config_buf_size =
+		prestart_args->size - available_size;
+
+	/*
+	 * Currently, no post config commands, we trigger HW start directly
+	 * from start(). Start trigger command can be inserted into CDM
+	 * as post config commands.
+	 */
+	prestart_args->post_config_buf_size = 0;
+
+	CAM_DBG(CAM_FD, "PreConfig [%pK %d], PostConfig[%pK %d]",
+		prestart_args->cmd_buf_addr, prestart_args->pre_config_buf_size,
+		cmd_buf_addr, prestart_args->post_config_buf_size);
+
+	for (i = 0; i < (prestart_args->pre_config_buf_size +
+		prestart_args->post_config_buf_size) / 4; i++)
+		CAM_DBG(CAM_FD, "CDM KMD Commands [%d] : [%pK] [0x%x]", i,
+			&prestart_args->cmd_buf_addr[i],
+			prestart_args->cmd_buf_addr[i]);
+
+	return 0;
+}
+
+static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw,
+	struct cam_fd_hw_frame_done_args *frame_done_args)
+{
+	struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info;
+	struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info;
+	struct cam_fd_hw_req_private *req_private;
+	uint32_t base, face_cnt;
+	uint32_t *buffer;
+	int i;
+
+	spin_lock(&fd_core->spin_lock);
+	if ((fd_core->core_state != CAM_FD_CORE_STATE_IDLE) ||
+		(fd_core->results_valid == false) ||
+		!fd_core->hw_req_private) {
+		CAM_ERR(CAM_FD,
+			"Invalid state for results state=%d, results=%d %pK",
+			fd_core->core_state, fd_core->results_valid,
+			fd_core->hw_req_private);
+		spin_unlock(&fd_core->spin_lock);
+		return -EINVAL;
+	}
+	fd_core->core_state = CAM_FD_CORE_STATE_READING_RESULTS;
+	req_private = fd_core->hw_req_private;
+	spin_unlock(&fd_core->spin_lock);
+
+	/*
+	 * Copy the register value as is into output buffers.
+	 * Wehter we are copying the output data by reading registers or
+	 * programming output buffer directly to HW must be transparent to UMD.
+	 * In case HW supports writing face count value directly into
+	 * DDR memory in future, these values should match.
+	 */
+	req_private->fd_results->face_count =
+		cam_fd_soc_register_read(&fd_hw->soc_info, CAM_FD_REG_CORE,
+		hw_static_info->core_regs.result_cnt);
+
+	face_cnt = req_private->fd_results->face_count & 0x3F;
+
+	if (face_cnt > hw_static_info->results.max_faces) {
+		CAM_WARN(CAM_FD, "Face count greater than max %d %d",
+			face_cnt, hw_static_info->results.max_faces);
+		face_cnt = hw_static_info->results.max_faces;
+	}
+
+	CAM_DBG(CAM_FD, "ReqID[%lld] Faces Detected = %d",
+		req_private->request_id, face_cnt);
+
+	/*
+	 * We need to read the face data information from registers only
+	 * if one of below is true
+	 * 1. RO mode is not set. i.e FD HW doesn't write face data into
+	 *    DDR memory
+	 * 2. On the current chipset, results written into DDR memory by FD HW
+	 *    are not gauranteed to be correct
+	 */
+	if (!req_private->ro_mode_enabled ||
+		hw_static_info->enable_errata_wa.ro_mode_results_invalid) {
+		buffer = (uint32_t *)&req_private->fd_results->faces[0];
+		base = hw_static_info->core_regs.results_reg_base;
+
+		/*
+		 * Write register values as is into face data buffer.  Its UMD
+		 * driver responsibility to interpret the data and extract face
+		 * properties from output buffer. Think in case output buffer
+		 * is directly programmed to HW, then KMD has no control to
+		 * extract the face properties and UMD anyway has to extract
+		 * face properties. So we follow the same approach and keep
+		 * this transparent to UMD.
+		 */
+		for (i = 0;
+			i < (face_cnt *
+			hw_static_info->results.per_face_entries); i++) {
+			*buffer = cam_fd_soc_register_read(&fd_hw->soc_info,
+				CAM_FD_REG_CORE, base + (i * 0x4));
+			CAM_DBG(CAM_FD, "FaceData[%d] : 0x%x", i / 4, *buffer);
+			buffer++;
+		}
+	}
+
+	if (req_private->get_raw_results &&
+		req_private->raw_results &&
+		hw_static_info->results.raw_results_available) {
+		buffer = req_private->raw_results;
+		base = hw_static_info->core_regs.raw_results_reg_base;
+
+		for (i = 0;
+			i < hw_static_info->results.raw_results_entries;
+			i++) {
+			*buffer = cam_fd_soc_register_read(&fd_hw->soc_info,
+				CAM_FD_REG_CORE, base + (i * 0x4));
+			CAM_DBG(CAM_FD, "RawData[%d] : 0x%x", i, *buffer);
+			buffer++;
+		}
+	}
+
+	spin_lock(&fd_core->spin_lock);
+	fd_core->hw_req_private = NULL;
+	fd_core->core_state = CAM_FD_CORE_STATE_IDLE;
+	spin_unlock(&fd_core->spin_lock);
+
+	return 0;
+}
+
+irqreturn_t cam_fd_hw_irq(int irq_num, void *data)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)data;
+	struct cam_fd_core *fd_core;
+	struct cam_hw_soc_info *soc_info;
+	struct cam_fd_hw_static_info *hw_static_info;
+	uint32_t reg_value;
+	enum cam_fd_hw_irq_type irq_type = CAM_FD_IRQ_FRAME_DONE;
+	uint32_t num_irqs = 0;
+
+	if (!fd_hw) {
+		CAM_ERR(CAM_FD, "Invalid data in IRQ callback");
+		return -EINVAL;
+	}
+
+	fd_core = (struct cam_fd_core *) fd_hw->core_info;
+	soc_info = &fd_hw->soc_info;
+	hw_static_info = fd_core->hw_static_info;
+
+	reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_WRAPPER,
+		hw_static_info->wrapper_regs.irq_status);
+
+	CAM_DBG(CAM_FD, "FD IRQ status 0x%x", reg_value);
+
+	if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE)) {
+		complete_all(&fd_core->halt_complete);
+		irq_type = CAM_FD_IRQ_HALT_DONE;
+		num_irqs++;
+	}
+
+	if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE)) {
+		complete_all(&fd_core->reset_complete);
+		irq_type = CAM_FD_IRQ_RESET_DONE;
+		num_irqs++;
+	}
+
+	if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE)) {
+		complete_all(&fd_core->processing_complete);
+		irq_type = CAM_FD_IRQ_FRAME_DONE;
+		num_irqs++;
+	}
+
+	/*
+	 * We should never get an IRQ callback with no or more than one mask.
+	 * Validate first to make sure nothing going wrong.
+	 */
+	if (num_irqs != 1) {
+		CAM_ERR(CAM_FD,
+			"Invalid number of IRQs, value=0x%x, num_irqs=%d",
+			reg_value, num_irqs);
+		return -EINVAL;
+	}
+
+	cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
+		hw_static_info->wrapper_regs.irq_clear,
+		hw_static_info->irq_mask);
+
+	if (irq_type == CAM_FD_IRQ_HALT_DONE) {
+		/*
+		 * Do not send HALT IRQ callback to Hw Mgr,
+		 * a reset would always follow
+		 */
+		return IRQ_HANDLED;
+	}
+
+	spin_lock(&fd_core->spin_lock);
+	/* Do not change state to IDLE on HALT IRQ. Reset must follow halt */
+	if ((irq_type == CAM_FD_IRQ_RESET_DONE) ||
+		(irq_type == CAM_FD_IRQ_FRAME_DONE)) {
+
+		fd_core->core_state = CAM_FD_CORE_STATE_IDLE;
+		if (irq_type == CAM_FD_IRQ_FRAME_DONE)
+			fd_core->results_valid = true;
+
+		CAM_DBG(CAM_FD, "FD IRQ type %d, state=%d",
+			irq_type, fd_core->core_state);
+	}
+	spin_unlock(&fd_core->spin_lock);
+
+	if (fd_core->irq_cb.cam_fd_hw_mgr_cb)
+		fd_core->irq_cb.cam_fd_hw_mgr_cb(fd_core->irq_cb.data,
+			irq_type);
+
+	return IRQ_HANDLED;
+}
+
+int cam_fd_hw_get_hw_caps(void *hw_priv, void *get_hw_cap_args,
+	uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv;
+	struct cam_fd_core *fd_core;
+	struct cam_fd_hw_caps *fd_hw_caps =
+		(struct cam_fd_hw_caps *)get_hw_cap_args;
+
+	if (!hw_priv || !get_hw_cap_args) {
+		CAM_ERR(CAM_FD, "Invalid input pointers %pK %pK",
+			hw_priv, get_hw_cap_args);
+		return -EINVAL;
+	}
+
+	fd_core = (struct cam_fd_core *)fd_hw->core_info;
+	*fd_hw_caps = fd_core->hw_caps;
+
+	CAM_DBG(CAM_FD, "core:%d.%d wrapper:%d.%d mode:%d, raw:%d",
+		fd_hw_caps->core_version.major,
+		fd_hw_caps->core_version.minor,
+		fd_hw_caps->wrapper_version.major,
+		fd_hw_caps->wrapper_version.minor,
+		fd_hw_caps->supported_modes,
+		fd_hw_caps->raw_results_available);
+
+	return 0;
+}
+
+int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv;
+	struct cam_fd_core *fd_core;
+	struct cam_fd_hw_init_args *init_args =
+		(struct cam_fd_hw_init_args *)init_hw_args;
+	int rc = 0;
+
+	if (!fd_hw || !init_args) {
+		CAM_ERR(CAM_FD, "Invalid argument %pK %pK", fd_hw, init_args);
+		return -EINVAL;
+	}
+
+	if (arg_size != sizeof(struct cam_fd_hw_init_args)) {
+		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+			sizeof(struct cam_fd_hw_init_args));
+		return -EINVAL;
+	}
+
+	fd_core = (struct cam_fd_core *)fd_hw->core_info;
+
+	mutex_lock(&fd_hw->hw_mutex);
+	CAM_DBG(CAM_FD, "FD HW Init ref count before %d", fd_hw->open_count);
+
+	if (fd_hw->open_count > 0) {
+		rc = 0;
+		mutex_unlock(&fd_hw->hw_mutex);
+		goto cdm_streamon;
+	}
+
+	rc = cam_fd_soc_enable_resources(&fd_hw->soc_info);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Enable SOC failed, rc=%d", rc);
+		goto unlock_return;
+	}
+
+	rc = cam_fd_hw_reset(hw_priv, NULL, 0);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Reset Failed, rc=%d", rc);
+		goto disable_soc;
+	}
+
+	cam_fd_hw_util_enable_power_on_settings(fd_hw);
+
+	fd_hw->hw_state = CAM_HW_STATE_POWER_UP;
+	fd_core->core_state = CAM_FD_CORE_STATE_IDLE;
+	fd_hw->open_count++;
+	CAM_DBG(CAM_FD, "FD HW Init ref count after %d", fd_hw->open_count);
+
+	mutex_unlock(&fd_hw->hw_mutex);
+
+cdm_streamon:
+	if (init_args->ctx_hw_private) {
+		struct cam_fd_ctx_hw_private *ctx_hw_private =
+			init_args->ctx_hw_private;
+
+		rc = cam_cdm_stream_on(ctx_hw_private->cdm_handle);
+		if (rc) {
+			CAM_ERR(CAM_FD, "CDM StreamOn fail :handle=0x%x, rc=%d",
+				ctx_hw_private->cdm_handle, rc);
+			return rc;
+		}
+	}
+
+	return rc;
+
+disable_soc:
+	if (cam_fd_soc_disable_resources(&fd_hw->soc_info))
+		CAM_ERR(CAM_FD, "Error in disable soc resources");
+unlock_return:
+	mutex_unlock(&fd_hw->hw_mutex);
+	return rc;
+}
+
+int cam_fd_hw_deinit(void *hw_priv, void *deinit_hw_args, uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = hw_priv;
+	struct cam_fd_core *fd_core;
+	struct cam_fd_hw_deinit_args *deinit_args =
+		(struct cam_fd_hw_deinit_args *)deinit_hw_args;
+	int rc = 0;
+
+	if (!fd_hw || !deinit_hw_args) {
+		CAM_ERR(CAM_FD, "Invalid argument");
+		return -EINVAL;
+	}
+
+	if (arg_size != sizeof(struct cam_fd_hw_deinit_args)) {
+		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+			sizeof(struct cam_fd_hw_deinit_args));
+		return -EINVAL;
+	}
+
+	fd_core = (struct cam_fd_core *)fd_hw->core_info;
+
+	if (deinit_args->ctx_hw_private) {
+		struct cam_fd_ctx_hw_private *ctx_hw_private =
+			deinit_args->ctx_hw_private;
+
+		rc = cam_cdm_stream_off(ctx_hw_private->cdm_handle);
+		if (rc) {
+			CAM_ERR(CAM_FD,
+				"Failed in CDM StreamOff, handle=0x%x, rc=%d",
+				ctx_hw_private->cdm_handle, rc);
+			return rc;
+		}
+	}
+
+	mutex_lock(&fd_hw->hw_mutex);
+
+	if (fd_hw->open_count == 0) {
+		mutex_unlock(&fd_hw->hw_mutex);
+		CAM_ERR(CAM_FD, "Error Unbalanced deinit");
+		return -EFAULT;
+	}
+
+	fd_hw->open_count--;
+	CAM_DBG(CAM_FD, "FD HW ref count=%d", fd_hw->open_count);
+
+	if (fd_hw->open_count) {
+		rc = 0;
+		goto unlock_return;
+	}
+
+	rc = cam_fd_soc_disable_resources(&fd_hw->soc_info);
+	if (rc)
+		CAM_ERR(CAM_FD, "Failed in Disable SOC, rc=%d", rc);
+
+	fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
+	fd_core->core_state = CAM_FD_CORE_STATE_POWERDOWN;
+
+unlock_return:
+	mutex_unlock(&fd_hw->hw_mutex);
+	return rc;
+}
+
+int cam_fd_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv;
+	struct cam_fd_core *fd_core;
+	int rc;
+
+	if (!fd_hw) {
+		CAM_ERR(CAM_FD, "Invalid input handle");
+		return -EINVAL;
+	}
+
+	fd_core = (struct cam_fd_core *)fd_hw->core_info;
+
+	spin_lock(&fd_core->spin_lock);
+	if (fd_core->core_state == CAM_FD_CORE_STATE_RESET_PROGRESS) {
+		CAM_ERR(CAM_FD, "Reset not allowed in %d state",
+			fd_core->core_state);
+		spin_unlock(&fd_core->spin_lock);
+		return -EINVAL;
+	}
+
+	fd_core->results_valid = false;
+	fd_core->core_state = CAM_FD_CORE_STATE_RESET_PROGRESS;
+	spin_unlock(&fd_core->spin_lock);
+
+	rc = cam_fd_hw_util_fdwrapper_sync_reset(fd_hw);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in RESET rc=%d", rc);
+		return rc;
+	}
+
+	spin_lock(&fd_core->spin_lock);
+	fd_core->core_state = CAM_FD_CORE_STATE_IDLE;
+	spin_unlock(&fd_core->spin_lock);
+
+	return rc;
+}
+
+int cam_fd_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv;
+	struct cam_fd_core *fd_core;
+	struct cam_fd_hw_static_info *hw_static_info;
+	struct cam_fd_hw_cmd_start_args *start_args =
+		(struct cam_fd_hw_cmd_start_args *)hw_start_args;
+	struct cam_fd_ctx_hw_private *ctx_hw_private;
+	int rc;
+
+	if (!hw_priv || !start_args) {
+		CAM_ERR(CAM_FD, "Invalid input args %pK %pK", hw_priv,
+			start_args);
+		return -EINVAL;
+	}
+
+	if (arg_size != sizeof(struct cam_fd_hw_cmd_start_args)) {
+		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+			sizeof(struct cam_fd_hw_cmd_start_args));
+		return -EINVAL;
+	}
+
+	fd_core = (struct cam_fd_core *)fd_hw->core_info;
+	hw_static_info = fd_core->hw_static_info;
+
+	spin_lock(&fd_core->spin_lock);
+	if (fd_core->core_state != CAM_FD_CORE_STATE_IDLE) {
+		CAM_ERR(CAM_FD, "Cannot start in %d state",
+			fd_core->core_state);
+		spin_unlock(&fd_core->spin_lock);
+		return -EINVAL;
+	}
+
+	/*
+	 * We are about to start FD HW processing, save the request
+	 * private data which is being processed by HW. Once the frame
+	 * processing is finished, process_cmd(FRAME_DONE) should be called
+	 * with same hw_req_private as input.
+	 */
+	fd_core->hw_req_private = start_args->hw_req_private;
+	fd_core->core_state = CAM_FD_CORE_STATE_PROCESSING;
+	fd_core->results_valid = false;
+	spin_unlock(&fd_core->spin_lock);
+
+	ctx_hw_private = start_args->ctx_hw_private;
+
+	/* Before starting HW process, clear processing complete */
+	reinit_completion(&fd_core->processing_complete);
+
+	if (hw_static_info->enable_errata_wa.single_irq_only) {
+		cam_fd_soc_register_write(&fd_hw->soc_info, CAM_FD_REG_WRAPPER,
+			hw_static_info->wrapper_regs.irq_mask,
+			CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE));
+	}
+
+	if (start_args->num_hw_update_entries > 0) {
+		struct cam_cdm_bl_request *cdm_cmd = ctx_hw_private->cdm_cmd;
+		struct cam_hw_update_entry *cmd;
+		int i;
+
+		cdm_cmd->cmd_arrary_count = start_args->num_hw_update_entries;
+		cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE;
+		cdm_cmd->flag = false;
+		cdm_cmd->userdata = NULL;
+		cdm_cmd->cookie = 0;
+
+		for (i = 0 ; i <= start_args->num_hw_update_entries; i++) {
+			cmd = (start_args->hw_update_entries + i);
+			cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle;
+			cdm_cmd->cmd[i].offset = cmd->offset;
+			cdm_cmd->cmd[i].len = cmd->len;
+		}
+
+		rc = cam_cdm_submit_bls(ctx_hw_private->cdm_handle, cdm_cmd);
+		if (rc) {
+			CAM_ERR(CAM_FD,
+				"Failed to submit cdm commands, rc=%d", rc);
+			goto error;
+		}
+	} else {
+		CAM_ERR(CAM_FD, "Invalid number of hw update entries");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	cam_fd_soc_register_write(&fd_hw->soc_info, CAM_FD_REG_CORE,
+		hw_static_info->core_regs.control, 0x2);
+
+	return 0;
+error:
+	spin_lock(&fd_core->spin_lock);
+	fd_core->core_state = CAM_FD_CORE_STATE_IDLE;
+	spin_unlock(&fd_core->spin_lock);
+
+	return rc;
+}
+
+int cam_fd_hw_halt_reset(void *hw_priv, void *stop_args, uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv;
+	struct cam_fd_core *fd_core;
+	int rc;
+
+	if (!fd_hw) {
+		CAM_ERR(CAM_FD, "Invalid input handle");
+		return -EINVAL;
+	}
+
+	fd_core = (struct cam_fd_core *)fd_hw->core_info;
+
+	spin_lock(&fd_core->spin_lock);
+	if ((fd_core->core_state == CAM_FD_CORE_STATE_POWERDOWN) ||
+		(fd_core->core_state == CAM_FD_CORE_STATE_RESET_PROGRESS)) {
+		CAM_ERR(CAM_FD, "Reset not allowed in %d state",
+			fd_core->core_state);
+		spin_unlock(&fd_core->spin_lock);
+		return -EINVAL;
+	}
+
+	fd_core->results_valid = false;
+	fd_core->core_state = CAM_FD_CORE_STATE_RESET_PROGRESS;
+	spin_unlock(&fd_core->spin_lock);
+
+	rc = cam_fd_hw_util_fdwrapper_halt(fd_hw);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in HALT rc=%d", rc);
+		return rc;
+	}
+
+	/* HALT must be followed by RESET */
+	rc = cam_fd_hw_util_fdwrapper_sync_reset(fd_hw);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in RESET rc=%d", rc);
+		return rc;
+	}
+
+	spin_lock(&fd_core->spin_lock);
+	fd_core->core_state = CAM_FD_CORE_STATE_IDLE;
+	spin_unlock(&fd_core->spin_lock);
+
+	return rc;
+}
+
+int cam_fd_hw_reserve(void *hw_priv, void *hw_reserve_args, uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv;
+	int rc = -EINVAL;
+	struct cam_fd_ctx_hw_private *ctx_hw_private;
+	struct cam_fd_hw_reserve_args *reserve_args =
+		(struct cam_fd_hw_reserve_args *)hw_reserve_args;
+	struct cam_cdm_acquire_data cdm_acquire;
+	struct cam_cdm_bl_request *cdm_cmd;
+	int i;
+
+	if (!fd_hw || !reserve_args) {
+		CAM_ERR(CAM_FD, "Invalid input %pK, %pK", fd_hw, reserve_args);
+		return -EINVAL;
+	}
+
+	if (arg_size != sizeof(struct cam_fd_hw_reserve_args)) {
+		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+			sizeof(struct cam_fd_hw_reserve_args));
+		return -EINVAL;
+	}
+
+	cdm_cmd = kzalloc(((sizeof(struct cam_cdm_bl_request)) +
+			((CAM_FD_MAX_HW_ENTRIES - 1) *
+			sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL);
+	if (!cdm_cmd)
+		return -ENOMEM;
+
+	ctx_hw_private = kzalloc(sizeof(struct cam_fd_ctx_hw_private),
+		GFP_KERNEL);
+	if (!ctx_hw_private) {
+		kfree(cdm_cmd);
+		return -ENOMEM;
+	}
+
+	memset(&cdm_acquire, 0, sizeof(cdm_acquire));
+	strlcpy(cdm_acquire.identifier, "fd", sizeof("fd"));
+	cdm_acquire.cell_index = fd_hw->soc_info.index;
+	cdm_acquire.handle = 0;
+	cdm_acquire.userdata = ctx_hw_private;
+	cdm_acquire.cam_cdm_callback = cam_fd_hw_util_cdm_callback;
+	cdm_acquire.id = CAM_CDM_VIRTUAL;
+	cdm_acquire.base_array_cnt = fd_hw->soc_info.num_reg_map;
+	for (i = 0; i < fd_hw->soc_info.num_reg_map; i++)
+		cdm_acquire.base_array[i] = &fd_hw->soc_info.reg_map[i];
+
+	rc = cam_cdm_acquire(&cdm_acquire);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed to acquire the CDM HW");
+		goto error;
+	}
+
+	ctx_hw_private->hw_ctx = reserve_args->hw_ctx;
+	ctx_hw_private->fd_hw = fd_hw;
+	ctx_hw_private->mode = reserve_args->mode;
+	ctx_hw_private->cdm_handle = cdm_acquire.handle;
+	ctx_hw_private->cdm_ops = cdm_acquire.ops;
+	ctx_hw_private->cdm_cmd = cdm_cmd;
+
+	reserve_args->ctx_hw_private = ctx_hw_private;
+
+	CAM_DBG(CAM_FD, "private=%pK, hw_ctx=%pK, mode=%d, cdm_handle=0x%x",
+		ctx_hw_private, ctx_hw_private->hw_ctx, ctx_hw_private->mode,
+		ctx_hw_private->cdm_handle);
+
+	return 0;
+error:
+	kfree(ctx_hw_private);
+	kfree(cdm_cmd);
+	return rc;
+}
+
+int cam_fd_hw_release(void *hw_priv, void *hw_release_args, uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv;
+	int rc = -EINVAL;
+	struct cam_fd_ctx_hw_private *ctx_hw_private;
+	struct cam_fd_hw_release_args *release_args =
+		(struct cam_fd_hw_release_args *)hw_release_args;
+
+	if (!fd_hw || !release_args) {
+		CAM_ERR(CAM_FD, "Invalid input %pK, %pK", fd_hw, release_args);
+		return -EINVAL;
+	}
+
+	if (arg_size != sizeof(struct cam_fd_hw_release_args)) {
+		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+			sizeof(struct cam_fd_hw_release_args));
+		return -EINVAL;
+	}
+
+	ctx_hw_private =
+		(struct cam_fd_ctx_hw_private *)release_args->ctx_hw_private;
+
+	rc = cam_cdm_release(ctx_hw_private->cdm_handle);
+	if (rc)
+		CAM_ERR(CAM_FD, "Release cdm handle failed, handle=0x%x, rc=%d",
+			ctx_hw_private->cdm_handle, rc);
+
+	kfree(ctx_hw_private);
+	release_args->ctx_hw_private = NULL;
+
+	return 0;
+}
+
+int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size)
+{
+	struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv;
+	int rc = -EINVAL;
+
+	if (!hw_priv || !cmd_args ||
+		(cmd_type >= CAM_FD_HW_CMD_MAX)) {
+		CAM_ERR(CAM_FD, "Invalid arguments %pK %pK %d", hw_priv,
+			cmd_args, cmd_type);
+		return -EINVAL;
+	}
+
+	switch (cmd_type) {
+	case CAM_FD_HW_CMD_REGISTER_CALLBACK: {
+		struct cam_fd_hw_cmd_set_irq_cb *irq_cb_args;
+		struct cam_fd_core *fd_core =
+			(struct cam_fd_core *)fd_hw->core_info;
+
+		if (sizeof(struct cam_fd_hw_cmd_set_irq_cb) != arg_size) {
+			CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d",
+				cmd_type, arg_size);
+			break;
+		}
+
+		irq_cb_args = (struct cam_fd_hw_cmd_set_irq_cb *)cmd_args;
+		fd_core->irq_cb.cam_fd_hw_mgr_cb =
+			irq_cb_args->cam_fd_hw_mgr_cb;
+		fd_core->irq_cb.data = irq_cb_args->data;
+		rc = 0;
+		break;
+	}
+	case CAM_FD_HW_CMD_PRESTART: {
+		struct cam_fd_hw_cmd_prestart_args *prestart_args;
+
+		if (sizeof(struct cam_fd_hw_cmd_prestart_args) != arg_size) {
+			CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d",
+				cmd_type, arg_size);
+			break;
+		}
+
+		prestart_args = (struct cam_fd_hw_cmd_prestart_args *)cmd_args;
+		rc = cam_fd_hw_util_processcmd_prestart(fd_hw, prestart_args);
+		break;
+	}
+	case CAM_FD_HW_CMD_FRAME_DONE: {
+		struct cam_fd_hw_frame_done_args *cmd_frame_results;
+
+		if (sizeof(struct cam_fd_hw_frame_done_args) !=
+			arg_size) {
+			CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d",
+				cmd_type, arg_size);
+			break;
+		}
+
+		cmd_frame_results =
+			(struct cam_fd_hw_frame_done_args *)cmd_args;
+		rc = cam_fd_hw_util_processcmd_frame_done(fd_hw,
+			cmd_frame_results);
+		break;
+	}
+	default:
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h
new file mode 100644
index 0000000..35bf6b6
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h
@@ -0,0 +1,244 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_FD_HW_CORE_H_
+#define _CAM_FD_HW_CORE_H_
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_defs.h>
+#include <media/cam_fd.h>
+
+#include "cam_common_util.h"
+#include "cam_debug_util.h"
+#include "cam_io_util.h"
+#include "cam_cpas_api.h"
+#include "cam_cdm_intf_api.h"
+#include "cam_fd_hw_intf.h"
+#include "cam_fd_hw_soc.h"
+
+#define CAM_FD_IRQ_TO_MASK(irq)        (1 << (irq))
+#define CAM_FD_MASK_TO_IRQ(mask, irq)  ((mask) >> (irq))
+
+#define CAM_FD_HW_HALT_RESET_TIMEOUT   3000
+
+/**
+ * enum cam_fd_core_state - FD Core internal states
+ *
+ * @CAM_FD_CORE_STATE_POWERDOWN       : Indicates FD core is powered down
+ * @CAM_FD_CORE_STATE_IDLE            : Indicates FD HW is in idle state.
+ *                                      Core can be in this state when it is
+ *                                      ready to process frames or when
+ *                                      processing is finished and results are
+ *                                      available
+ * @CAM_FD_CORE_STATE_PROCESSING      : Indicates FD core is processing frame
+ * @CAM_FD_CORE_STATE_READING_RESULTS : Indicates results are being read from
+ *                                      FD core
+ * @CAM_FD_CORE_STATE_RESET_PROGRESS  :  Indicates FD Core is in reset state
+ */
+enum cam_fd_core_state {
+	CAM_FD_CORE_STATE_POWERDOWN,
+	CAM_FD_CORE_STATE_IDLE,
+	CAM_FD_CORE_STATE_PROCESSING,
+	CAM_FD_CORE_STATE_READING_RESULTS,
+	CAM_FD_CORE_STATE_RESET_PROGRESS,
+};
+
+/**
+ * struct cam_fd_ctx_hw_private : HW private information for a specific hw ctx.
+ *                                This information is populated by HW layer on
+ *                                reserve() and given back to HW Mgr as private
+ *                                data for the hw context. This private_data
+ *                                has to be passed by HW Mgr layer while
+ *                                further HW layer calls
+ *
+ * @hw_ctx           : Corresponding hw_ctx pointer
+ * @fd_hw            : FD HW info pointer
+ * @cdm_handle       : CDM Handle for this context
+ * @cdm_ops          : CDM Ops
+ * @cdm_cmd          : CDM command pointer
+ * @mode             : Mode this context is running
+ * @curr_req_private : Current Request information
+ *
+ */
+struct cam_fd_ctx_hw_private {
+	void                          *hw_ctx;
+	struct cam_hw_info            *fd_hw;
+	uint32_t                       cdm_handle;
+	struct cam_cdm_utils_ops      *cdm_ops;
+	struct cam_cdm_bl_request     *cdm_cmd;
+	enum cam_fd_hw_mode            mode;
+	struct cam_fd_hw_req_private  *curr_req_private;
+};
+
+/**
+ * struct cam_fd_core_regs : FD HW Core register offsets info
+ *
+ * @version              : Offset of version register
+ * @control              : Offset of control register
+ * @result_cnt           : Offset of result count register
+ * @result_addr          : Offset of results address register
+ * @image_addr           : Offset of image address register
+ * @work_addr            : Offset of work address register
+ * @ro_mode              : Offset of ro_mode register
+ * @results_reg_base     : Offset of results_reg_base register
+ * @raw_results_reg_base : Offset of raw_results_reg_base register
+ *
+ */
+struct cam_fd_core_regs {
+	uint32_t       version;
+	uint32_t       control;
+	uint32_t       result_cnt;
+	uint32_t       result_addr;
+	uint32_t       image_addr;
+	uint32_t       work_addr;
+	uint32_t       ro_mode;
+	uint32_t       results_reg_base;
+	uint32_t       raw_results_reg_base;
+};
+
+/**
+ * struct cam_fd_core_regs : FD HW Wrapper register offsets info
+ *
+ * @wrapper_version     : Offset of wrapper_version register
+ * @cgc_disable         : Offset of cgc_disable register
+ * @hw_stop             : Offset of hw_stop register
+ * @sw_reset            : Offset of sw_reset register
+ * @vbif_req_priority   : Offset of vbif_req_priority register
+ * @vbif_priority_level : Offset of vbif_priority_level register
+ * @vbif_done_status    : Offset of vbif_done_status register
+ * @irq_mask            : Offset of irq mask register
+ * @irq_status          : Offset of irq status register
+ * @irq_clear           : Offset of irq clear register
+ *
+ */
+struct cam_fd_wrapper_regs {
+	uint32_t       wrapper_version;
+	uint32_t       cgc_disable;
+	uint32_t       hw_stop;
+	uint32_t       sw_reset;
+	uint32_t       vbif_req_priority;
+	uint32_t       vbif_priority_level;
+	uint32_t       vbif_done_status;
+	uint32_t       irq_mask;
+	uint32_t       irq_status;
+	uint32_t       irq_clear;
+};
+
+/**
+ * struct cam_fd_hw_errata_wa : FD HW Errata workaround enable/dsiable info
+ *
+ * @single_irq_only         : Whether to enable only one irq at any time
+ * @ro_mode_enable_always   : Whether to enable ro mode always
+ * @ro_mode_results_invalid : Whether results written directly into output
+ *                            memory by HW are valid or not
+ */
+struct cam_fd_hw_errata_wa {
+	bool   single_irq_only;
+	bool   ro_mode_enable_always;
+	bool   ro_mode_results_invalid;
+};
+
+/**
+ * struct cam_fd_hw_results_prop : FD HW Results properties
+ *
+ * @max_faces             : Maximum number of faces supported
+ * @per_face_entries      : Number of register with properties for each face
+ * @raw_results_entries   : Number of raw results entries for the full search
+ * @raw_results_available : Whether raw results available on this HW
+ *
+ */
+struct cam_fd_hw_results_prop {
+	uint32_t       max_faces;
+	uint32_t       per_face_entries;
+	uint32_t       raw_results_entries;
+	bool           raw_results_available;
+};
+
+/**
+ * struct cam_fd_hw_static_info : FD HW information based on HW version
+ *
+ * @core_version       : Core version of FD HW
+ * @wrapper_version    : Wrapper version of FD HW
+ * @core_regs          : Register offset information for core registers
+ * @wrapper_regs       : Register offset information for wrapper registers
+ * @results            : Information about results available on this HW
+ * @enable_errata_wa   : Errata workaround information
+ * @irq_mask           : IRQ mask to enable
+ * @qos_priority       : QoS priority setting for this chipset
+ * @qos_priority_level : QoS priority level setting for this chipset
+ * @supported_modes    : Supported HW modes on this HW version
+ * @ro_mode_supported  : Whether RO mode is supported on this HW
+ *
+ */
+struct cam_fd_hw_static_info {
+	struct cam_hw_version          core_version;
+	struct cam_hw_version          wrapper_version;
+	struct cam_fd_core_regs        core_regs;
+	struct cam_fd_wrapper_regs     wrapper_regs;
+	struct cam_fd_hw_results_prop  results;
+	struct cam_fd_hw_errata_wa     enable_errata_wa;
+	uint32_t                       irq_mask;
+	uint32_t                       qos_priority;
+	uint32_t                       qos_priority_level;
+	uint32_t                       supported_modes;
+	bool                           ro_mode_supported;
+};
+
+/**
+ * struct cam_fd_core : FD HW core data structure
+ *
+ * @hw_static_info      : HW information specific to version
+ * @hw_caps             : HW capabilities
+ * @core_state          : Current HW state
+ * @processing_complete : Whether processing is complete
+ * @reset_complete      : Whether reset is complete
+ * @halt_complete       : Whether halt is complete
+ * @hw_req_private      : Request that is being currently processed by HW
+ * @results_valid       : Whether HW frame results are available to get
+ * @spin_lock           : Mutex to protect shared data in hw layer
+ * @irq_cb              : HW Manager callback information
+ *
+ */
+struct cam_fd_core {
+	struct cam_fd_hw_static_info   *hw_static_info;
+	struct cam_fd_hw_caps           hw_caps;
+	enum cam_fd_core_state          core_state;
+	struct completion               processing_complete;
+	struct completion               reset_complete;
+	struct completion               halt_complete;
+	struct cam_fd_hw_req_private   *hw_req_private;
+	bool                            results_valid;
+	spinlock_t                      spin_lock;
+	struct cam_fd_hw_cmd_set_irq_cb irq_cb;
+};
+
+int cam_fd_hw_util_get_hw_caps(struct cam_hw_info *fd_hw,
+	struct cam_fd_hw_caps *hw_caps);
+irqreturn_t cam_fd_hw_irq(int irq_num, void *data);
+
+int cam_fd_hw_get_hw_caps(void *hw_priv, void *get_hw_cap_args,
+	uint32_t arg_size);
+int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size);
+int cam_fd_hw_deinit(void *hw_priv, void *deinit_hw_args, uint32_t arg_size);
+int cam_fd_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size);
+int cam_fd_hw_reserve(void *hw_priv, void *hw_reserve_args, uint32_t arg_size);
+int cam_fd_hw_release(void *hw_priv, void *hw_release_args, uint32_t arg_size);
+int cam_fd_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size);
+int cam_fd_hw_halt_reset(void *hw_priv, void *stop_args, uint32_t arg_size);
+int cam_fd_hw_read(void *hw_priv, void *read_args, uint32_t arg_size);
+int cam_fd_hw_write(void *hw_priv, void *write_args, uint32_t arg_size);
+int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type,
+	void *cmd_args, uint32_t arg_size);
+
+#endif /* _CAM_FD_HW_CORE_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c
new file mode 100644
index 0000000..803da76
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_subdev.h"
+#include "cam_fd_hw_intf.h"
+#include "cam_fd_hw_core.h"
+#include "cam_fd_hw_soc.h"
+#include "cam_fd_hw_v41.h"
+
+static int cam_fd_hw_dev_probe(struct platform_device *pdev)
+{
+	struct cam_hw_info *fd_hw;
+	struct cam_hw_intf *fd_hw_intf;
+	struct cam_fd_core *fd_core;
+	const struct of_device_id *match_dev = NULL;
+	struct cam_fd_hw_static_info *hw_static_info = NULL;
+	int rc = 0;
+	struct cam_fd_hw_init_args init_args;
+	struct cam_fd_hw_deinit_args deinit_args;
+
+	fd_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL);
+	if (!fd_hw_intf)
+		return -ENOMEM;
+
+	fd_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL);
+	if (!fd_hw) {
+		kfree(fd_hw_intf);
+		return -ENOMEM;
+	}
+
+	fd_core = kzalloc(sizeof(struct cam_fd_core), GFP_KERNEL);
+	if (!fd_core) {
+		kfree(fd_hw);
+		kfree(fd_hw_intf);
+		return -ENOMEM;
+	}
+
+	fd_hw_intf->hw_priv = fd_hw;
+	fd_hw->core_info = fd_core;
+
+	fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN;
+	fd_hw->soc_info.pdev = pdev;
+	fd_hw->soc_info.dev = &pdev->dev;
+	fd_hw->soc_info.dev_name = pdev->name;
+	fd_hw->open_count = 0;
+	mutex_init(&fd_hw->hw_mutex);
+	spin_lock_init(&fd_hw->hw_lock);
+	init_completion(&fd_hw->hw_complete);
+
+	spin_lock_init(&fd_core->spin_lock);
+	init_completion(&fd_core->processing_complete);
+	init_completion(&fd_core->halt_complete);
+	init_completion(&fd_core->reset_complete);
+
+	fd_hw_intf->hw_ops.get_hw_caps = cam_fd_hw_get_hw_caps;
+	fd_hw_intf->hw_ops.init = cam_fd_hw_init;
+	fd_hw_intf->hw_ops.deinit = cam_fd_hw_deinit;
+	fd_hw_intf->hw_ops.reset = cam_fd_hw_reset;
+	fd_hw_intf->hw_ops.reserve = cam_fd_hw_reserve;
+	fd_hw_intf->hw_ops.release = cam_fd_hw_release;
+	fd_hw_intf->hw_ops.start = cam_fd_hw_start;
+	fd_hw_intf->hw_ops.stop = cam_fd_hw_halt_reset;
+	fd_hw_intf->hw_ops.read = NULL;
+	fd_hw_intf->hw_ops.write = NULL;
+	fd_hw_intf->hw_ops.process_cmd = cam_fd_hw_process_cmd;
+	fd_hw_intf->hw_type = CAM_HW_FD;
+
+	match_dev = of_match_device(pdev->dev.driver->of_match_table,
+		&pdev->dev);
+	if (!match_dev || !match_dev->data) {
+		CAM_ERR(CAM_FD, "No Of_match data, %pK", match_dev);
+		rc = -EINVAL;
+		goto free_memory;
+	}
+	hw_static_info = (struct cam_fd_hw_static_info *)match_dev->data;
+	fd_core->hw_static_info = hw_static_info;
+
+	CAM_DBG(CAM_FD, "HW Static Info : version core[%d.%d] wrapper[%d.%d]",
+		hw_static_info->core_version.major,
+		hw_static_info->core_version.minor,
+		hw_static_info->wrapper_version.major,
+		hw_static_info->wrapper_version.minor);
+
+	rc = cam_fd_soc_init_resources(&fd_hw->soc_info, cam_fd_hw_irq, fd_hw);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed to init soc, rc=%d", rc);
+		goto free_memory;
+	}
+
+	fd_hw_intf->hw_idx = fd_hw->soc_info.index;
+
+	memset(&init_args, 0x0, sizeof(init_args));
+	memset(&deinit_args, 0x0, sizeof(deinit_args));
+	rc = cam_fd_hw_init(fd_hw, &init_args, sizeof(init_args));
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed to hw init, rc=%d", rc);
+		goto deinit_platform_res;
+	}
+
+	rc = cam_fd_hw_util_get_hw_caps(fd_hw, &fd_core->hw_caps);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed to get hw caps, rc=%d", rc);
+		goto deinit_hw;
+	}
+
+	rc = cam_fd_hw_deinit(fd_hw, &deinit_args, sizeof(deinit_args));
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed to deinit hw, rc=%d", rc);
+		goto deinit_platform_res;
+	}
+
+	platform_set_drvdata(pdev, fd_hw_intf);
+	CAM_DBG(CAM_FD, "FD-%d probe successful", fd_hw_intf->hw_idx);
+
+	return rc;
+
+deinit_hw:
+	if (cam_fd_hw_deinit(fd_hw, &deinit_args, sizeof(deinit_args)))
+		CAM_ERR(CAM_FD, "Failed in hw deinit");
+deinit_platform_res:
+	if (cam_fd_soc_deinit_resources(&fd_hw->soc_info))
+		CAM_ERR(CAM_FD, "Failed in soc deinit");
+	mutex_destroy(&fd_hw->hw_mutex);
+free_memory:
+	kfree(fd_hw);
+	kfree(fd_hw_intf);
+	kfree(fd_core);
+
+	return rc;
+}
+
+static int cam_fd_hw_dev_remove(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct cam_hw_intf *fd_hw_intf;
+	struct cam_hw_info *fd_hw;
+	struct cam_fd_core *fd_core;
+
+	fd_hw_intf = platform_get_drvdata(pdev);
+	if (!fd_hw_intf) {
+		CAM_ERR(CAM_FD, "Invalid fd_hw_intf from pdev");
+		return -EINVAL;
+	}
+
+	fd_hw = fd_hw_intf->hw_priv;
+	if (!fd_hw) {
+		CAM_ERR(CAM_FD, "Invalid fd_hw from fd_hw_intf");
+		rc = -ENODEV;
+		goto free_fd_hw_intf;
+	}
+
+	fd_core = (struct cam_fd_core *)fd_hw->core_info;
+	if (!fd_core) {
+		CAM_ERR(CAM_FD, "Invalid fd_core from fd_hw");
+		rc = -EINVAL;
+		goto deinit_platform_res;
+	}
+
+	kfree(fd_core);
+
+deinit_platform_res:
+	rc = cam_fd_soc_deinit_resources(&fd_hw->soc_info);
+	if (rc)
+		CAM_ERR(CAM_FD, "Error in FD soc deinit, rc=%d", rc);
+
+	mutex_destroy(&fd_hw->hw_mutex);
+	kfree(fd_hw);
+
+free_fd_hw_intf:
+	kfree(fd_hw_intf);
+
+	return rc;
+}
+
+static const struct of_device_id cam_fd_hw_dt_match[] = {
+	{
+		.compatible = "qcom,fd41",
+		.data = &cam_fd_wrapper120_core410_info,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match);
+
+static struct platform_driver cam_fd_hw_driver = {
+	.probe = cam_fd_hw_dev_probe,
+	.remove = cam_fd_hw_dev_remove,
+	.driver = {
+		.name = "cam_fd_hw",
+		.owner = THIS_MODULE,
+		.of_match_table = cam_fd_hw_dt_match,
+	},
+};
+
+static int __init cam_fd_hw_init_module(void)
+{
+	return platform_driver_register(&cam_fd_hw_driver);
+}
+
+static void __exit cam_fd_hw_exit_module(void)
+{
+	platform_driver_unregister(&cam_fd_hw_driver);
+}
+
+module_init(cam_fd_hw_init_module);
+module_exit(cam_fd_hw_exit_module);
+MODULE_DESCRIPTION("CAM FD HW driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h
new file mode 100644
index 0000000..aae7648
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h
@@ -0,0 +1,289 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_FD_HW_INTF_H_
+#define _CAM_FD_HW_INTF_H_
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <media/cam_cpas.h>
+#include <media/cam_req_mgr.h>
+#include <media/cam_fd.h>
+
+#include "cam_io_util.h"
+#include "cam_soc_util.h"
+#include "cam_hw.h"
+#include "cam_hw_intf.h"
+#include "cam_subdev.h"
+#include "cam_cpas_api.h"
+#include "cam_hw_mgr_intf.h"
+#include "cam_debug_util.h"
+
+#define CAM_FD_MAX_IO_BUFFERS        5
+#define CAM_FD_MAX_HW_ENTRIES        5
+
+/**
+ * enum cam_fd_hw_type - Enum for FD HW type
+ *
+ * @CAM_HW_FD : FaceDetection HW type
+ */
+enum cam_fd_hw_type {
+	CAM_HW_FD,
+};
+
+/**
+ * enum cam_fd_hw_mode - Mode in which HW can run
+ *
+ * @CAM_FD_MODE_FACEDETECTION : Face Detection mode in which face search
+ *                              is done on the given frame
+ * @CAM_FD_MODE_PYRAMID       : Pyramid mode where a pyramid image is generated
+ *                              from an input image
+ */
+enum cam_fd_hw_mode {
+	CAM_FD_MODE_FACEDETECTION    = 0x1,
+	CAM_FD_MODE_PYRAMID          = 0x2,
+};
+
+/**
+ * enum cam_fd_priority - FD priority levels
+ *
+ * @CAM_FD_PRIORITY_HIGH   : Indicates high priority client, driver prioritizes
+ *                           frame requests coming from contexts with HIGH
+ *                           priority compared to context with normal priority
+ * @CAM_FD_PRIORITY_NORMAL : Indicates normal priority client
+ */
+enum cam_fd_priority {
+	CAM_FD_PRIORITY_HIGH         = 0x0,
+	CAM_FD_PRIORITY_NORMAL,
+};
+
+/**
+ * enum cam_fd_hw_irq_type - FD HW IRQ types
+ *
+ * @CAM_FD_IRQ_FRAME_DONE : Indicates frame processing is finished
+ * @CAM_FD_IRQ_HALT_DONE  : Indicates HW halt is finished
+ * @CAM_FD_IRQ_RESET_DONE : Indicates HW reset is finished
+ */
+enum cam_fd_hw_irq_type {
+	CAM_FD_IRQ_FRAME_DONE,
+	CAM_FD_IRQ_HALT_DONE,
+	CAM_FD_IRQ_RESET_DONE,
+};
+
+/**
+ * enum cam_fd_hw_cmd_type - FD HW layer custom commands
+ *
+ * @CAM_FD_HW_CMD_PRESTART          : Command to process pre-start settings
+ * @CAM_FD_HW_CMD_FRAME_DONE        : Command to process frame done settings
+ * @CAM_FD_HW_CMD_UPDATE_SOC        : Command to process soc update
+ * @CAM_FD_HW_CMD_REGISTER_CALLBACK : Command to set hw mgr callback
+ * @CAM_FD_HW_CMD_MAX               : Indicates max cmd
+ */
+enum cam_fd_hw_cmd_type {
+	CAM_FD_HW_CMD_PRESTART,
+	CAM_FD_HW_CMD_FRAME_DONE,
+	CAM_FD_HW_CMD_UPDATE_SOC,
+	CAM_FD_HW_CMD_REGISTER_CALLBACK,
+	CAM_FD_HW_CMD_MAX,
+};
+
+/**
+ * struct cam_fd_hw_io_buffer : FD HW IO Buffer information
+ *
+ * @valid    : Whether this IO Buf configuration is valid
+ * @io_cfg   : IO Configuration information
+ * @num_buf  : Number planes in io_addr, cpu_addr array
+ * @io_addr  : Array of IO address information for planes
+ * @cpu_addr : Array of CPU address information for planes
+ */
+struct cam_fd_hw_io_buffer {
+	bool                   valid;
+	struct cam_buf_io_cfg *io_cfg;
+	uint32_t               num_buf;
+	uint64_t               io_addr[CAM_PACKET_MAX_PLANES];
+	uint64_t               cpu_addr[CAM_PACKET_MAX_PLANES];
+};
+
+/**
+ * struct cam_fd_hw_req_private : FD HW layer's private information
+ *               specific to a request
+ *
+ * @ctx_hw_private  : FD HW layer's ctx specific private data
+ * @request_id      : Request ID corresponding to this private information
+ * @get_raw_results : Whether to get raw results for this request
+ * @ro_mode_enabled : Whether RO mode is enabled for this request
+ * @fd_results      : Pointer to save face detection results
+ * @raw_results     : Pointer to save face detection raw results
+ */
+struct cam_fd_hw_req_private {
+	void                  *ctx_hw_private;
+	uint64_t               request_id;
+	bool                   get_raw_results;
+	bool                   ro_mode_enabled;
+	struct cam_fd_results *fd_results;
+	uint32_t              *raw_results;
+};
+
+/**
+ * struct cam_fd_hw_reserve_args : Reserve args for this HW context
+ *
+ * @hw_ctx         : HW context for which reserve is requested
+ * @mode           : Mode for which this reserve is requested
+ * @ctx_hw_private : Pointer to save HW layer's private information specific
+ *                   to this hw context. This has to be passed while calling
+ *                   further HW layer calls
+ */
+struct cam_fd_hw_reserve_args {
+	void                  *hw_ctx;
+	enum cam_fd_hw_mode    mode;
+	void                  *ctx_hw_private;
+};
+
+/**
+ * struct cam_fd_hw_release_args : Release args for this HW context
+ *
+ * @hw_ctx         : HW context for which release is requested
+ * @ctx_hw_private : HW layer's private information specific to this hw context
+ */
+struct cam_fd_hw_release_args {
+	void    *hw_ctx;
+	void    *ctx_hw_private;
+};
+
+/**
+ * struct cam_fd_hw_init_args : Init args for this HW context
+ *
+ * @hw_ctx         : HW context for which init is requested
+ * @ctx_hw_private : HW layer's private information specific to this hw context
+ */
+struct cam_fd_hw_init_args {
+	void    *hw_ctx;
+	void    *ctx_hw_private;
+};
+
+/**
+ * struct cam_fd_hw_deinit_args : Deinit args for this HW context
+ *
+ * @hw_ctx         : HW context for which deinit is requested
+ * @ctx_hw_private : HW layer's private information specific to this hw context
+ */
+struct cam_fd_hw_deinit_args {
+	void    *hw_ctx;
+	void    *ctx_hw_private;
+};
+
+/**
+ * struct cam_fd_hw_cmd_prestart_args : Prestart command args
+ *
+ * @hw_ctx               : HW context which submitted this prestart
+ * @ctx_hw_private       : HW layer's private information specific to
+ *                         this hw context
+ * @request_id           : Request ID corresponds to this pre-start command
+ * @get_raw_results      : Whether to get raw results for this request
+ * @input_buf            : Input IO Buffer information for this request
+ * @output_buf           : Output IO Buffer information for this request
+ * @cmd_buf_addr         : Command buffer address to fill kmd commands
+ * @size                 : Size available in command buffer
+ * @pre_config_buf_size  : Buffer size filled with commands by KMD that has
+ *                         to be inserted before umd commands
+ * @post_config_buf_size : Buffer size filled with commands by KMD that has
+ *                         to be inserted after umd commands
+ * @hw_req_private       : HW layer's private information specific to
+ *                         this request
+ */
+struct cam_fd_hw_cmd_prestart_args {
+	void                         *hw_ctx;
+	void                         *ctx_hw_private;
+	uint64_t                      request_id;
+	bool                          get_raw_results;
+	struct cam_fd_hw_io_buffer    input_buf[CAM_FD_MAX_IO_BUFFERS];
+	struct cam_fd_hw_io_buffer    output_buf[CAM_FD_MAX_IO_BUFFERS];
+	uint32_t                     *cmd_buf_addr;
+	uint32_t                      size;
+	uint32_t                      pre_config_buf_size;
+	uint32_t                      post_config_buf_size;
+	struct cam_fd_hw_req_private  hw_req_private;
+};
+
+/**
+ * struct cam_fd_hw_cmd_start_args : Start command args
+ *
+ * @hw_ctx                : HW context which submitting start command
+ * @ctx_hw_private        : HW layer's private information specific to
+ *                            this hw context
+ * @hw_req_private        : HW layer's private information specific to
+ *          this request
+ * @hw_update_entries     : HW update entries corresponds to this request
+ * @num_hw_update_entries : Number of hw update entries
+ */
+struct cam_fd_hw_cmd_start_args {
+	void                          *hw_ctx;
+	void                          *ctx_hw_private;
+	struct cam_fd_hw_req_private  *hw_req_private;
+	struct cam_hw_update_entry    *hw_update_entries;
+	uint32_t                       num_hw_update_entries;
+};
+
+/**
+ * struct cam_fd_hw_stop_args : Stop command args
+ *
+ * @hw_ctx         : HW context which submitting stop command
+ * @ctx_hw_private : HW layer's private information specific to this hw context
+ * @request_id     : Request ID that need to be stopped
+ * @hw_req_private : HW layer's private information specific to this request
+ */
+struct cam_fd_hw_stop_args {
+	void                         *hw_ctx;
+	void                         *ctx_hw_private;
+	uint64_t                      request_id;
+	struct cam_fd_hw_req_private *hw_req_private;
+};
+
+/**
+ * struct cam_fd_hw_frame_done_args : Frame done command args
+ *
+ * @hw_ctx         : HW context which submitting frame done request
+ * @ctx_hw_private : HW layer's private information specific to this hw context
+ * @request_id     : Request ID that need to be stopped
+ * @hw_req_private : HW layer's private information specific to this request
+ */
+struct cam_fd_hw_frame_done_args {
+	void                         *hw_ctx;
+	void                         *ctx_hw_private;
+	uint64_t                      request_id;
+	struct cam_fd_hw_req_private *hw_req_private;
+};
+
+/**
+ * struct cam_fd_hw_reset_args : Reset command args
+ *
+ * @hw_ctx         : HW context which submitting reset command
+ * @ctx_hw_private : HW layer's private information specific to this hw context
+ */
+struct cam_fd_hw_reset_args {
+	void    *hw_ctx;
+	void    *ctx_hw_private;
+};
+
+/**
+ * struct cam_fd_hw_cmd_set_irq_cb : Set IRQ callback command args
+ *
+ * @cam_fd_hw_mgr_cb : HW Mgr's callback pointer
+ * @data             : HW Mgr's private data
+ */
+struct cam_fd_hw_cmd_set_irq_cb {
+	int (*cam_fd_hw_mgr_cb)(void *data, enum cam_fd_hw_irq_type irq_type);
+	void *data;
+};
+
+#endif /* _CAM_FD_HW_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c
new file mode 100644
index 0000000..9045dc1
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c
@@ -0,0 +1,285 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include "cam_fd_hw_core.h"
+#include "cam_fd_hw_soc.h"
+
+static void cam_fd_hw_util_cpas_callback(uint32_t handle, void *userdata,
+	enum cam_camnoc_irq_type event_type, uint32_t event_data)
+{
+	CAM_DBG(CAM_FD, "CPAS hdl=%d, udata=%pK, event=%d, event_data=%d",
+		handle, userdata, event_type, event_data);
+}
+
+static int cam_fd_hw_soc_util_setup_regbase_indices(
+	struct cam_hw_soc_info *soc_info)
+{
+	struct cam_fd_soc_private *soc_private =
+		(struct cam_fd_soc_private *)soc_info->soc_private;
+	uint32_t index;
+	int rc, i;
+
+	for (i = 0; i < CAM_FD_REG_MAX; i++)
+		soc_private->regbase_index[i] = -1;
+
+	if ((soc_info->num_mem_block > CAM_SOC_MAX_BLOCK) ||
+		(soc_info->num_mem_block != CAM_FD_REG_MAX)) {
+		CAM_ERR(CAM_FD, "Invalid num_mem_block=%d",
+			soc_info->num_mem_block);
+		return -EINVAL;
+	}
+
+	rc = cam_common_util_get_string_index(soc_info->mem_block_name,
+		soc_info->num_mem_block, "fd_core", &index);
+	if ((rc == 0) && (index < CAM_FD_REG_MAX)) {
+		soc_private->regbase_index[CAM_FD_REG_CORE] = index;
+	} else {
+		CAM_ERR(CAM_FD, "regbase not found for FD_CORE, rc=%d, %d %d",
+			rc, index, CAM_FD_REG_MAX);
+		return -EINVAL;
+	}
+
+	rc = cam_common_util_get_string_index(soc_info->mem_block_name,
+		soc_info->num_mem_block, "fd_wrapper", &index);
+	if ((rc == 0) && (index < CAM_FD_REG_MAX)) {
+		soc_private->regbase_index[CAM_FD_REG_WRAPPER] = index;
+	} else {
+		CAM_ERR(CAM_FD, "regbase not found FD_WRAPPER, rc=%d, %d %d",
+			rc, index, CAM_FD_REG_MAX);
+		return -EINVAL;
+	}
+
+	CAM_DBG(CAM_FD, "Reg indices : CORE=%d, WRAPPER=%d",
+		soc_private->regbase_index[CAM_FD_REG_CORE],
+		soc_private->regbase_index[CAM_FD_REG_WRAPPER]);
+
+	return 0;
+}
+
+static int cam_fd_soc_set_clk_flags(struct cam_hw_soc_info *soc_info)
+{
+	int i, rc = 0;
+
+	if (soc_info->num_clk > CAM_SOC_MAX_CLK) {
+		CAM_ERR(CAM_FD, "Invalid num clk %d", soc_info->num_clk);
+		return -EINVAL;
+	}
+
+	/* set memcore and mem periphery logic flags to 0 */
+	for (i = 0; i < soc_info->num_clk; i++) {
+		if ((strcmp(soc_info->clk_name[i], "fd_core_clk") == 0) ||
+			(strcmp(soc_info->clk_name[i], "fd_core_uar_clk") ==
+			0)) {
+			rc = cam_soc_util_set_clk_flags(soc_info, i,
+				CLKFLAG_NORETAIN_MEM);
+			if (rc)
+				CAM_ERR(CAM_FD,
+					"Failed in NORETAIN_MEM i=%d, rc=%d",
+					i, rc);
+
+			cam_soc_util_set_clk_flags(soc_info, i,
+				CLKFLAG_NORETAIN_PERIPH);
+			if (rc)
+				CAM_ERR(CAM_FD,
+					"Failed in NORETAIN_PERIPH i=%d, rc=%d",
+					i, rc);
+		}
+	}
+
+	return rc;
+}
+
+void cam_fd_soc_register_write(struct cam_hw_soc_info *soc_info,
+	enum cam_fd_reg_base reg_base, uint32_t reg_offset, uint32_t reg_value)
+{
+	struct cam_fd_soc_private *soc_private =
+		(struct cam_fd_soc_private *)soc_info->soc_private;
+	int32_t reg_index = soc_private->regbase_index[reg_base];
+
+	CAM_DBG(CAM_FD, "FD_REG_WRITE: Base[%d] Offset[0x%8x] Value[0x%8x]",
+		reg_base, reg_offset, reg_value);
+
+	cam_io_w_mb(reg_value,
+		soc_info->reg_map[reg_index].mem_base + reg_offset);
+}
+
+uint32_t cam_fd_soc_register_read(struct cam_hw_soc_info *soc_info,
+	enum cam_fd_reg_base reg_base, uint32_t reg_offset)
+{
+	struct cam_fd_soc_private *soc_private =
+		(struct cam_fd_soc_private *)soc_info->soc_private;
+	int32_t reg_index = soc_private->regbase_index[reg_base];
+	uint32_t reg_value;
+
+	reg_value = cam_io_r_mb(
+		soc_info->reg_map[reg_index].mem_base + reg_offset);
+
+	CAM_DBG(CAM_FD, "FD_REG_READ: Base[%d] Offset[0x%8x] Value[0x%8x]",
+		reg_base, reg_offset, reg_value);
+
+	return reg_value;
+}
+
+int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info)
+{
+	struct cam_fd_soc_private *soc_private = soc_info->soc_private;
+	struct cam_ahb_vote ahb_vote;
+	struct cam_axi_vote axi_vote;
+	int rc;
+
+	ahb_vote.type = CAM_VOTE_ABSOLUTE;
+	ahb_vote.vote.level = CAM_SVS_VOTE;
+	axi_vote.compressed_bw = 7200000;
+	axi_vote.uncompressed_bw = 7200000;
+	rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in CPAS START, rc=%d", rc);
+		return -EFAULT;
+	}
+
+	rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE,
+		true);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error enable platform failed, rc=%d", rc);
+		goto stop_cpas;
+	}
+
+	return rc;
+
+stop_cpas:
+	if (cam_cpas_stop(soc_private->cpas_handle))
+		CAM_ERR(CAM_FD, "Error in CPAS STOP");
+
+	return rc;
+}
+
+
+int cam_fd_soc_disable_resources(struct cam_hw_soc_info *soc_info)
+{
+	struct cam_fd_soc_private *soc_private;
+	int rc = 0;
+
+	if (!soc_info) {
+		CAM_ERR(CAM_FD, "Invalid soc_info param");
+		return -EINVAL;
+	}
+	soc_private = soc_info->soc_private;
+
+	rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
+	if (rc) {
+		CAM_ERR(CAM_FD, "disable platform resources failed, rc=%d", rc);
+		return rc;
+	}
+
+	rc = cam_cpas_stop(soc_private->cpas_handle);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Error in CPAS STOP, handle=0x%x, rc=%d",
+			soc_private->cpas_handle, rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int cam_fd_soc_init_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t irq_handler, void *private_data)
+{
+	struct cam_fd_soc_private *soc_private;
+	struct cam_cpas_register_params cpas_register_param;
+	int rc;
+
+	rc = cam_soc_util_get_dt_properties(soc_info);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in get_dt_properties, rc=%d", rc);
+		return rc;
+	}
+
+	rc = cam_soc_util_request_platform_resource(soc_info, irq_handler,
+		private_data);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in request_platform_resource rc=%d",
+			rc);
+		return rc;
+	}
+
+	rc = cam_fd_soc_set_clk_flags(soc_info);
+	if (rc) {
+		CAM_ERR(CAM_FD, "failed in set_clk_flags rc=%d", rc);
+		goto release_res;
+	}
+
+	soc_private = kzalloc(sizeof(struct cam_fd_soc_private), GFP_KERNEL);
+	if (!soc_private) {
+		rc = -ENOMEM;
+		goto release_res;
+	}
+	soc_info->soc_private = soc_private;
+
+	rc = cam_fd_hw_soc_util_setup_regbase_indices(soc_info);
+	if (rc) {
+		CAM_ERR(CAM_FD, "Failed in setup regbase, rc=%d", rc);
+		goto free_soc_private;
+	}
+
+	memset(&cpas_register_param, 0, sizeof(cpas_register_param));
+	strlcpy(cpas_register_param.identifier, "fd", CAM_HW_IDENTIFIER_LENGTH);
+	cpas_register_param.cell_index = soc_info->index;
+	cpas_register_param.dev = &soc_info->pdev->dev;
+	cpas_register_param.userdata = private_data;
+	cpas_register_param.cam_cpas_client_cb = cam_fd_hw_util_cpas_callback;
+
+	rc = cam_cpas_register_client(&cpas_register_param);
+	if (rc) {
+		CAM_ERR(CAM_FD, "CPAS registration failed");
+		goto free_soc_private;
+	}
+	soc_private->cpas_handle = cpas_register_param.client_handle;
+	CAM_DBG(CAM_FD, "CPAS handle=%d", soc_private->cpas_handle);
+
+	return rc;
+
+free_soc_private:
+	kfree(soc_info->soc_private);
+	soc_info->soc_private = NULL;
+release_res:
+	cam_soc_util_release_platform_resource(soc_info);
+
+	return rc;
+}
+
+int cam_fd_soc_deinit_resources(struct cam_hw_soc_info *soc_info)
+{
+	struct cam_fd_soc_private *soc_private =
+		(struct cam_fd_soc_private *)soc_info->soc_private;
+	int rc;
+
+	rc = cam_cpas_unregister_client(soc_private->cpas_handle);
+	if (rc)
+		CAM_ERR(CAM_FD, "Unregister cpas failed, handle=%d, rc=%d",
+			soc_private->cpas_handle, rc);
+
+	rc = cam_soc_util_release_platform_resource(soc_info);
+	if (rc)
+		CAM_ERR(CAM_FD, "release platform failed, rc=%d", rc);
+
+	kfree(soc_info->soc_private);
+	soc_info->soc_private = NULL;
+
+	return rc;
+}
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h
new file mode 100644
index 0000000..4a22293
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_FD_HW_SOC_H_
+#define _CAM_FD_HW_SOC_H_
+
+#include "cam_soc_util.h"
+
+/**
+ * enum cam_fd_reg_base - Enum for FD register sets
+ *
+ * @CAM_FD_REG_CORE    : Indicates FD Core register space
+ * @CAM_FD_REG_WRAPPER : Indicates FD Wrapper register space
+ * @CAM_FD_REG_MAX     : Max number of register sets supported
+ */
+enum cam_fd_reg_base {
+	CAM_FD_REG_CORE,
+	CAM_FD_REG_WRAPPER,
+	CAM_FD_REG_MAX
+};
+
+/**
+ * struct cam_fd_soc_private : FD private SOC information
+ *
+ * @regbase_index : Mapping between Register base enum to register index in SOC
+ * @cpas_handle   : CPAS handle
+ *
+ */
+struct cam_fd_soc_private {
+	int32_t        regbase_index[CAM_FD_REG_MAX];
+	uint32_t       cpas_handle;
+};
+
+int cam_fd_soc_init_resources(struct cam_hw_soc_info *soc_info,
+	irq_handler_t irq_handler, void *private_data);
+int cam_fd_soc_deinit_resources(struct cam_hw_soc_info *soc_info);
+int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info);
+int cam_fd_soc_disable_resources(struct cam_hw_soc_info *soc_info);
+uint32_t cam_fd_soc_register_read(struct cam_hw_soc_info *soc_info,
+	enum cam_fd_reg_base reg_base, uint32_t reg_offset);
+void cam_fd_soc_register_write(struct cam_hw_soc_info *soc_info,
+	enum cam_fd_reg_base reg_base, uint32_t reg_offset, uint32_t reg_value);
+
+#endif /* _CAM_FD_HW_SOC_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h
new file mode 100644
index 0000000..70448bb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_FD_HW_V41_H_
+#define _CAM_FD_HW_V41_H_
+
+static struct cam_fd_hw_static_info cam_fd_wrapper120_core410_info = {
+	.core_version = {
+		.major  = 4,
+		.minor  = 1,
+		.incr   = 0,
+	},
+	.wrapper_version = {
+		.major  = 1,
+		.minor  = 2,
+		.incr   = 0,
+	},
+	.core_regs = {
+		.version               = 0x38,
+		.control               = 0x0,
+		.result_cnt            = 0x4,
+		.result_addr           = 0x20,
+		.image_addr            = 0x24,
+		.work_addr             = 0x28,
+		.ro_mode               = 0x34,
+		.results_reg_base      = 0x400,
+		.raw_results_reg_base  = 0x800,
+	},
+	.wrapper_regs = {
+		.wrapper_version       = 0x0,
+		.cgc_disable           = 0x4,
+		.hw_stop               = 0x8,
+		.sw_reset              = 0x10,
+		.vbif_req_priority     = 0x20,
+		.vbif_priority_level   = 0x24,
+		.vbif_done_status      = 0x34,
+		.irq_mask              = 0x50,
+		.irq_status            = 0x54,
+		.irq_clear             = 0x58,
+	},
+	.results = {
+		.max_faces             = 35,
+		.per_face_entries      = 4,
+		.raw_results_available = true,
+		.raw_results_entries   = 512,
+	},
+	.enable_errata_wa = {
+		.single_irq_only         = true,
+		.ro_mode_enable_always   = true,
+		.ro_mode_results_invalid = true,
+	},
+	.irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) |
+		CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) |
+		CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE),
+	.qos_priority       = 4,
+	.qos_priority_level = 4,
+	.supported_modes    = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID,
+	.ro_mode_supported  = true,
+};
+
+#endif /* _CAM_FD_HW_V41_H_ */
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 55a2e1b..3473d08 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
@@ -75,8 +75,8 @@
 
 	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
 	cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE;
-	cpas_vote.axi_vote.compressed_bw = ICP_TURBO_VOTE;
-	cpas_vote.axi_vote.uncompressed_bw = ICP_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	cpas_vote.axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
 
 	rc = cam_cpas_start(core_info->cpas_handle,
 			&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
@@ -269,6 +269,13 @@
 	case CAM_ICP_BPS_CMD_POWER_RESUME:
 		rc = cam_bps_handle_resume(bps_dev);
 		break;
+	case CAM_ICP_BPS_CMD_UPDATE_CLK: {
+		uint32_t clk_rate = *(uint32_t *)cmd_args;
+
+		CAM_DBG(CAM_ICP, "bps_src_clk rate = %d", (int)clk_rate);
+		rc = cam_bps_update_clk_rate(soc_info, clk_rate);
+	}
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
index 07dacb2..2477e7d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c
@@ -132,3 +132,13 @@
 
 	return rc;
 }
+
+int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info,
+	uint32_t clk_rate)
+{
+	if (!soc_info)
+		return -EINVAL;
+
+	return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx],
+		soc_info->clk_name[soc_info->src_clk_idx], clk_rate);
+}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
index 3cffb09..2dd2c08 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.h
@@ -26,4 +26,6 @@
 
 int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info);
 
+int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info,
+	uint32_t clk_rate);
 #endif /* _CAM_BPS_SOC_H_*/
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 171d8bd..7c5b405 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
@@ -45,6 +45,7 @@
 #include "a5_core.h"
 #include "hfi_sys_defs.h"
 #include "cam_debug_util.h"
+#include "cam_soc_util.h"
 
 #define ICP_WORKQ_NUM_TASK      30
 #define ICP_WORKQ_TASK_CMD_TYPE 1
@@ -52,6 +53,644 @@
 
 static struct cam_icp_hw_mgr icp_hw_mgr;
 
+static void cam_icp_hw_mgr_clk_info_update(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data)
+{
+	struct cam_icp_clk_info *hw_mgr_clk_info;
+
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
+		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS];
+	else
+		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE];
+
+	if (hw_mgr_clk_info->base_clk >= ctx_data->clk_info.base_clk)
+		hw_mgr_clk_info->base_clk -= ctx_data->clk_info.base_clk;
+}
+
+static void cam_icp_hw_mgr_reset_clk_info(struct cam_icp_hw_mgr *hw_mgr)
+{
+	int i;
+
+	for (i = 0; i < ICP_CLK_HW_MAX; i++) {
+		hw_mgr->clk_info[i].base_clk = 0;
+		hw_mgr->clk_info[i].curr_clk = ICP_TURBO_VOTE;
+		hw_mgr->clk_info[i].threshold = ICP_OVER_CLK_THRESHOLD;
+		hw_mgr->clk_info[i].over_clked = 0;
+		hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+		hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	}
+	hw_mgr->icp_default_clk = ICP_SVS_VOTE;
+}
+
+static int cam_icp_get_actual_clk_rate_idx(
+	struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk)
+{
+	int i;
+
+	for (i = 0; i < CAM_MAX_VOTE; i++)
+		if (ctx_data->clk_info.clk_rate[i] >= base_clk)
+			return i;
+
+	return 0;
+}
+
+static bool cam_icp_is_over_clk(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data,
+	struct cam_icp_clk_info *hw_mgr_clk_info)
+{
+	int base_clk_idx;
+	int curr_clk_idx;
+
+	base_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data,
+		hw_mgr_clk_info->base_clk);
+
+	curr_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data,
+		hw_mgr_clk_info->curr_clk);
+
+	CAM_DBG(CAM_ICP, "bc_idx = %d cc_idx = %d %lld %lld",
+		base_clk_idx, curr_clk_idx, hw_mgr_clk_info->base_clk,
+		hw_mgr_clk_info->curr_clk);
+
+	if (curr_clk_idx > base_clk_idx)
+		return true;
+
+	return false;
+}
+
+static int cam_icp_get_lower_clk_rate(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk)
+{
+	int i;
+
+	i = cam_icp_get_actual_clk_rate_idx(ctx_data, base_clk);
+
+	if (i > 0)
+		return ctx_data->clk_info.clk_rate[i - 1];
+
+	CAM_DBG(CAM_ICP, "Already clk at lower level");
+	return base_clk;
+}
+
+static int cam_icp_get_next_clk_rate(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk)
+{
+	int i;
+
+	i = cam_icp_get_actual_clk_rate_idx(ctx_data, base_clk);
+
+	if (i < CAM_MAX_VOTE - 1)
+		return ctx_data->clk_info.clk_rate[i + 1];
+
+	CAM_DBG(CAM_ICP, "Already clk at higher level");
+
+	return base_clk;
+}
+
+static int cam_icp_get_actual_clk_rate(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk)
+{
+	int i;
+
+	for (i = 0; i < CAM_MAX_VOTE; i++)
+		if (ctx_data->clk_info.clk_rate[i] >= base_clk)
+			return ctx_data->clk_info.clk_rate[i];
+
+	return base_clk;
+}
+
+static int cam_icp_supported_clk_rates(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data)
+{
+	int i;
+	struct cam_hw_soc_info *soc_info;
+	struct cam_hw_intf *dev_intf = NULL;
+	struct cam_hw_info *dev = NULL;
+
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
+		dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+	else
+		dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+
+	if (!dev_intf) {
+		CAM_ERR(CAM_ICP, "dev_intf is invalid");
+		return -EINVAL;
+	}
+	dev = (struct cam_hw_info *)dev_intf->hw_priv;
+	soc_info = &dev->soc_info;
+
+	for (i = 0; i < CAM_MAX_VOTE; i++) {
+		ctx_data->clk_info.clk_rate[i] =
+			soc_info->clk_rate[i][soc_info->num_clk - 1];
+		CAM_DBG(CAM_ICP, "clk_info = %d",
+			ctx_data->clk_info.clk_rate[i]);
+	}
+
+	return 0;
+}
+
+static int cam_icp_clk_idx_from_req_id(struct cam_icp_hw_ctx_data *ctx_data,
+	uint64_t req_id)
+{
+	struct hfi_frame_process_info *frame_process;
+	int i;
+
+	frame_process = &ctx_data->hfi_frame_process;
+
+	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
+		if (frame_process->request_id[i] == req_id)
+			return i;
+
+	return 0;
+}
+
+static int cam_icp_clk_info_init(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data)
+{
+	int i;
+
+	for (i = 0; i < ICP_CLK_HW_MAX; i++) {
+		hw_mgr->clk_info[i].base_clk = ICP_TURBO_VOTE;
+		hw_mgr->clk_info[i].curr_clk = ICP_TURBO_VOTE;
+		hw_mgr->clk_info[i].threshold = ICP_OVER_CLK_THRESHOLD;
+		hw_mgr->clk_info[i].over_clked = 0;
+		hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+		hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	}
+	hw_mgr->icp_default_clk = ICP_SVS_VOTE;
+
+	return 0;
+}
+
+static int cam_icp_ctx_clk_info_init(struct cam_icp_hw_ctx_data *ctx_data)
+{
+	ctx_data->clk_info.curr_fc = 0;
+	ctx_data->clk_info.base_clk = 0;
+	ctx_data->clk_info.uncompressed_bw = 0;
+	ctx_data->clk_info.compressed_bw = 0;
+	cam_icp_supported_clk_rates(&icp_hw_mgr, ctx_data);
+
+	return 0;
+}
+
+static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles,
+	uint64_t budget)
+{
+	uint64_t base_clk;
+	uint64_t mul = 1000000000;
+
+	base_clk = (frame_cycles * mul) / budget;
+
+	CAM_DBG(CAM_ICP, "budget = %lld fc = %d ib = %lld base_clk = %lld",
+		budget, frame_cycles,
+		(long long int)(frame_cycles * mul), base_clk);
+
+	return base_clk;
+}
+
+static bool cam_icp_busy_prev_reqs(struct hfi_frame_process_info *frm_process,
+	uint64_t req_id)
+{
+	int i;
+	int cnt;
+
+	for (i = 0, cnt = 0; i < CAM_FRAME_CMD_MAX; i++) {
+		if (frm_process->request_id[i]) {
+			if (frm_process->fw_process_flag[i]) {
+				CAM_DBG(CAM_ICP, "r id = %lld busy = %d",
+					frm_process->request_id[i],
+					frm_process->fw_process_flag[i]);
+				cnt++;
+			}
+		}
+	}
+	if (cnt > 1)
+		return true;
+
+	return false;
+}
+
+static int cam_icp_calc_total_clk(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_clk_info *hw_mgr_clk_info, uint32_t dev_type)
+{
+	int i;
+	struct cam_icp_hw_ctx_data *ctx_data;
+
+	hw_mgr_clk_info->base_clk = 0;
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
+		ctx_data = &hw_mgr->ctx_data[i];
+		if (ctx_data->in_use &&
+			ctx_data->icp_dev_acquire_info->dev_type == dev_type)
+			hw_mgr_clk_info->base_clk +=
+				ctx_data->clk_info.base_clk;
+	}
+
+	return 0;
+}
+
+static bool cam_icp_update_clk_busy(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data,
+	struct cam_icp_clk_info *hw_mgr_clk_info,
+	struct cam_icp_clk_bw_request *clk_info,
+	uint32_t base_clk)
+{
+	uint32_t next_clk_level;
+	uint32_t actual_clk;
+
+	/* 1. if current request frame cycles(fc) are more than previous
+	 *      frame fc
+	 *      Calculate the new base clock.
+	 *      if sum of base clocks are more than next available clk level
+	 *       Update clock rate, change curr_clk_rate to sum of base clock
+	 *       rates and make over_clked to zero
+	 *      else
+	 *       Update clock rate to next level, update curr_clk_rate and make
+	 *       overclked cnt to zero
+	 * 2. if current fc is less than or equal to previous  frame fc
+	 *      Still Bump up the clock to next available level
+	 *      if it is available, then update clock, make overclk cnt to
+	 *      zero
+	 */
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	ctx_data->clk_info.curr_fc = clk_info->frame_cycles;
+	ctx_data->clk_info.base_clk = base_clk;
+	hw_mgr_clk_info->over_clked = 0;
+	if (clk_info->frame_cycles > ctx_data->clk_info.curr_fc) {
+		cam_icp_calc_total_clk(hw_mgr, hw_mgr_clk_info,
+			ctx_data->icp_dev_acquire_info->dev_type);
+		actual_clk = cam_icp_get_actual_clk_rate(hw_mgr,
+			ctx_data, base_clk);
+		if (hw_mgr_clk_info->base_clk > actual_clk) {
+			hw_mgr_clk_info->curr_clk = hw_mgr_clk_info->base_clk;
+		} else {
+			next_clk_level = cam_icp_get_next_clk_rate(hw_mgr,
+				ctx_data, hw_mgr_clk_info->curr_clk);
+			hw_mgr_clk_info->curr_clk = next_clk_level;
+		}
+	} else {
+		hw_mgr_clk_info->curr_clk =
+			cam_icp_get_next_clk_rate(hw_mgr, ctx_data,
+			hw_mgr_clk_info->curr_clk);
+	}
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	return true;
+}
+
+static bool cam_icp_update_clk_overclk_free(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data,
+	struct cam_icp_clk_info *hw_mgr_clk_info,
+	struct cam_icp_clk_bw_request *clk_info,
+	uint32_t base_clk)
+{
+	int rc = false;
+
+	/*
+	 * In caseof no pending packets case
+	 *    1. In caseof overclk cnt is less than threshold, increase
+	 *       overclk count and no update in the clock rate
+	 *    2. In caseof overclk cnt is greater than or equal to threshold
+	 *       then lower clock rate by one level and update hw_mgr current
+	 *       clock value.
+	 *        a. In case of new clock rate greater than sum of clock
+	 *           rates, reset overclk count value to zero if it is
+	 *           overclock
+	 *        b. if it is less than sum of base clocks then go to next
+	 *           level of clock and make overclk count to zero
+	 *        c. if it is same as sum of base clock rates update overclock
+	 *           cnt to 0
+	 */
+	if (hw_mgr_clk_info->over_clked < hw_mgr_clk_info->threshold) {
+		hw_mgr_clk_info->over_clked++;
+		rc = false;
+	} else {
+		hw_mgr_clk_info->curr_clk =
+			cam_icp_get_lower_clk_rate(hw_mgr, ctx_data,
+			hw_mgr_clk_info->curr_clk);
+		if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk) {
+			if (cam_icp_is_over_clk(hw_mgr, ctx_data,
+				hw_mgr_clk_info))
+				hw_mgr_clk_info->over_clked = 0;
+		} else if (hw_mgr_clk_info->curr_clk <
+			hw_mgr_clk_info->base_clk) {
+			hw_mgr_clk_info->curr_clk =
+				cam_icp_get_next_clk_rate(hw_mgr, ctx_data,
+				hw_mgr_clk_info->curr_clk);
+				hw_mgr_clk_info->over_clked = 0;
+		} else if (hw_mgr_clk_info->curr_clk ==
+			hw_mgr_clk_info->base_clk) {
+			hw_mgr_clk_info->over_clked = 0;
+		}
+		rc = true;
+	}
+
+	return rc;
+}
+
+static bool cam_icp_update_clk_free(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data,
+	struct cam_icp_clk_info *hw_mgr_clk_info,
+	struct cam_icp_clk_bw_request *clk_info,
+	uint32_t base_clk)
+{
+	int rc = false;
+	bool over_clocked = false;
+
+	ctx_data->clk_info.curr_fc = clk_info->frame_cycles;
+	ctx_data->clk_info.base_clk = base_clk;
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	cam_icp_calc_total_clk(hw_mgr, hw_mgr_clk_info,
+		ctx_data->icp_dev_acquire_info->dev_type);
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	/*
+	 * Current clock is not always sum of base clocks, due to
+	 * clock scales update to next higher or lower levels, it
+	 * equals to one of discrete clock values supported by hardware.
+	 * So even current clock is higher than sum of base clocks, we
+	 * can not consider it is over clocked. if it is greater than
+	 * discrete clock level then only it is considered as over clock.
+	 * 1. Handle over clock case
+	 * 2. If current clock is less than sum of base clocks
+	 *    update current clock
+	 * 3. If current clock is same as sum of base clocks no action
+	 */
+
+	over_clocked = cam_icp_is_over_clk(hw_mgr, ctx_data,
+		hw_mgr_clk_info);
+
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk &&
+		over_clocked) {
+		rc = cam_icp_update_clk_overclk_free(hw_mgr, ctx_data,
+			hw_mgr_clk_info, clk_info, base_clk);
+	} else if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk) {
+		hw_mgr_clk_info->over_clked = 0;
+		rc = false;
+	}  else if (hw_mgr_clk_info->curr_clk < hw_mgr_clk_info->base_clk) {
+		hw_mgr_clk_info->curr_clk = hw_mgr_clk_info->base_clk;
+		rc = true;
+	}
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+
+	return rc;
+}
+
+static bool cam_icp_debug_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info)
+{
+	if (icp_hw_mgr.icp_debug_clk < ICP_TURBO_VOTE &&
+		icp_hw_mgr.icp_debug_clk &&
+		icp_hw_mgr.icp_debug_clk != hw_mgr_clk_info->curr_clk) {
+		mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+		hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_debug_clk;
+		hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_debug_clk;
+		hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_debug_clk;
+		hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_debug_clk;
+		mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+		CAM_DBG(CAM_ICP, "bc = %d cc = %d",
+			hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk);
+		return true;
+	}
+
+	return false;
+}
+
+static bool cam_icp_default_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info)
+{
+	if (icp_hw_mgr.icp_default_clk != hw_mgr_clk_info->curr_clk) {
+		mutex_lock(&icp_hw_mgr.hw_mgr_mutex);
+		hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_default_clk;
+		hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_default_clk;
+		hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_default_clk;
+		hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_default_clk;
+		mutex_unlock(&icp_hw_mgr.hw_mgr_mutex);
+		CAM_DBG(CAM_ICP, "bc = %d cc = %d",
+			hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk);
+		return true;
+	}
+
+	return false;
+}
+
+static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data,
+	struct cam_icp_clk_info *hw_mgr_clk_info,
+	struct cam_icp_clk_bw_request *clk_info,
+	bool busy)
+{
+	int i;
+	struct cam_icp_hw_ctx_data *ctx;
+
+	/*
+	 * If current request bandwidth is different from previous frames, then
+	 * recalculate bandwidth of all contexts of same hardware and update
+	 * voting of bandwidth
+	 */
+	if (clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw)
+		return false;
+
+	if (busy &&
+		ctx_data->clk_info.uncompressed_bw > clk_info->uncompressed_bw)
+		return false;
+
+	ctx_data->clk_info.uncompressed_bw = clk_info->uncompressed_bw;
+	ctx_data->clk_info.compressed_bw = clk_info->compressed_bw;
+	hw_mgr_clk_info->uncompressed_bw = 0;
+	hw_mgr_clk_info->compressed_bw = 0;
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
+		ctx = &hw_mgr->ctx_data[i];
+		if (ctx->in_use &&
+			ctx->icp_dev_acquire_info->dev_type ==
+			ctx_data->icp_dev_acquire_info->dev_type) {
+			mutex_lock(&hw_mgr->hw_mgr_mutex);
+			hw_mgr_clk_info->uncompressed_bw +=
+				ctx->clk_info.uncompressed_bw;
+			hw_mgr_clk_info->compressed_bw +=
+				ctx->clk_info.compressed_bw;
+			mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		}
+	}
+
+	return true;
+}
+
+static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data, int idx)
+{
+	bool busy, rc = false;
+	uint32_t base_clk;
+	struct cam_icp_clk_bw_request *clk_info;
+	struct hfi_frame_process_info *frame_info;
+	uint64_t req_id;
+	struct cam_icp_clk_info *hw_mgr_clk_info;
+
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
+		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS];
+	else
+		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE];
+
+	if (icp_hw_mgr.icp_debug_clk)
+		return cam_icp_debug_clk_update(hw_mgr_clk_info);
+
+	/* Check is there any pending frames in this context */
+	frame_info = &ctx_data->hfi_frame_process;
+	req_id = frame_info->request_id[idx];
+	busy = cam_icp_busy_prev_reqs(frame_info, req_id);
+	CAM_DBG(CAM_ICP, "busy = %d req_id = %lld", busy, req_id);
+
+	clk_info = &ctx_data->hfi_frame_process.clk_info[idx];
+	if (!clk_info->frame_cycles)
+		return cam_icp_default_clk_update(hw_mgr_clk_info);
+
+	/* Calculate base clk rate */
+	base_clk = cam_icp_mgr_calc_base_clk(
+		clk_info->frame_cycles, clk_info->budget_ns);
+	ctx_data->clk_info.rt_flag = clk_info->rt_flag;
+
+	if (busy)
+		rc = cam_icp_update_clk_busy(hw_mgr, ctx_data,
+			hw_mgr_clk_info, clk_info, base_clk);
+	else
+		rc = cam_icp_update_clk_free(hw_mgr, ctx_data,
+			hw_mgr_clk_info, clk_info, base_clk);
+
+	CAM_DBG(CAM_ICP, "bc = %d cc = %d busy = %d overclk = %d uc = %d",
+		hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk,
+		busy, hw_mgr_clk_info->over_clked, rc);
+
+	return rc;
+}
+
+static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data, int idx)
+{
+	bool busy, rc = false;
+	struct cam_icp_clk_bw_request *clk_info;
+	struct cam_icp_clk_info *hw_mgr_clk_info;
+	struct hfi_frame_process_info *frame_info;
+	uint64_t req_id;
+
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
+		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS];
+	else
+		hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE];
+
+	clk_info = &ctx_data->hfi_frame_process.clk_info[idx];
+	frame_info = &ctx_data->hfi_frame_process;
+	req_id = frame_info->request_id[idx];
+	busy = cam_icp_busy_prev_reqs(frame_info, req_id);
+	rc = cam_icp_update_bw(hw_mgr, ctx_data, hw_mgr_clk_info,
+		clk_info, busy);
+
+	CAM_DBG(CAM_ICP, "bw = %d update_bw = %d",
+		hw_mgr_clk_info->uncompressed_bw, rc);
+
+	return rc;
+}
+
+static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data)
+{
+	uint32_t id;
+	uint32_t curr_clk_rate;
+	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;
+
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+
+	if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+		CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk");
+		return -EINVAL;
+	}
+
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
+		dev_intf = bps_dev_intf;
+		curr_clk_rate = hw_mgr->clk_info[ICP_CLK_HW_BPS].curr_clk;
+		id = CAM_ICP_BPS_CMD_UPDATE_CLK;
+	} else {
+		dev_intf = ipe0_dev_intf;
+		curr_clk_rate = hw_mgr->clk_info[ICP_CLK_HW_IPE].curr_clk;
+		id = CAM_ICP_IPE_CMD_UPDATE_CLK;
+	}
+
+	dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
+		&curr_clk_rate, sizeof(curr_clk_rate));
+
+	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));
+
+	return 0;
+}
+
+static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data)
+{
+	uint32_t id;
+	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_icp_clk_info *clk_info;
+	struct cam_icp_cpas_vote clk_update;
+
+	ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+	ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+	bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+
+	if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+		CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk");
+		return -EINVAL;
+	}
+
+	if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
+		dev_intf = bps_dev_intf;
+		clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS];
+		id = CAM_ICP_BPS_CMD_VOTE_CPAS;
+	} else {
+		dev_intf = ipe0_dev_intf;
+		clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE];
+		id = CAM_ICP_IPE_CMD_VOTE_CPAS;
+	}
+
+	clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC;
+	clk_update.ahb_vote.vote.freq = clk_info->curr_clk;
+	clk_update.ahb_vote_valid = true;
+	clk_update.axi_vote.compressed_bw = clk_info->compressed_bw;
+	clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw;
+	clk_update.axi_vote_valid = true;
+	dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id,
+		&clk_update, sizeof(clk_update));
+
+	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,
+				&clk_update, sizeof(clk_update));
+
+	return 0;
+}
+
+static int cam_icp_mgr_ipe_bps_clk_update(struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_icp_hw_ctx_data *ctx_data, int idx)
+{
+	int rc = 0;
+
+	if (cam_icp_check_clk_update(hw_mgr, ctx_data, idx))
+		rc = cam_icp_update_clk_rate(hw_mgr, ctx_data);
+
+	if (cam_icp_check_bw_update(hw_mgr, ctx_data, idx))
+		rc |= cam_icp_update_cpas_vote(hw_mgr, ctx_data);
+
+	return rc;
+}
+
 static int cam_icp_mgr_ipe_bps_resume(struct cam_icp_hw_mgr *hw_mgr,
 	struct cam_icp_hw_ctx_data *ctx_data)
 {
@@ -128,8 +767,26 @@
 	return rc;
 }
 
+static int cam_icp_set_dbg_default_clk(void *data, u64 val)
+{
+	icp_hw_mgr.icp_debug_clk = val;
+	return 0;
+}
+
+static int cam_icp_get_dbg_default_clk(void *data, u64 *val)
+{
+	*val = icp_hw_mgr.icp_debug_clk;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_default_clk,
+	cam_icp_get_dbg_default_clk,
+	cam_icp_set_dbg_default_clk, "%16llu");
+
 static int cam_icp_hw_mgr_create_debugfs_entry(void)
 {
+	int rc = 0;
+
 	icp_hw_mgr.dentry = debugfs_create_dir("camera_icp", NULL);
 	if (!icp_hw_mgr.dentry)
 		return -ENOMEM;
@@ -139,7 +796,8 @@
 		icp_hw_mgr.dentry,
 		&icp_hw_mgr.a5_debug)) {
 		debugfs_remove_recursive(icp_hw_mgr.dentry);
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto err;
 	}
 
 	if (!debugfs_create_bool("icp_pc",
@@ -147,10 +805,23 @@
 		icp_hw_mgr.dentry,
 		&icp_hw_mgr.icp_pc_flag)) {
 		CAM_ERR(CAM_ICP, "failed to create icp_pc entry");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto err;
 	}
 
-	return 0;
+	if (!debugfs_create_file("icp_debug_clk",
+		0644,
+		icp_hw_mgr.dentry, NULL,
+		&cam_icp_debug_default_clk)) {
+		CAM_ERR(CAM_ICP, "failed to create icp_debug_clk entry");
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	return rc;
+err:
+	debugfs_remove_recursive(icp_hw_mgr.dentry);
+	return rc;
 }
 
 static int cam_icp_mgr_process_cmd(void *priv, void *data)
@@ -210,6 +881,7 @@
 	ctx_data->ctxt_event_cb(ctx_data->context_priv, flag, &buf_data);
 	hfi_frame_process->request_id[idx] = 0;
 	clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
+	hfi_frame_process->fw_process_flag[idx] = false;
 	mutex_unlock(&ctx_data->ctx_mutex);
 
 	return 0;
@@ -228,7 +900,7 @@
 	ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
 	if (ioconfig_ack->err_type != HFI_ERR_SYS_NONE) {
 		CAM_ERR(CAM_ICP, "failed with error : %u",
-			ioconfig_ack->err_type);
+		ioconfig_ack->err_type);
 		cam_icp_mgr_handle_frame_process(msg_ptr,
 			ICP_FRAME_PROCESS_FAILURE);
 		return -EIO;
@@ -791,6 +1463,9 @@
 	for (i = 0; i < CAM_FRAME_CMD_MAX; i++)
 		clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
 	kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap);
+	cam_icp_hw_mgr_clk_info_update(hw_mgr, &hw_mgr->ctx_data[ctx_id]);
+	hw_mgr->ctx_data[ctx_id].clk_info.curr_fc = 0;
+	hw_mgr->ctx_data[ctx_id].clk_info.base_clk = 0;
 	hw_mgr->ctxt_cnt--;
 	kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info);
 	hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL;
@@ -1135,13 +1810,18 @@
 
 static int cam_icp_mgr_handle_config_err(
 	struct cam_hw_config_args *config_args,
-	struct cam_icp_hw_ctx_data *ctx_data)
+	struct cam_icp_hw_ctx_data *ctx_data,
+	int idx)
 {
 	struct cam_hw_done_event_data buf_data;
 
 	buf_data.request_id = *(uint64_t *)config_args->priv;
 	ctx_data->ctxt_event_cb(ctx_data->context_priv, true, &buf_data);
 
+	ctx_data->hfi_frame_process.request_id[idx] = 0;
+	ctx_data->hfi_frame_process.fw_process_flag[idx] = false;
+	clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
+
 	return 0;
 }
 
@@ -1180,6 +1860,8 @@
 static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args)
 {
 	int rc = 0;
+	int idx;
+	uint64_t req_id;
 	struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
 	struct cam_hw_config_args *config_args = config_hw_args;
 	struct cam_icp_hw_ctx_data *ctx_data = NULL;
@@ -1199,10 +1881,14 @@
 	mutex_lock(&ctx_data->ctx_mutex);
 	if (!ctx_data->in_use) {
 		CAM_ERR(CAM_ICP, "ctx is not in use");
-		rc = -EINVAL;
-		goto config_err;
+		return -EINVAL;
 	}
 
+	req_id = *(uint64_t *)config_args->priv;
+	idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id);
+	ctx_data->hfi_frame_process.fw_process_flag[idx] = true;
+	cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx);
+
 	rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args);
 	if (rc)
 		goto config_err;
@@ -1210,8 +1896,8 @@
 
 	return 0;
 config_err:
+	cam_icp_mgr_handle_config_err(config_args, ctx_data, idx);
 	mutex_unlock(&ctx_data->ctx_mutex);
-	cam_icp_mgr_handle_config_err(config_args, ctx_data);
 	return rc;
 }
 
@@ -1250,14 +1936,8 @@
 			packet->header.op_code & 0xff);
 		return -EINVAL;
 	}
-
-	if ((packet->num_cmd_buf > 1) || (!packet->num_patches) ||
-		(!packet->num_io_configs)) {
-		CAM_ERR(CAM_ICP, "wrong number of cmd/patch info: %u %u",
+	CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u",
 			packet->num_cmd_buf, packet->num_patches);
-		return -EINVAL;
-	}
-
 	return 0;
 }
 
@@ -1266,25 +1946,29 @@
 	uint32_t *fw_cmd_buf_iova_addr)
 {
 	int rc = 0;
-	uint64_t iova_addr;
-	size_t   fw_cmd_buf_len;
+	int i;
+	uint64_t addr;
+	size_t len;
 	struct cam_cmd_buf_desc *cmd_desc = NULL;
 
 	cmd_desc = (struct cam_cmd_buf_desc *)
 		((uint32_t *) &packet->payload + packet->cmd_buf_offset/4);
 
-	rc = cam_mem_get_io_buf(cmd_desc->mem_handle,
-		hw_mgr->iommu_hdl, &iova_addr, &fw_cmd_buf_len);
-	if (rc) {
-		CAM_ERR(CAM_ICP, "unable to get src buf info for cmd buf: %x",
-			hw_mgr->iommu_hdl);
-		return rc;
+	*fw_cmd_buf_iova_addr = 0;
+	for (i = 0; i < packet->num_cmd_buf; i++) {
+		if (cmd_desc[i].type == CAM_CMD_BUF_FW) {
+			rc = cam_mem_get_io_buf(cmd_desc[i].mem_handle,
+				hw_mgr->iommu_hdl, &addr, &len);
+			if (rc) {
+				CAM_ERR(CAM_ICP, "get cmd buf failed %x",
+					hw_mgr->iommu_hdl);
+				return rc;
+			}
+			*fw_cmd_buf_iova_addr = addr;
+			*fw_cmd_buf_iova_addr =
+				(*fw_cmd_buf_iova_addr + cmd_desc[i].offset);
+		}
 	}
-	CAM_DBG(CAM_ICP, "cmd_buf desc cpu and iova address: %pK %zu",
-		(void *)iova_addr, fw_cmd_buf_len);
-
-	*fw_cmd_buf_iova_addr = iova_addr;
-	*fw_cmd_buf_iova_addr = (*fw_cmd_buf_iova_addr + cmd_desc->offset);
 
 	return rc;
 }
@@ -1317,13 +2001,87 @@
 	}
 }
 
+static int cam_icp_packet_generic_blob_handler(void *user_data,
+	uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
+{
+	struct cam_icp_clk_bw_request *soc_req;
+	struct cam_icp_clk_bw_request *clk_info;
+	struct icp_cmd_generic_blob *blob;
+	struct cam_icp_hw_ctx_data *ctx_data;
+	uint32_t index;
+	int rc = 0;
+
+	if (!blob_data || (blob_size == 0)) {
+		CAM_ERR(CAM_ICP, "Invalid blob info %pK %d", blob_data,
+			blob_size);
+		return -EINVAL;
+	}
+
+	blob = (struct icp_cmd_generic_blob *)user_data;
+	ctx_data = blob->ctx;
+	index = blob->frame_info_idx;
+
+	switch (blob_type) {
+	case CAM_ICP_CMD_GENERIC_BLOB_CLK:
+		if (blob_size != sizeof(struct cam_icp_clk_bw_request)) {
+			rc = -EINVAL;
+			break;
+		}
+		clk_info = &ctx_data->hfi_frame_process.clk_info[index];
+		memset(clk_info, 0, sizeof(struct cam_icp_clk_bw_request));
+
+		soc_req = (struct cam_icp_clk_bw_request *)blob_data;
+		*clk_info = *soc_req;
+		CAM_DBG(CAM_ICP, "%llu %llu %d %d %d",
+			clk_info->budget_ns, clk_info->frame_cycles,
+			clk_info->rt_flag, clk_info->uncompressed_bw,
+			clk_info->compressed_bw);
+		break;
+
+	default:
+		CAM_WARN(CAM_ICP, "Invalid blob type %d", blob_type);
+		break;
+	}
+	return rc;
+}
+
+static int cam_icp_process_generic_cmd_buffer(
+	struct cam_packet *packet,
+	struct cam_icp_hw_ctx_data *ctx_data,
+	int32_t index)
+{
+	int i, rc = 0;
+	struct cam_cmd_buf_desc *cmd_desc = NULL;
+	struct icp_cmd_generic_blob cmd_generic_blob;
+
+	cmd_generic_blob.ctx = ctx_data;
+	cmd_generic_blob.frame_info_idx = index;
+
+	cmd_desc = (struct cam_cmd_buf_desc *)
+		((uint32_t *) &packet->payload + packet->cmd_buf_offset/4);
+	for (i = 0; i < packet->num_cmd_buf; i++) {
+		if (!cmd_desc[i].length)
+			continue;
+
+		if (cmd_desc[i].meta_data != CAM_ICP_CMD_META_GENERIC_BLOB)
+			continue;
+
+		rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[i],
+			cam_icp_packet_generic_blob_handler, &cmd_generic_blob);
+		if (rc)
+			CAM_ERR(CAM_ICP, "Failed in processing blobs %d", rc);
+	}
+
+	return rc;
+}
+
 static int cam_icp_mgr_update_hfi_frame_process(
 	struct cam_icp_hw_ctx_data *ctx_data,
 	struct cam_packet *packet,
 	struct cam_hw_prepare_update_args *prepare_args,
 	int32_t *idx)
 {
-	int32_t index;
+	int32_t index, rc;
 
 	index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap,
 		ctx_data->hfi_frame_process.bits);
@@ -1335,7 +2093,12 @@
 
 	ctx_data->hfi_frame_process.request_id[index] =
 		packet->header.request_id;
-
+	rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index);
+	if (rc) {
+		clear_bit(index, ctx_data->hfi_frame_process.bitmap);
+		ctx_data->hfi_frame_process.request_id[index] = -1;
+		return rc;
+	}
 	*idx = index;
 
 	return 0;
@@ -1475,6 +2238,7 @@
 		cam_icp_mgr_ipe_bps_power_collapse(hw_mgr,
 			NULL, 0);
 		cam_icp_mgr_hw_close(hw_mgr, NULL);
+		cam_icp_hw_mgr_reset_clk_info(hw_mgr);
 	}
 
 	return rc;
@@ -1730,6 +2494,9 @@
 	mutex_lock(&hw_mgr->hw_mgr_mutex);
 	if (!hw_mgr->ctxt_cnt) {
 		mutex_unlock(&hw_mgr->hw_mgr_mutex);
+		rc = cam_icp_clk_info_init(hw_mgr, ctx_data);
+		if (rc)
+			goto get_io_buf_failed;
 		rc = cam_icp_mgr_download_fw(hw_mgr, ctx_data);
 		if (rc)
 			goto get_io_buf_failed;
@@ -1775,6 +2542,7 @@
 		icp_dev_acquire_info, sizeof(struct cam_icp_acquire_dev_info)))
 		goto copy_to_user_failed;
 
+	cam_icp_ctx_clk_info_init(ctx_data);
 	mutex_unlock(&ctx_data->ctx_mutex);
 	CAM_DBG(CAM_ICP, "scratch size = %x fw_handle = %x",
 			(unsigned int)icp_dev_acquire_info->scratch_mem_size,
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 27a86b2..d4f5482 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
@@ -24,7 +24,7 @@
 #include "cam_req_mgr_workq.h"
 #include "cam_mem_mgr.h"
 #include "cam_smmu_api.h"
-
+#include "cam_soc_util.h"
 
 #define CAM_ICP_ROLE_PARENT     1
 #define CAM_ICP_ROLE_CHILD      2
@@ -45,6 +45,12 @@
 #define ICP_FRAME_PROCESS_SUCCESS 0
 #define ICP_FRAME_PROCESS_FAILURE 1
 
+#define ICP_CLK_HW_IPE          0x0
+#define ICP_CLK_HW_BPS          0x1
+#define ICP_CLK_HW_MAX          0x2
+
+#define ICP_OVER_CLK_THRESHOLD  15
+
 /**
  * struct icp_hfi_mem_info
  * @qtbl: Memory info of queue table
@@ -97,6 +103,8 @@
  * @request_id: Request id list
  * @num_out_resources: Number of out syncs
  * @out_resource: Out sync info
+ * @fw_process_flag: Frame process flag
+ * @clk_info: Clock information for a request
  */
 struct hfi_frame_process_info {
 	struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX];
@@ -106,9 +114,28 @@
 	uint64_t request_id[CAM_FRAME_CMD_MAX];
 	uint32_t num_out_resources[CAM_FRAME_CMD_MAX];
 	uint32_t out_resource[CAM_FRAME_CMD_MAX][CAM_MAX_OUT_RES];
+	uint32_t fw_process_flag[CAM_FRAME_CMD_MAX];
+	struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX];
 };
 
 /**
+ * struct cam_ctx_clk_info
+ * @curr_fc: Context latest request frame cycles
+ * @rt_flag: Flag to indicate real time request
+ * @base_clk: Base clock to process the request
+ * #uncompressed_bw: Current bandwidth voting
+ * @compressed_bw: Current compressed bandwidth voting
+ * @clk_rate: Supported clock rates for the context
+ */
+struct cam_ctx_clk_info {
+	uint32_t curr_fc;
+	uint32_t rt_flag;
+	uint32_t base_clk;
+	uint32_t uncompressed_bw;
+	uint32_t compressed_bw;
+	int32_t clk_rate[CAM_MAX_VOTE];
+};
+/**
  * struct cam_icp_hw_ctx_data
  * @context_priv: Context private data
  * @ctx_mutex: Mutex for context
@@ -122,8 +149,9 @@
  * @chain_ctx: Peer context
  * @hfi_frame_process: Frame process command
  * @wait_complete: Completion info
- * @ctx_id: Context Id
  * @temp_payload: Payload for destroy handle data
+ * @ctx_id: Context Id
+ * @clk_info: Current clock info of a context
  */
 struct cam_icp_hw_ctx_data {
 	void *context_priv;
@@ -140,6 +168,35 @@
 	struct completion wait_complete;
 	struct ipe_bps_destroy temp_payload;
 	uint32_t ctx_id;
+	struct cam_ctx_clk_info clk_info;
+};
+
+/**
+ * struct icp_cmd_generic_blob
+ * @ctx: Current context info
+ * @frame_info_idx: Index used for frame process info
+ */
+struct icp_cmd_generic_blob {
+	struct cam_icp_hw_ctx_data *ctx;
+	uint32_t frame_info_idx;
+};
+
+/**
+ * struct cam_icp_clk_info
+ * @base_clk: Base clock to process request
+ * @curr_clk: Current clock of hadrware
+ * @threshold: Threshold for overclk count
+ * @over_clked: Over clock count
+ * #uncompressed_bw: Current bandwidth voting
+ * @compressed_bw: Current compressed bandwidth voting
+ */
+struct cam_icp_clk_info {
+	uint32_t base_clk;
+	uint32_t curr_clk;
+	uint32_t threshold;
+	uint32_t over_clked;
+	uint32_t uncompressed_bw;
+	uint32_t compressed_bw;
 };
 
 /**
@@ -166,6 +223,9 @@
  * @dentry: Debugfs entry
  * @a5_debug: A5 debug flag
  * @icp_pc_flag: Flag to enable/disable power collapse
+ * @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
  */
 struct cam_icp_hw_mgr {
 	struct mutex hw_mgr_mutex;
@@ -192,6 +252,9 @@
 	struct dentry *dentry;
 	bool a5_debug;
 	bool icp_pc_flag;
+	uint64_t icp_debug_clk;
+	uint64_t icp_default_clk;
+	struct cam_icp_clk_info clk_info[ICP_CLK_HW_MAX];
 };
 
 static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h
index 4427a30..d79187f 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h
@@ -26,6 +26,7 @@
 	CAM_ICP_BPS_CMD_VOTE_CPAS,
 	CAM_ICP_BPS_CMD_CPAS_START,
 	CAM_ICP_BPS_CMD_CPAS_STOP,
+	CAM_ICP_BPS_CMD_UPDATE_CLK,
 	CAM_ICP_BPS_CMD_MAX,
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h
index 0db66c0..697757e 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h
@@ -26,6 +26,7 @@
 	CAM_ICP_IPE_CMD_VOTE_CPAS,
 	CAM_ICP_IPE_CMD_CPAS_START,
 	CAM_ICP_IPE_CMD_CPAS_STOP,
+	CAM_ICP_IPE_CMD_UPDATE_CLK,
 	CAM_ICP_IPE_CMD_MAX,
 };
 
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
index 2f100ca..d99a878 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
@@ -18,7 +18,8 @@
 #include <linux/of.h>
 #include "cam_cpas_api.h"
 
-#define ICP_TURBO_VOTE           640000000
+#define ICP_TURBO_VOTE           600000000
+#define ICP_SVS_VOTE             400000000
 
 int cam_icp_hw_mgr_init(struct device_node *of_node,
 	uint64_t *hw_mgr_hdl);
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 79c3388..8630e34 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
@@ -73,8 +73,8 @@
 
 	cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
 	cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE;
-	cpas_vote.axi_vote.compressed_bw = ICP_TURBO_VOTE;
-	cpas_vote.axi_vote.uncompressed_bw = ICP_TURBO_VOTE;
+	cpas_vote.axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+	cpas_vote.axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
 
 	rc = cam_cpas_start(core_info->cpas_handle,
 		&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
@@ -263,6 +263,13 @@
 	case CAM_ICP_IPE_CMD_POWER_RESUME:
 		rc = cam_ipe_handle_resume(ipe_dev);
 		break;
+	case CAM_ICP_IPE_CMD_UPDATE_CLK: {
+		uint32_t clk_rate = *(uint32_t *)cmd_args;
+
+		CAM_DBG(CAM_ICP, "ipe_src_clk rate = %d", (int)clk_rate);
+		rc = cam_ipe_update_clk_rate(soc_info, clk_rate);
+		}
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
index e7b2733f..49176b5 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c
@@ -135,3 +135,13 @@
 
 	return rc;
 }
+
+int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info,
+	uint32_t clk_rate)
+{
+	if (!soc_info)
+		return -EINVAL;
+
+	return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx],
+		soc_info->clk_name[soc_info->src_clk_idx], clk_rate);
+}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
index ed8bb6e..8e5a38a 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.h
@@ -25,4 +25,7 @@
 int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info);
 
 int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info);
+
+int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info,
+	uint32_t clk_rate);
 #endif /* CAM_IPE_SOC_H */
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 1fbc105..03c5eb3 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
@@ -656,8 +656,20 @@
 	case CAM_FORMAT_UBWC_NV12:
 	case CAM_FORMAT_UBWC_NV12_4R:
 		return PACKER_FMT_PLAIN_8_LSB_MSB_10;
+	case CAM_FORMAT_PLAIN16_16:
+		return PACKER_FMT_PLAIN_16_16BPP;
 	case CAM_FORMAT_PLAIN64:
 		return PACKER_FMT_PLAIN_64;
+	case CAM_FORMAT_PLAIN8:
+		return PACKER_FMT_PLAIN_8;
+	case CAM_FORMAT_PLAIN16_10:
+		return PACKER_FMT_PLAIN_16_10BPP;
+	case CAM_FORMAT_PLAIN16_12:
+		return PACKER_FMT_PLAIN_16_12BPP;
+	case CAM_FORMAT_PLAIN16_14:
+		return PACKER_FMT_PLAIN_16_14BPP;
+	case CAM_FORMAT_PLAIN32_20:
+		return PACKER_FMT_PLAIN_32_20BPP;
 	case CAM_FORMAT_MIPI_RAW_6:
 	case CAM_FORMAT_MIPI_RAW_8:
 	case CAM_FORMAT_MIPI_RAW_10:
@@ -665,14 +677,8 @@
 	case CAM_FORMAT_MIPI_RAW_14:
 	case CAM_FORMAT_MIPI_RAW_16:
 	case CAM_FORMAT_MIPI_RAW_20:
-	case CAM_FORMAT_PLAIN128:
-	case CAM_FORMAT_PLAIN8:
 	case CAM_FORMAT_PLAIN16_8:
-	case CAM_FORMAT_PLAIN16_10:
-	case CAM_FORMAT_PLAIN16_12:
-	case CAM_FORMAT_PLAIN16_14:
-	case CAM_FORMAT_PLAIN16_16:
-	case CAM_FORMAT_PLAIN32_20:
+	case CAM_FORMAT_PLAIN128:
 	case CAM_FORMAT_PD8:
 	case CAM_FORMAT_PD10:
 		return PACKER_FMT_PLAIN_128;
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 6a148ca..96d5b6e 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
@@ -575,7 +575,6 @@
 			slot->status = CRM_SLOT_STATUS_REQ_APPLIED;
 			link->trigger_mask = 0;
 			CAM_DBG(CAM_CRM, "req is applied\n");
-			__cam_req_mgr_check_next_req_slot(in_q);
 
 			idx = in_q->rd_idx;
 			__cam_req_mgr_dec_idx(
@@ -1370,7 +1369,11 @@
 		/*
 		 * Do NOT reset req q slot data here, it can not be done
 		 * here because we need to preserve the data to handle bubble.
+		 *
+		 * Check if any new req is pending in slot, if not finish the
+		 * lower pipeline delay device with available req ids.
 		 */
+		__cam_req_mgr_check_next_req_slot(in_q);
 		__cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots);
 	}
 	rc = __cam_req_mgr_process_req(link, trigger_data->trigger);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
index b36fc68..bcf4133 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -16,6 +16,70 @@
 #include "cam_sensor_util.h"
 #include "cam_trace.h"
 
+static int32_t cam_actuator_i2c_modes_util(
+	struct camera_io_master *io_master_info,
+	struct i2c_settings_list *i2c_list)
+{
+	int32_t rc = 0;
+	uint32_t i, size;
+
+	if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) {
+		rc = camera_io_dev_write(io_master_info,
+			&(i2c_list->i2c_settings));
+		if (rc < 0) {
+			CAM_ERR(CAM_ACTUATOR,
+				"Failed to random write I2C settings: %d",
+				rc);
+			return rc;
+		}
+	} else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) {
+		rc = camera_io_dev_write_continuous(
+			io_master_info,
+			&(i2c_list->i2c_settings),
+			0);
+		if (rc < 0) {
+			CAM_ERR(CAM_ACTUATOR,
+				"Failed to seq write I2C settings: %d",
+				rc);
+			return rc;
+			}
+	} else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_BURST) {
+		rc = camera_io_dev_write_continuous(
+			io_master_info,
+			&(i2c_list->i2c_settings),
+			1);
+		if (rc < 0) {
+			CAM_ERR(CAM_ACTUATOR,
+				"Failed to burst write I2C settings: %d",
+				rc);
+			return rc;
+		}
+	} else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) {
+		size = i2c_list->i2c_settings.size;
+		for (i = 0; i < size; i++) {
+			rc = camera_io_dev_poll(
+			io_master_info,
+			i2c_list->i2c_settings.
+				reg_setting[i].reg_addr,
+			i2c_list->i2c_settings.
+				reg_setting[i].reg_data,
+			i2c_list->i2c_settings.
+				reg_setting[i].data_mask,
+			i2c_list->i2c_settings.addr_type,
+				i2c_list->i2c_settings.data_type,
+			i2c_list->i2c_settings.
+				reg_setting[i].delay);
+			if (rc < 0) {
+				CAM_ERR(CAM_ACTUATOR,
+					"i2c poll apply setting Fail: %d", rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
 int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl,
 	uint32_t *cmd_buf)
 {
@@ -52,7 +116,6 @@
 {
 	struct i2c_settings_list *i2c_list;
 	int32_t rc = 0;
-	uint32_t i, size;
 
 	if (a_ctrl == NULL || i2c_set == NULL) {
 		CAM_ERR(CAM_ACTUATOR, "Invalid Args");
@@ -66,35 +129,14 @@
 
 	list_for_each_entry(i2c_list,
 		&(i2c_set->list_head), list) {
-		if (i2c_list->op_code ==  CAM_SENSOR_I2C_WRITE_RANDOM) {
-			rc = camera_io_dev_write(&(a_ctrl->io_master_info),
-				&(i2c_list->i2c_settings));
-			if (rc < 0) {
-				CAM_ERR(CAM_ACTUATOR,
-					"Failed in Applying i2c wrt settings");
-				return rc;
-			}
-		} else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) {
-			size = i2c_list->i2c_settings.size;
-			for (i = 0; i < size; i++) {
-				rc = camera_io_dev_poll(
-					&(a_ctrl->io_master_info),
-					i2c_list->i2c_settings.
-						reg_setting[i].reg_addr,
-					i2c_list->i2c_settings.
-						reg_setting[i].reg_data,
-					i2c_list->i2c_settings.
-						reg_setting[i].data_mask,
-					i2c_list->i2c_settings.addr_type,
-					i2c_list->i2c_settings.data_type,
-					i2c_list->i2c_settings.
-						reg_setting[i].delay);
-				if (rc < 0) {
-					CAM_ERR(CAM_ACTUATOR,
-						"i2c poll apply setting Fail");
-					return rc;
-				}
-			}
+		rc = cam_actuator_i2c_modes_util(
+			&(a_ctrl->io_master_info),
+			i2c_list);
+		if (rc < 0) {
+			CAM_ERR(CAM_ACTUATOR,
+				"Failed to apply settings: %d",
+				rc);
+			return rc;
 		}
 	}
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
index 975b301..c62b251 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -424,7 +424,8 @@
 	msg = &c_ctrl->cfg.cci_i2c_write_cfg;
 	*pack = 0;
 
-	if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) {
+	if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ ||
+		c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) {
 		addr_len = cam_cci_convert_type_to_num_bytes(msg->addr_type);
 		len = (size + addr_len) <= (cci_dev->payload_size) ?
 			(size + addr_len):cci_dev->payload_size;
@@ -725,24 +726,29 @@
 		do {
 			if (i2c_msg->data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
 				data[i++] = i2c_cmd->reg_data;
-				reg_addr++;
+				if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ)
+					reg_addr++;
 			} else {
 				if ((i + 1) <= cci_dev->payload_size) {
 					data[i++] = (i2c_cmd->reg_data &
 						0xFF00) >> 8; /* MSB */
 					data[i++] = i2c_cmd->reg_data &
 						0x00FF; /* LSB */
-					reg_addr++;
+					if (c_ctrl->cmd ==
+						MSM_CCI_I2C_WRITE_SEQ)
+						reg_addr++;
 				} else
 					break;
 			}
 			i2c_cmd++;
 			--cmd_size;
-		} while (((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) || pack--) &&
+		} while (((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ ||
+			c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) || pack--) &&
 				(cmd_size > 0) && (i <= cci_dev->payload_size));
 		free_size = cam_cci_get_queue_free_size(cci_dev, master,
 				queue);
-		if ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) &&
+		if ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ ||
+			c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) &&
 			((i-1) == MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) &&
 			cci_dev->support_seq_write && cmd_size > 0 &&
 			free_size > BURST_MIN_FREE_SIZE) {
@@ -1205,10 +1211,8 @@
 	rc = cam_cci_soc_release(cci_dev);
 	if (rc < 0) {
 		CAM_ERR(CAM_CCI, "Failed in releasing the cci: %d", rc);
-		cam_cpas_stop(cci_dev->cpas_handle);
 		return rc;
 	}
-	cam_cpas_stop(cci_dev->cpas_handle);
 
 	return rc;
 }
@@ -1253,6 +1257,7 @@
 		break;
 	case MSM_CCI_I2C_WRITE:
 	case MSM_CCI_I2C_WRITE_SEQ:
+	case MSM_CCI_I2C_WRITE_BURST:
 		for (i = 0; i < NUM_QUEUES; i++) {
 			if (mutex_trylock(&cci_master_info->mutex_q[i])) {
 				rc = cam_cci_i2c_write(sd, c_ctrl, i,
@@ -1295,6 +1300,7 @@
 		break;
 	case MSM_CCI_I2C_WRITE:
 	case MSM_CCI_I2C_WRITE_SEQ:
+	case MSM_CCI_I2C_WRITE_BURST:
 	case MSM_CCI_I2C_WRITE_SYNC:
 	case MSM_CCI_I2C_WRITE_ASYNC:
 	case MSM_CCI_I2C_WRITE_SYNC_BLOCK:
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
index cb01c6c..4c996e08 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h
@@ -95,6 +95,7 @@
 	MSM_CCI_I2C_READ,
 	MSM_CCI_I2C_WRITE,
 	MSM_CCI_I2C_WRITE_SEQ,
+	MSM_CCI_I2C_WRITE_BURST,
 	MSM_CCI_I2C_WRITE_ASYNC,
 	MSM_CCI_GPIO_WRITE,
 	MSM_CCI_I2C_WRITE_SYNC,
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
index 83cb49e3..8de4472 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_soc.c
@@ -392,5 +392,7 @@
 	cci_dev->cycles_per_us = 0;
 	soc_info->src_clk_idx = 0;
 
+	cam_cpas_stop(cci_dev->cpas_handle);
+
 	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 5c64451..0aaf8b0c 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
@@ -67,7 +67,7 @@
 	}
 
 	soc_private = (struct cam_flash_private_soc *)
-		&flash_ctrl->soc_info.soc_private;
+		flash_ctrl->soc_info.soc_private;
 
 	if (op == CAMERA_SENSOR_FLASH_OP_FIRELOW) {
 		for (i = 0; i < flash_ctrl->torch_num_sources; i++) {
@@ -349,7 +349,7 @@
 		} else if ((flash_data->opcode ==
 			CAMERA_SENSOR_FLASH_OP_FIRELOW) &&
 			(flash_data->cmn_attr.is_settings_valid)) {
-			/* Turn Off Flash */
+			/* Turn On Torch */
 			if (fctrl->flash_state == CAM_FLASH_STATE_INIT) {
 				rc = cam_flash_low(fctrl, flash_data);
 				if (rc) {
@@ -427,7 +427,15 @@
 		return rc;
 	}
 
-	csl_packet = (struct cam_packet *)generic_ptr;
+	if (config.offset > len_of_buffer) {
+		CAM_ERR(CAM_FLASH,
+			"offset is out of bounds: offset: %lld len: %zu",
+			config.offset, len_of_buffer);
+		return -EINVAL;
+	}
+
+	/* Add offset to the flash csl header */
+	csl_packet = (struct cam_packet *)(generic_ptr + config.offset);
 
 	switch (csl_packet->header.op_code & 0xFFFFFF) {
 	case CAM_FLASH_PACKET_OPCODE_INIT: {
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 75205f9..edbb335 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
@@ -127,6 +127,70 @@
 	return rc;
 }
 
+static int32_t cam_sensor_i2c_modes_util(
+	struct camera_io_master *io_master_info,
+	struct i2c_settings_list *i2c_list)
+{
+	int32_t rc = 0;
+	uint32_t i, size;
+
+	if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) {
+		rc = camera_io_dev_write(io_master_info,
+			&(i2c_list->i2c_settings));
+		if (rc < 0) {
+			CAM_ERR(CAM_SENSOR,
+				"Failed to random write I2C settings: %d",
+				rc);
+			return rc;
+		}
+	} else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) {
+		rc = camera_io_dev_write_continuous(
+			io_master_info,
+			&(i2c_list->i2c_settings),
+			0);
+		if (rc < 0) {
+			CAM_ERR(CAM_SENSOR,
+				"Failed to seq write I2C settings: %d",
+				rc);
+			return rc;
+		}
+	} else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_BURST) {
+		rc = camera_io_dev_write_continuous(
+			io_master_info,
+			&(i2c_list->i2c_settings),
+			1);
+		if (rc < 0) {
+			CAM_ERR(CAM_SENSOR,
+				"Failed to burst write I2C settings: %d",
+				rc);
+			return rc;
+		}
+	} else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) {
+		size = i2c_list->i2c_settings.size;
+		for (i = 0; i < size; i++) {
+			rc = camera_io_dev_poll(
+			io_master_info,
+			i2c_list->i2c_settings.
+				reg_setting[i].reg_addr,
+			i2c_list->i2c_settings.
+				reg_setting[i].reg_data,
+			i2c_list->i2c_settings.
+				reg_setting[i].data_mask,
+			i2c_list->i2c_settings.addr_type,
+				i2c_list->i2c_settings.data_type,
+			i2c_list->i2c_settings.
+				reg_setting[i].delay);
+			if (rc < 0) {
+				CAM_ERR(CAM_SENSOR,
+					"i2c poll apply setting Fail: %d", rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
 int32_t cam_sensor_update_i2c_info(struct cam_cmd_i2c_info *i2c_info,
 	struct cam_sensor_ctrl_t *s_ctrl)
 {
@@ -715,12 +779,13 @@
 		if (i2c_set->is_settings_valid == 1) {
 			list_for_each_entry(i2c_list,
 				&(i2c_set->list_head), list) {
-				rc = camera_io_dev_write(
+				rc = cam_sensor_i2c_modes_util(
 					&(s_ctrl->io_master_info),
-					&(i2c_list->i2c_settings));
+					i2c_list);
 				if (rc < 0) {
 					CAM_ERR(CAM_SENSOR,
-					"Failed to write the I2C settings");
+						"Failed to apply settings: %d",
+						rc);
 					return rc;
 				}
 			}
@@ -738,13 +803,13 @@
 			i2c_set->request_id == req_id) {
 			list_for_each_entry(i2c_list,
 				&(i2c_set->list_head), list) {
-				rc = camera_io_dev_write(
+				rc = cam_sensor_i2c_modes_util(
 					&(s_ctrl->io_master_info),
-					&(i2c_list->i2c_settings));
+					i2c_list);
 				if (rc < 0) {
 					CAM_ERR(CAM_SENSOR,
-					"Fail to write the I2C settings: %d",
-						 rc);
+						"Failed to apply settings: %d",
+						rc);
 					return rc;
 				}
 			}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
index ca648f01..3257703 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
@@ -145,6 +145,23 @@
 		MSM_CCI_I2C_WRITE);
 }
 
+int32_t cam_cci_i2c_write_continuous_table(
+	struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_setting,
+	uint8_t cam_sensor_i2c_write_flag)
+{
+	int32_t rc = 0;
+
+	if (cam_sensor_i2c_write_flag == 1)
+		rc = cam_cci_i2c_write_table_cmd(client, write_setting,
+			MSM_CCI_I2C_WRITE_BURST);
+	else if (cam_sensor_i2c_write_flag == 0)
+		rc = cam_cci_i2c_write_table_cmd(client, write_setting,
+			MSM_CCI_I2C_WRITE_SEQ);
+
+	return rc;
+}
+
 static int32_t cam_cci_i2c_compare(struct cam_sensor_cci_client *client,
 	uint32_t addr, uint16_t data, uint16_t data_mask,
 	enum camera_sensor_i2c_type data_type,
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h
index 6207a8a..10b07ec 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h
@@ -57,7 +57,7 @@
 
 /**
  * @client: CCI client structure
- * @cci_cmd: CCI command type
+ * @write_setting: I2C register setting
  *
  * This API handles CCI random write
  */
@@ -66,6 +66,18 @@
 	struct cam_sensor_i2c_reg_setting *write_setting);
 
 /**
+ * @client: CCI client structure
+ * @write_setting: I2C register setting
+ * @cam_sensor_i2c_write_flag: burst or seq write
+ *
+ * This API handles CCI continuous write
+ */
+int32_t cam_cci_i2c_write_continuous_table(
+	struct camera_io_master *client,
+	struct cam_sensor_i2c_reg_setting *write_setting,
+	uint8_t cam_sensor_i2c_write_flag);
+
+/**
  * @cci_client: CCI client structure
  * @cci_cmd: CCI command type
  *
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index f0142e7..c9cf088 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -114,6 +114,33 @@
 	}
 }
 
+int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info,
+	struct cam_sensor_i2c_reg_setting *write_setting,
+	uint8_t cam_sensor_i2c_write_flag)
+{
+	if (!write_setting || !io_master_info) {
+		CAM_ERR(CAM_SENSOR,
+			"Input parameters not valid ws: %pK ioinfo: %pK",
+			write_setting, io_master_info);
+		return -EINVAL;
+	}
+
+	if (io_master_info->master_type == CCI_MASTER) {
+		return cam_cci_i2c_write_continuous_table(io_master_info,
+			write_setting, cam_sensor_i2c_write_flag);
+	} else if (io_master_info->master_type == I2C_MASTER) {
+		return cam_qup_i2c_write_table(io_master_info,
+			write_setting);
+	} else if (io_master_info->master_type == SPI_MASTER) {
+		return cam_spi_write_table(io_master_info,
+			write_setting);
+	} else {
+		CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
+			io_master_info->master_type);
+		return -EINVAL;
+	}
+}
+
 int32_t camera_io_init(struct camera_io_master *io_master_info)
 {
 	if (!io_master_info) {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
index 9a60fd0e..f6620c0 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
@@ -87,6 +87,18 @@
 
 /**
  * @io_master_info: I2C/SPI master information
+ * @write_setting: write settings information
+ * @cam_sensor_i2c_write_flag: differentiate between burst & seq
+ *
+ * This API abstracts write functionality based on master type and
+ * write flag for continuous write
+ */
+int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info,
+	struct cam_sensor_i2c_reg_setting *write_setting,
+	uint8_t cam_sensor_i2c_write_flag);
+
+/**
+ * @io_master_info: I2C/SPI master information
  * @addr: I2C address
  * @data: I2C data
  * @data_mask: I2C data mask
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
index 6520042b..6ebd58b 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -204,6 +204,8 @@
 
 enum cam_sensor_i2c_cmd_type {
 	CAM_SENSOR_I2C_WRITE_RANDOM,
+	CAM_SENSOR_I2C_WRITE_BURST,
+	CAM_SENSOR_I2C_WRITE_SEQ,
 	CAM_SENSOR_I2C_READ,
 	CAM_SENSOR_I2C_POLL
 };
@@ -224,14 +226,6 @@
 	enum camera_vreg_type type;
 };
 
-struct cam_sensor_module_power_setting {
-	enum msm_camera_power_seq_type seq_type;
-	unsigned short seq_val;
-	uint32_t config_val_low;
-	uint32_t config_val_high;
-	unsigned short delay;
-};
-
 struct msm_camera_gpio_num_info {
 	uint16_t gpio_num[SENSOR_SEQ_TYPE_MAX];
 	uint8_t valid[SENSOR_SEQ_TYPE_MAX];
@@ -333,26 +327,6 @@
 	void *data[10];
 };
 
-struct cam_sensor_power_setting_array {
-	struct cam_sensor_power_setting  power_setting_a[MAX_POWER_CONFIG];
-	struct cam_sensor_power_setting *power_setting;
-	unsigned short size;
-	struct cam_sensor_power_setting  power_down_setting_a[MAX_POWER_CONFIG];
-	struct cam_sensor_power_setting *power_down_setting;
-	unsigned short size_down;
-};
-
-struct msm_camera_sensor_slave_info {
-	enum msm_sensor_camera_id_t camera_id;
-	unsigned short slave_addr;
-	enum i2c_freq_mode i2c_freq_mode;
-	enum camera_sensor_i2c_type addr_type;
-	struct msm_sensor_id_info_t sensor_id_info;
-	struct cam_sensor_power_setting_array power_setting_array;
-	unsigned char  is_init_params_valid;
-	enum msm_sensor_output_format_t output_format;
-};
-
 struct cam_sensor_board_info {
 	struct cam_camera_slave_info slave_info;
 	int32_t sensor_mount_angle;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index 878ce73..f5df775 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -82,7 +82,7 @@
 		(struct cam_cmd_unconditional_wait *) *cmd_buf;
 	struct i2c_settings_list *i2c_list = NULL;
 
-	if (i2c_list == NULL) {
+	if (list_ptr == NULL) {
 		CAM_ERR(CAM_SENSOR, "Invalid list ptr");
 		return -EINVAL;
 	}
@@ -196,6 +196,49 @@
 	return rc;
 }
 
+static int32_t cam_sensor_handle_continuous_write(
+	struct cam_cmd_i2c_continuous_wr *cam_cmd_i2c_continuous_wr,
+	struct i2c_settings_array *i2c_reg_settings,
+	uint16_t *cmd_length_in_bytes, int32_t *offset,
+	struct list_head **list)
+{
+	struct i2c_settings_list *i2c_list;
+	int32_t rc = 0, cnt;
+
+	i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings,
+		cam_cmd_i2c_continuous_wr->header.count);
+	if (i2c_list == NULL ||
+		i2c_list->i2c_settings.reg_setting == NULL) {
+		CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list");
+		return -ENOMEM;
+	}
+
+	*cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) +
+		sizeof(cam_cmd_i2c_continuous_wr->reg_addr) +
+		sizeof(struct cam_cmd_read) *
+		(cam_cmd_i2c_continuous_wr->header.count));
+	i2c_list->op_code = cam_cmd_i2c_continuous_wr->header.op_code;
+	i2c_list->i2c_settings.addr_type =
+		cam_cmd_i2c_continuous_wr->header.addr_type;
+
+	for (cnt = 0; cnt < (cam_cmd_i2c_continuous_wr->header.count);
+		cnt++) {
+		i2c_list->i2c_settings.reg_setting[cnt].reg_addr =
+			cam_cmd_i2c_continuous_wr->
+			reg_addr;
+		i2c_list->i2c_settings.
+			reg_setting[cnt].reg_data =
+			cam_cmd_i2c_continuous_wr->
+			data_read[cnt].reg_data;
+		i2c_list->i2c_settings.
+			reg_setting[cnt].data_mask = 0;
+	}
+	(*offset) += cnt;
+	*list = &(i2c_list->list);
+
+	return rc;
+}
+
 /**
  * Name : cam_sensor_i2c_pkt_parser
  * Description : Parse CSL CCI packet and apply register settings
@@ -260,7 +303,29 @@
 					&cmd_length_in_bytes, &j, &list);
 				if (rc < 0) {
 					CAM_ERR(CAM_SENSOR,
-						"Failed in random read %d", rc);
+					"Failed in random write %d", rc);
+					return rc;
+				}
+
+				cmd_buf += cmd_length_in_bytes /
+					sizeof(uint32_t);
+				byte_cnt += cmd_length_in_bytes;
+				break;
+			}
+			case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR: {
+				uint16_t cmd_length_in_bytes   = 0;
+				struct cam_cmd_i2c_continuous_wr
+				*cam_cmd_i2c_continuous_wr =
+				(struct cam_cmd_i2c_continuous_wr *)
+				cmd_buf;
+
+				rc = cam_sensor_handle_continuous_write(
+					cam_cmd_i2c_continuous_wr,
+					i2c_reg_settings,
+					&cmd_length_in_bytes, &j, &list);
+				if (rc < 0) {
+					CAM_ERR(CAM_SENSOR,
+					"Failed in continuous write %d", rc);
 					return rc;
 				}
 
@@ -1242,16 +1307,13 @@
 				CAM_ERR(CAM_SENSOR, "request gpio failed");
 				return no_gpio;
 			}
-			if (power_setting->seq_val >= CAM_VREG_MAX ||
-				!gpio_num_info) {
-				CAM_ERR(CAM_SENSOR, "gpio index %d >= max %d",
-					power_setting->seq_val,
-					CAM_VREG_MAX);
+			if (!gpio_num_info) {
+				CAM_ERR(CAM_SENSOR, "Invalid gpio_num_info");
 				goto power_up_failed;
 			}
 			CAM_DBG(CAM_SENSOR, "gpio set val %d",
 				gpio_num_info->gpio_num
-				[power_setting->seq_val]);
+				[power_setting->seq_type]);
 
 			rc = msm_cam_sensor_handle_reg_gpio(
 				power_setting->seq_type,
@@ -1349,11 +1411,11 @@
 			if (!gpio_num_info)
 				continue;
 			if (!gpio_num_info->valid
-				[power_setting->seq_val])
+				[power_setting->seq_type])
 				continue;
 			gpio_set_value_cansleep(
 				gpio_num_info->gpio_num
-				[power_setting->seq_val], GPIOF_OUT_INIT_LOW);
+				[power_setting->seq_type], GPIOF_OUT_INIT_LOW);
 			break;
 		case SENSOR_VANA:
 		case SENSOR_VDIG:
@@ -1519,12 +1581,12 @@
 		case SENSOR_CUSTOM_GPIO1:
 		case SENSOR_CUSTOM_GPIO2:
 
-			if (!gpio_num_info->valid[pd->seq_val])
+			if (!gpio_num_info->valid[pd->seq_type])
 				continue;
 
 			gpio_set_value_cansleep(
 				gpio_num_info->gpio_num
-				[pd->seq_val],
+				[pd->seq_type],
 				(int) pd->config_val);
 
 			break;
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 56e7a99..cb03576 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -581,6 +581,13 @@
 
 		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
 		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto err_invalid_fmt;
+		}
+
 		msm_comm_set_color_format(inst,
 				msm_comm_get_hal_output_buffer(inst),
 				f->fmt.pix_mp.pixelformat);
@@ -648,6 +655,12 @@
 		}
 		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
 		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto err_invalid_fmt;
+		}
 
 		frame_sz.buffer_type = HAL_BUFFER_INPUT;
 		frame_sz.width = inst->prop.width[OUTPUT_PORT];
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index dfb2ad5..0d8cb76 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2385,6 +2385,12 @@
 
 		inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
 		inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto exit;
+		}
 
 		frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
 		frame_sz.width = inst->prop.width[CAPTURE_PORT];
@@ -2443,6 +2449,12 @@
 
 		inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
 		inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
+		rc = msm_vidc_check_session_supported(inst);
+		if (rc) {
+			dprintk(VIDC_ERR,
+				"%s: session not supported\n", __func__);
+			goto exit;
+		}
 
 		frame_sz.buffer_type = HAL_BUFFER_INPUT;
 		frame_sz.width = inst->prop.width[OUTPUT_PORT];
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 6a7588c..5149086 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -883,6 +883,13 @@
 		goto fail_start;
 	}
 
+	rc = msm_vidc_check_scaling_supported(inst);
+	if (rc) {
+		dprintk(VIDC_ERR,
+			"This session scaling is not supported %pK\n", inst);
+		goto fail_start;
+	}
+
 	/* Decide work mode for current session */
 	rc = msm_vidc_decide_work_mode(inst);
 	if (rc) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 428bf71..6e29c53 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2161,6 +2161,7 @@
 				"Got SYS_ERR but unable to identify core\n");
 		return;
 	}
+	hdev = core->device;
 
 	mutex_lock(&core->lock);
 	if (core->state == VIDC_CORE_UNINIT) {
@@ -2181,7 +2182,6 @@
 		msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR);
 		msm_comm_print_inst_info(inst);
 	}
-	hdev = core->device;
 	dprintk(VIDC_DBG, "Calling core_release\n");
 	rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data);
 	if (rc) {
@@ -3011,6 +3011,23 @@
 	return msm_vidc_deinit_core(inst);
 }
 
+static int msm_comm_session_init_done(int flipped_state,
+	struct msm_vidc_inst *inst)
+{
+	int rc;
+
+	dprintk(VIDC_DBG, "inst %pK: waiting for session init done\n", inst);
+	rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+			HAL_SESSION_INIT_DONE);
+	if (rc) {
+		dprintk(VIDC_ERR, "Session init failed for inst %pK\n", inst);
+		msm_comm_generate_sys_error(inst);
+		return rc;
+	}
+
+	return rc;
+}
+
 static int msm_comm_session_init(int flipped_state,
 	struct msm_vidc_inst *inst)
 {
@@ -3693,8 +3710,7 @@
 		if (rc || state <= get_flipped_state(inst->state, state))
 			break;
 	case MSM_VIDC_OPEN_DONE:
-		rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
-			HAL_SESSION_INIT_DONE);
+		rc = msm_comm_session_init_done(flipped_state, inst);
 		if (rc || state <= get_flipped_state(inst->state, state))
 			break;
 	case MSM_VIDC_LOAD_RESOURCES:
@@ -5472,10 +5488,6 @@
 			capability->width.max, capability->height.max);
 			rc = -ENOTSUPP;
 		}
-
-		if (!rc && msm_vidc_check_scaling_supported(inst)) {
-			rc = -ENOTSUPP;
-		}
 	}
 	if (rc) {
 		dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index c94da61..dde6029 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1047,9 +1047,9 @@
 
 	mutex_lock(&device->lock);
 
-	if (device->power_enabled) {
-		dprintk(VIDC_DBG, "Venus is busy\n");
-		rc = -EBUSY;
+	if (!device->power_enabled) {
+		dprintk(VIDC_WARN, "%s: venus power off\n", __func__);
+		rc = -EINVAL;
 		goto exit;
 	}
 	__flush_debug_queue(device, NULL);
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index b3c9cbe..5626908 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -5186,7 +5186,9 @@
 	    skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
 	    skb->inner_protocol != htons(ETH_P_TEB) ||
 	    skb_inner_mac_header(skb) - skb_transport_header(skb) !=
-	    sizeof(struct udphdr) + sizeof(struct vxlanhdr))
+		sizeof(struct udphdr) + sizeof(struct vxlanhdr) ||
+	    !adapter->vxlan_port ||
+	    udp_hdr(skb)->dest != adapter->vxlan_port)
 		return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
 
 	return features;
diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c
index 2a9dd46..e1f9e7c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/icm.c
+++ b/drivers/net/ethernet/mellanox/mlx4/icm.c
@@ -118,8 +118,13 @@
 	if (!buf)
 		return -ENOMEM;
 
+	if (offset_in_page(buf)) {
+		dma_free_coherent(dev, PAGE_SIZE << order,
+				  buf, sg_dma_address(mem));
+		return -ENOMEM;
+	}
+
 	sg_set_buf(mem, buf, PAGE_SIZE << order);
-	BUG_ON(mem->offset);
 	sg_dma_len(mem) = PAGE_SIZE << order;
 	return 0;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index b2ca8a6..551786f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -42,6 +42,7 @@
 #include <linux/io-mapping.h>
 #include <linux/delay.h>
 #include <linux/kmod.h>
+#include <linux/etherdevice.h>
 #include <net/devlink.h>
 
 #include <linux/mlx4/device.h>
@@ -782,6 +783,23 @@
 }
 EXPORT_SYMBOL(mlx4_is_slave_active);
 
+void mlx4_handle_eth_header_mcast_prio(struct mlx4_net_trans_rule_hw_ctrl *ctrl,
+				       struct _rule_hw *eth_header)
+{
+	if (is_multicast_ether_addr(eth_header->eth.dst_mac) ||
+	    is_broadcast_ether_addr(eth_header->eth.dst_mac)) {
+		struct mlx4_net_trans_rule_hw_eth *eth =
+			(struct mlx4_net_trans_rule_hw_eth *)eth_header;
+		struct _rule_hw *next_rule = (struct _rule_hw *)(eth + 1);
+		bool last_rule = next_rule->size == 0 && next_rule->id == 0 &&
+			next_rule->rsvd == 0;
+
+		if (last_rule)
+			ctrl->prio = cpu_to_be16(MLX4_DOMAIN_NIC);
+	}
+}
+EXPORT_SYMBOL(mlx4_handle_eth_header_mcast_prio);
+
 static void slave_adjust_steering_mode(struct mlx4_dev *dev,
 				       struct mlx4_dev_cap *dev_cap,
 				       struct mlx4_init_hca_param *hca_param)
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 32f76bf..1822382 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -4165,22 +4165,6 @@
 	return 0;
 }
 
-static void handle_eth_header_mcast_prio(struct mlx4_net_trans_rule_hw_ctrl *ctrl,
-					 struct _rule_hw *eth_header)
-{
-	if (is_multicast_ether_addr(eth_header->eth.dst_mac) ||
-	    is_broadcast_ether_addr(eth_header->eth.dst_mac)) {
-		struct mlx4_net_trans_rule_hw_eth *eth =
-			(struct mlx4_net_trans_rule_hw_eth *)eth_header;
-		struct _rule_hw *next_rule = (struct _rule_hw *)(eth + 1);
-		bool last_rule = next_rule->size == 0 && next_rule->id == 0 &&
-			next_rule->rsvd == 0;
-
-		if (last_rule)
-			ctrl->prio = cpu_to_be16(MLX4_DOMAIN_NIC);
-	}
-}
-
 /*
  * In case of missing eth header, append eth header with a MAC address
  * assigned to the VF.
@@ -4364,10 +4348,7 @@
 	header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id));
 
 	if (header_id == MLX4_NET_TRANS_RULE_ID_ETH)
-		handle_eth_header_mcast_prio(ctrl, rule_header);
-
-	if (slave == dev->caps.function)
-		goto execute;
+		mlx4_handle_eth_header_mcast_prio(ctrl, rule_header);
 
 	switch (header_id) {
 	case MLX4_NET_TRANS_RULE_ID_ETH:
@@ -4395,7 +4376,6 @@
 		goto err_put_qp;
 	}
 
-execute:
 	err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
 			   vhcr->in_modifier, 0,
 			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
@@ -4474,6 +4454,7 @@
 	struct res_qp *rqp;
 	struct res_fs_rule *rrule;
 	u64 mirr_reg_id;
+	int qpn;
 
 	if (dev->caps.steering_mode !=
 	    MLX4_STEERING_MODE_DEVICE_MANAGED)
@@ -4490,10 +4471,11 @@
 	}
 	mirr_reg_id = rrule->mirr_rule_id;
 	kfree(rrule->mirr_mbox);
+	qpn = rrule->qpn;
 
 	/* Release the rule form busy state before removal */
 	put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
-	err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp);
+	err = get_res(dev, slave, qpn, RES_QP, &rqp);
 	if (err)
 		return err;
 
@@ -4518,7 +4500,7 @@
 	if (!err)
 		atomic_dec(&rqp->ref_count);
 out:
-	put_res(dev, slave, rrule->qpn, RES_QP);
+	put_res(dev, slave, qpn, RES_QP);
 	return err;
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index b08b9e2..6ffd5d2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -672,6 +672,12 @@
 		if (err)
 			goto err_reps;
 	}
+
+	/* disable PF RoCE so missed packets don't go through RoCE steering */
+	mlx5_dev_list_lock();
+	mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+	mlx5_dev_list_unlock();
+
 	return 0;
 
 err_reps:
@@ -695,6 +701,11 @@
 {
 	int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
 
+	/* enable back PF RoCE */
+	mlx5_dev_list_lock();
+	mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+	mlx5_dev_list_unlock();
+
 	mlx5_eswitch_disable_sriov(esw);
 	err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
 	if (err) {
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index bf000d8..2c4350a 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -326,6 +326,7 @@
 static const struct pci_device_id rtl8169_pci_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8129), 0, 0, RTL_CFG_0 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8136), 0, 0, RTL_CFG_2 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8161), 0, 0, RTL_CFG_1 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8167), 0, 0, RTL_CFG_0 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8168), 0, 0, RTL_CFG_1 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	0x8169), 0, 0, RTL_CFG_0 },
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index a2d218b..12be259 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -819,6 +819,7 @@
 	.tsu		= 1,
 	.hw_crc		= 1,
 	.select_mii	= 1,
+	.shift_rd0	= 1,
 };
 
 /* SH7763 */
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 32b555a..9e7b783 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1792,7 +1792,7 @@
 	.phy_id		= 0xffffffff,
 	.phy_id_mask	= 0xffffffff,
 	.name		= "Generic PHY",
-	.soft_reset	= genphy_soft_reset,
+	.soft_reset	= genphy_no_soft_reset,
 	.config_init	= genphy_config_init,
 	.features	= PHY_GBIT_FEATURES | SUPPORTED_MII |
 			  SUPPORTED_AUI | SUPPORTED_FIBRE |
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index dc7b639..50737de 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -1369,6 +1369,7 @@
 	.probe =	usbnet_probe,
 	.suspend =	asix_suspend,
 	.resume =	asix_resume,
+	.reset_resume =	asix_resume,
 	.disconnect =	usbnet_disconnect,
 	.supports_autosuspend = 1,
 	.disable_hub_initiated_lpm = 1,
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
index c9a8bb1..c7956e1 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -660,6 +660,9 @@
 	struct sk_buff *skb;
 	u32 cmd_id;
 
+	if (!ar->wmi.ops->gen_vdev_spectral_conf)
+		return -EOPNOTSUPP;
+
 	skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg);
 	if (IS_ERR(skb))
 		return PTR_ERR(skb);
@@ -675,6 +678,9 @@
 	struct sk_buff *skb;
 	u32 cmd_id;
 
+	if (!ar->wmi.ops->gen_vdev_spectral_enable)
+		return -EOPNOTSUPP;
+
 	skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger,
 						    enable);
 	if (IS_ERR(skb))
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 60ea0ec..45a8081 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -20,7 +20,6 @@
 #include <linux/pci.h>
 #include <linux/rtnetlink.h>
 #include <linux/power_supply.h>
-
 #include "wil6210.h"
 #include "wmi.h"
 #include "txrx.h"
@@ -30,7 +29,6 @@
 static u32 mem_addr;
 static u32 dbg_txdesc_index;
 static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
-u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */
 
 enum dbg_off_type {
 	doff_u32 = 0,
@@ -1768,6 +1766,7 @@
 	WIL_FIELD(chip_revision, 0444,	doff_u8),
 	WIL_FIELD(abft_len, 0644,		doff_u8),
 	WIL_FIELD(wakeup_trigger, 0644,		doff_u8),
+	WIL_FIELD(vring_idle_trsh, 0644,	doff_u32),
 	{},
 };
 
@@ -1783,8 +1782,6 @@
 	{"desc_index",	0644, (ulong)&dbg_txdesc_index, doff_u32},
 	{"vring_index",	0644, (ulong)&dbg_vring_index, doff_u32},
 	{"mem_addr",	0644, (ulong)&mem_addr, doff_u32},
-	{"vring_idle_trsh", 0644, (ulong)&vring_idle_trsh,
-	 doff_u32},
 	{"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
 	{},
 };
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 409b8cb..d90fe1c 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -584,6 +584,7 @@
 			      WMI_WAKEUP_TRIGGER_BCAST;
 	memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
 	wil->suspend_stats.min_suspend_time = ULONG_MAX;
+	wil->vring_idle_trsh = 16;
 
 	return 0;
 
@@ -1042,6 +1043,12 @@
 		wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
 		wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
 
+		if (wil->fw_calib_result > 0) {
+			__le32 val = cpu_to_le32(wil->fw_calib_result |
+						 (CALIB_RESULT_SIGNATURE << 8));
+			wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val);
+		}
+
 		wil_release_cpu(wil);
 	}
 
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 8f1e79b4..8fe2239 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1666,7 +1666,7 @@
 
 	/* performance monitoring */
 	used = wil_vring_used_tx(vring);
-	if (wil_val_in_range(vring_idle_trsh,
+	if (wil_val_in_range(wil->vring_idle_trsh,
 			     used, used + descs_used)) {
 		txdata->idle += get_cycles() - txdata->last_idle;
 		wil_dbg_txrx(wil,  "Ring[%2d] not idle %d -> %d\n",
@@ -1813,7 +1813,7 @@
 
 	/* performance monitoring */
 	used = wil_vring_used_tx(vring);
-	if (wil_val_in_range(vring_idle_trsh,
+	if (wil_val_in_range(wil->vring_idle_trsh,
 			     used, used + nr_frags + 1)) {
 		txdata->idle += get_cycles() - txdata->last_idle;
 		wil_dbg_txrx(wil,  "Ring[%2d] not idle %d -> %d\n",
@@ -2175,7 +2175,7 @@
 
 	/* performance monitoring */
 	used_new = wil_vring_used_tx(vring);
-	if (wil_val_in_range(vring_idle_trsh,
+	if (wil_val_in_range(wil->vring_idle_trsh,
 			     used_new, used_before_complete)) {
 		wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n",
 			     ringid, used_before_complete, used_new);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 17d7f19..b4ca4e3 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -31,7 +31,6 @@
 extern unsigned int mtu_max;
 extern unsigned short rx_ring_overflow_thrsh;
 extern int agg_wsize;
-extern u32 vring_idle_trsh;
 extern bool rx_align_2;
 extern bool rx_large_buf;
 extern bool debug_fw;
@@ -175,6 +174,10 @@
 #define RGF_USER_USER_SCRATCH_PAD	(0x8802bc)
 #define RGF_USER_BL			(0x880A3C) /* Boot Loader */
 #define RGF_USER_FW_REV_ID		(0x880a8c) /* chip revision */
+#define RGF_USER_FW_CALIB_RESULT	(0x880a90) /* b0-7:result
+						    * b8-15:signature
+						    */
+	#define CALIB_RESULT_SIGNATURE	(0x11)
 #define RGF_USER_CLKS_CTL_0		(0x880abc)
 	#define BIT_USER_CLKS_CAR_AHB_SW_SEL	BIT(1) /* ref clk/PLL */
 	#define BIT_USER_CLKS_RST_PWGD	BIT(11) /* reset on "power good" */
@@ -694,6 +697,7 @@
 	u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
 	struct wil_sta_info sta[WIL6210_MAX_CID];
 	int bcast_vring;
+	u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once  */
 	bool use_extended_dma_addr; /* indicates whether we are using 48 bits */
 	/* scan */
 	struct cfg80211_scan_request *scan_request;
@@ -733,6 +737,8 @@
 	bool tt_data_set;
 	struct wmi_tt_data tt_data;
 
+	int fw_calib_result;
+
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM_SLEEP
 	struct notifier_block pm_notify;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index dc1b30c..43cdaef 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -345,6 +345,11 @@
 	strlcpy(wdev->wiphy->fw_version, wil->fw_version,
 		sizeof(wdev->wiphy->fw_version));
 
+	if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) {
+		wil_dbg_wmi(wil, "rfc calibration result %d\n",
+			    evt->rfc_read_calib_result);
+		wil->fw_calib_result = evt->rfc_read_calib_result;
+	}
 	wil_set_recovery_state(wil, fw_recovery_idle);
 	set_bit(wil_status_fwready, wil->status);
 	/* let the reset sequence continue */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 4e31c2f..1b426d7 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -1300,6 +1300,8 @@
 	/* enum wmi_phy_capability */
 	u8 phy_capability;
 	u8 numof_additional_mids;
+	u8 rfc_read_calib_result;
+	u8 reserved[3];
 } __packed;
 
 /* WMI_NOTIFY_REQ_DONE_EVENTID */
diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c
index 5e797d5..712936f 100644
--- a/drivers/nfc/fdp/i2c.c
+++ b/drivers/nfc/fdp/i2c.c
@@ -210,14 +210,14 @@
 	struct sk_buff *skb;
 	int r;
 
-	client = phy->i2c_dev;
-	dev_dbg(&client->dev, "%s\n", __func__);
-
 	if (!phy || irq != phy->i2c_dev->irq) {
 		WARN_ON_ONCE(1);
 		return IRQ_NONE;
 	}
 
+	client = phy->i2c_dev;
+	dev_dbg(&client->dev, "%s\n", __func__);
+
 	r = fdp_nci_i2c_read(phy, &skb);
 
 	if (r == -EREMOTEIO)
diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c
index 2b2330b..073e4a4 100644
--- a/drivers/nfc/port100.c
+++ b/drivers/nfc/port100.c
@@ -725,23 +725,33 @@
 
 static int port100_send_ack(struct port100 *dev)
 {
-	int rc;
+	int rc = 0;
 
 	mutex_lock(&dev->out_urb_lock);
 
-	init_completion(&dev->cmd_cancel_done);
-
-	usb_kill_urb(dev->out_urb);
-
-	dev->out_urb->transfer_buffer = ack_frame;
-	dev->out_urb->transfer_buffer_length = sizeof(ack_frame);
-	rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
-
-	/* Set the cmd_cancel flag only if the URB has been successfully
-	 * submitted. It will be reset by the out URB completion callback
-	 * port100_send_complete().
+	/*
+	 * If prior cancel is in-flight (dev->cmd_cancel == true), we
+	 * can skip to send cancel. Then this will wait the prior
+	 * cancel, or merged into the next cancel rarely if next
+	 * cancel was started before waiting done. In any case, this
+	 * will be waked up soon or later.
 	 */
-	dev->cmd_cancel = !rc;
+	if (!dev->cmd_cancel) {
+		reinit_completion(&dev->cmd_cancel_done);
+
+		usb_kill_urb(dev->out_urb);
+
+		dev->out_urb->transfer_buffer = ack_frame;
+		dev->out_urb->transfer_buffer_length = sizeof(ack_frame);
+		rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
+
+		/*
+		 * Set the cmd_cancel flag only if the URB has been
+		 * successfully submitted. It will be reset by the out
+		 * URB completion callback port100_send_complete().
+		 */
+		dev->cmd_cancel = !rc;
+	}
 
 	mutex_unlock(&dev->out_urb_lock);
 
@@ -928,8 +938,8 @@
 	struct port100 *dev = urb->context;
 
 	if (dev->cmd_cancel) {
+		complete_all(&dev->cmd_cancel_done);
 		dev->cmd_cancel = false;
-		complete(&dev->cmd_cancel_done);
 	}
 
 	switch (urb->status) {
@@ -1543,6 +1553,7 @@
 			    PORT100_COMM_RF_HEAD_MAX_LEN;
 	dev->skb_tailroom = PORT100_FRAME_TAIL_LEN;
 
+	init_completion(&dev->cmd_cancel_done);
 	INIT_WORK(&dev->cmd_complete_work, port100_wq_cmd_complete);
 
 	/* The first thing to do with the Port-100 is to set the command type
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index ac27b9b..8e7b120 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -71,7 +71,7 @@
 
 static const struct of_device_id imx_ocotp_dt_ids[] = {
 	{ .compatible = "fsl,imx6q-ocotp",  (void *)128 },
-	{ .compatible = "fsl,imx6sl-ocotp", (void *)32 },
+	{ .compatible = "fsl,imx6sl-ocotp", (void *)64 },
 	{ .compatible = "fsl,imx6sx-ocotp", (void *)128 },
 	{ },
 };
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index f06fb1f..2ecbd22 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, 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
@@ -471,6 +471,7 @@
 
 	pad = pctldev->desc->pins[pin].drv_data;
 
+	pad->is_enabled = true;
 	for (i = 0; i < nconfs; i++) {
 		param = pinconf_to_config_param(configs[i]);
 		arg = pinconf_to_config_argument(configs[i]);
@@ -619,6 +620,10 @@
 			return ret;
 	}
 
+	val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT;
+
+	ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val);
+
 	return ret;
 }
 
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index 205a756..f5d8d61 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -784,7 +784,7 @@
 
 	mutex_lock(&ipa3_usb_ctx->general_mutex);
 	IPA_USB_DBG_LOW("entry\n");
-	if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE ||
+	if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE ||
 		((teth_prot == IPA_USB_RNDIS || teth_prot == IPA_USB_ECM) &&
 		teth_params == NULL) || ipa_usb_notify_cb == NULL ||
 		user_data == NULL) {
@@ -987,7 +987,8 @@
 		params->xfer_scratch.depcmd_hi_addr);
 
 	if (params->client >= IPA_CLIENT_MAX  ||
-		params->teth_prot > IPA_USB_MAX_TETH_PROT_SIZE ||
+		params->teth_prot < 0 ||
+		params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE ||
 		params->xfer_ring_len % GSI_CHAN_RE_SIZE_16B ||
 		params->xfer_scratch.const_buffer_size < 1 ||
 		params->xfer_scratch.const_buffer_size > 31) {
@@ -1251,7 +1252,7 @@
 	int result = 0;
 
 	IPA_USB_DBG_LOW("entry\n");
-	if (ttype > IPA_USB_TRANSPORT_MAX) {
+	if (ttype < 0 || ttype >= IPA_USB_TRANSPORT_MAX) {
 		IPA_USB_ERR("bad parameter.\n");
 		return -EINVAL;
 	}
@@ -1355,7 +1356,8 @@
 		(params->teth_prot != IPA_USB_DIAG &&
 		(params->usb_to_ipa_xferrscidx < 0 ||
 		params->usb_to_ipa_xferrscidx > 127)) ||
-		params->teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
+		params->teth_prot < 0 ||
+		params->teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
 		IPA_USB_ERR("Invalid params\n");
 		return false;
 	}
@@ -2059,7 +2061,7 @@
 
 static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot)
 {
-	if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
+	if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
 		IPA_USB_ERR("bad parameter.\n");
 		return -EFAULT;
 	}
@@ -2247,7 +2249,7 @@
 
 	mutex_lock(&ipa3_usb_ctx->general_mutex);
 	IPA_USB_DBG_LOW("entry\n");
-	if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
+	if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
 		IPA_USB_ERR("bad parameters.\n");
 		result = -EINVAL;
 		goto bad_params;
@@ -2432,7 +2434,7 @@
 	mutex_lock(&ipa3_usb_ctx->general_mutex);
 	IPA_USB_DBG_LOW("entry\n");
 
-	if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
+	if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
 		IPA_USB_ERR("bad parameters.\n");
 		result = -EINVAL;
 		goto bad_params;
@@ -2604,7 +2606,7 @@
 	mutex_lock(&ipa3_usb_ctx->general_mutex);
 	IPA_USB_DBG_LOW("entry\n");
 
-	if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) {
+	if (teth_prot < 0 || teth_prot >= IPA_USB_MAX_TETH_PROT_SIZE) {
 		IPA_USB_ERR("bad parameters.\n");
 		result = -EINVAL;
 		goto bad_params;
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 48e689f..aad7924 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -3642,6 +3642,37 @@
 	}
 }
 
+static void smblib_notify_extcon_props(struct smb_charger *chg, int id)
+{
+	union extcon_property_value val;
+	union power_supply_propval prop_val;
+
+	smblib_get_prop_typec_cc_orientation(chg, &prop_val);
+	val.intval = ((prop_val.intval == 2) ? 1 : 0);
+	extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_TYPEC_POLARITY, val);
+
+	val.intval = true;
+	extcon_set_property(chg->extcon, id,
+				EXTCON_PROP_USB_SS, val);
+}
+
+static void smblib_notify_device_mode(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB, enable);
+}
+
+static void smblib_notify_usb_host(struct smb_charger *chg, bool enable)
+{
+	if (enable)
+		smblib_notify_extcon_props(chg, EXTCON_USB_HOST);
+
+	extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable);
+}
+
 #define HVDCP_DET_MS 2500
 static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
 {
@@ -3664,6 +3695,8 @@
 		/* if not DCP then no hvdcp timeout happens. Enable pd here */
 		vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
 				false, 0);
+		if (chg->use_extcon)
+			smblib_notify_device_mode(chg, true);
 		break;
 	case OCP_CHARGER_BIT:
 	case FLOAT_CHARGER_BIT:
@@ -3749,6 +3782,10 @@
 	 */
 	vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
 			false, 0);
+	if (chg->use_extcon) {
+		smblib_notify_usb_host(chg, true);
+		chg->otg_present = true;
+	}
 }
 
 static void typec_sink_removal(struct smb_charger *chg)
@@ -3899,6 +3936,14 @@
 
 	typec_sink_removal(chg);
 	smblib_update_usb_type(chg);
+
+	if (chg->use_extcon) {
+		if (chg->otg_present)
+			smblib_notify_usb_host(chg, false);
+		else
+			smblib_notify_device_mode(chg, false);
+	}
+	chg->otg_present = false;
 }
 
 static void smblib_handle_typec_insertion(struct smb_charger *chg)
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 704a8db..5251b6f 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -144,6 +144,9 @@
 	EXTCON_NONE,
 };
 
+/* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */
+static const u32 smblib_extcon_exclusive[] = {0x3, 0};
+
 struct smb_regulator {
 	struct regulator_dev	*rdev;
 	struct regulator_desc	rdesc;
@@ -331,6 +334,8 @@
 	int			usb_icl_change_irq_enabled;
 	u32			jeita_status;
 	u8			float_cfg;
+	bool			use_extcon;
+	bool			otg_present;
 
 	/* workaround flag */
 	u32			wa_flags;
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 911dd69..e0c92c6 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -170,6 +170,9 @@
 	chip->dt.suspend_input = of_property_read_bool(node,
 				"qcom,suspend-input");
 
+	chg->use_extcon = of_property_read_bool(node,
+				"qcom,use-extcon");
+
 	rc = of_property_read_u32(node,
 				"qcom,fcc-max-ua", &chip->dt.fcc_ua);
 	if (rc < 0)
@@ -1405,55 +1408,95 @@
 	rc = smb138x_parse_dt(chip);
 	if (rc < 0) {
 		pr_err("Couldn't parse device tree rc=%d\n", rc);
-		return rc;
+		goto cleanup;
 	}
 
 	rc = smb138x_init_vbus_regulator(chip);
 	if (rc < 0) {
 		pr_err("Couldn't initialize vbus regulator rc=%d\n",
 			rc);
-		return rc;
+		goto cleanup;
 	}
 
 	rc = smb138x_init_vconn_regulator(chip);
 	if (rc < 0) {
 		pr_err("Couldn't initialize vconn regulator rc=%d\n",
 			rc);
-		return rc;
+		goto cleanup;
+	}
+
+	if (chg->use_extcon) {
+		/* extcon registration */
+		chg->extcon = devm_extcon_dev_allocate(chg->dev,
+							smblib_extcon_cable);
+		if (IS_ERR(chg->extcon)) {
+			rc = PTR_ERR(chg->extcon);
+			dev_err(chg->dev, "failed to allocate extcon device rc=%d\n",
+					rc);
+			goto cleanup;
+		}
+
+		chg->extcon->mutually_exclusive = smblib_extcon_exclusive;
+		rc = devm_extcon_dev_register(chg->dev, chg->extcon);
+		if (rc < 0) {
+			dev_err(chg->dev, "failed to register extcon device rc=%d\n",
+						rc);
+			goto cleanup;
+		}
+
+		/* Support reporting polarity and speed via properties */
+		rc = extcon_set_property_capability(chg->extcon,
+				EXTCON_USB, EXTCON_PROP_USB_TYPEC_POLARITY);
+		rc |= extcon_set_property_capability(chg->extcon,
+				EXTCON_USB, EXTCON_PROP_USB_SS);
+		rc |= extcon_set_property_capability(chg->extcon,
+				EXTCON_USB_HOST,
+				EXTCON_PROP_USB_TYPEC_POLARITY);
+		rc |= extcon_set_property_capability(chg->extcon,
+				EXTCON_USB_HOST, EXTCON_PROP_USB_SS);
+		if (rc < 0) {
+			dev_err(chg->dev,
+				"failed to configure extcon capabilities\n");
+			goto cleanup;
+		}
 	}
 
 	rc = smb138x_init_usb_psy(chip);
 	if (rc < 0) {
 		pr_err("Couldn't initialize usb psy rc=%d\n", rc);
-		return rc;
+		goto cleanup;
 	}
 
 	rc = smb138x_init_batt_psy(chip);
 	if (rc < 0) {
 		pr_err("Couldn't initialize batt psy rc=%d\n", rc);
-		return rc;
+		goto cleanup;
 	}
 
 	rc = smb138x_init_hw(chip);
 	if (rc < 0) {
 		pr_err("Couldn't initialize hardware rc=%d\n", rc);
-		return rc;
+		goto cleanup;
 	}
 
 	rc = smb138x_determine_initial_status(chip);
 	if (rc < 0) {
 		pr_err("Couldn't determine initial status rc=%d\n",
 			rc);
-		return rc;
+		goto cleanup;
 	}
 
 	rc = smb138x_request_interrupts(chip);
 	if (rc < 0) {
 		pr_err("Couldn't request interrupts rc=%d\n", rc);
-		return rc;
+		goto cleanup;
 	}
 
 	return rc;
+
+cleanup:
+	smblib_deinit(chg);
+	return rc;
 }
 
 static int smb138x_slave_probe(struct smb138x *chip)
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 9d253cb..e70410b 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -64,9 +64,9 @@
 u32	bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size;
 u32	*bfi_image_cb, *bfi_image_ct, *bfi_image_ct2;
 
-#define BFAD_FW_FILE_CB		"cbfw-3.2.3.0.bin"
-#define BFAD_FW_FILE_CT		"ctfw-3.2.3.0.bin"
-#define BFAD_FW_FILE_CT2	"ct2fw-3.2.3.0.bin"
+#define BFAD_FW_FILE_CB		"cbfw-3.2.5.1.bin"
+#define BFAD_FW_FILE_CT		"ctfw-3.2.5.1.bin"
+#define BFAD_FW_FILE_CT2	"ct2fw-3.2.5.1.bin"
 
 static u32 *bfad_load_fwimg(struct pci_dev *pdev);
 static void bfad_free_fwimg(void);
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index f9e8620..cfcfff4 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -58,7 +58,7 @@
 #ifdef BFA_DRIVER_VERSION
 #define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION
 #else
-#define BFAD_DRIVER_VERSION    "3.2.25.0"
+#define BFAD_DRIVER_VERSION    "3.2.25.1"
 #endif
 
 #define BFAD_PROTO_NAME FCPI_NAME
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index 9ddc920..9e4b770 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -248,6 +248,7 @@
 	struct completion *remove_wait; /* device remove thread blocks */
 
 	atomic_t in_flight;		/* io counter */
+	bool internal_reset_inprogress;
 	u32 _reserved;			/* fill hole */
 	unsigned long state_flags;	/* protected by host lock */
 	enum fnic_state state;
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index d9fd2f8..44dd372 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -2573,6 +2573,19 @@
 	unsigned long wait_host_tmo;
 	struct Scsi_Host *shost = sc->device->host;
 	struct fc_lport *lp = shost_priv(shost);
+	struct fnic *fnic = lport_priv(lp);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fnic->fnic_lock, flags);
+	if (fnic->internal_reset_inprogress == 0) {
+		fnic->internal_reset_inprogress = 1;
+	} else {
+		spin_unlock_irqrestore(&fnic->fnic_lock, flags);
+		FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+			"host reset in progress skipping another host reset\n");
+		return SUCCESS;
+	}
+	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 
 	/*
 	 * If fnic_reset is successful, wait for fabric login to complete
@@ -2593,6 +2606,9 @@
 		}
 	}
 
+	spin_lock_irqsave(&fnic->fnic_lock, flags);
+	fnic->internal_reset_inprogress = 0;
+	spin_unlock_irqrestore(&fnic->fnic_lock, flags);
 	return ret;
 }
 
diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c
index 396b32d..7cf70aa 100644
--- a/drivers/scsi/snic/snic_main.c
+++ b/drivers/scsi/snic/snic_main.c
@@ -591,6 +591,7 @@
 	if (!pool) {
 		SNIC_HOST_ERR(shost, "dflt sgl pool creation failed\n");
 
+		ret = -ENOMEM;
 		goto err_free_res;
 	}
 
@@ -601,6 +602,7 @@
 	if (!pool) {
 		SNIC_HOST_ERR(shost, "max sgl pool creation failed\n");
 
+		ret = -ENOMEM;
 		goto err_free_dflt_sgl_pool;
 	}
 
@@ -611,6 +613,7 @@
 	if (!pool) {
 		SNIC_HOST_ERR(shost, "snic tmreq info pool creation failed.\n");
 
+		ret = -ENOMEM;
 		goto err_free_max_sgl_pool;
 	}
 
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 04c53751..a8fb8b6 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -692,3 +692,14 @@
 	  This module enables bridging an Inter-Processor Communication(IPC)
 	  interrupt from a remote subsystem directed towards Qualcomm
 	  Technologies, Inc. Secure Execution Environment(QSEE).
+
+config MSM_JTAGV8
+	bool "Debug and ETM trace support across power collapse for ARMv8"
+	default y if CORESIGHT_SOURCE_ETM4X
+	help
+	  Enables support for debugging (specifically breakpoints) and ETM
+	  processor tracing across power collapse both for JTag and OS hosted
+	  software running on ARMv8 target. Enabling this will ensure debug
+	  and ETM registers are saved and restored across power collapse.
+	  If unsure, say 'N' here to avoid potential power, performance and
+	  memory penalty.
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index ca3fd0b..6eef58f 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -68,6 +68,7 @@
        obj-y += subsystem_restart.o
        obj-y += ramdump.o
 endif
+obj-$(CONFIG_MSM_JTAGV8) += jtagv8.o jtagv8-etm.o
 obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
 obj-$(CONFIG_MSM_QBT1000) += qbt1000.o
 obj-$(CONFIG_MSM_EVENT_TIMER) += event_timer.o
diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c
index 21b2034..2a23ba7 100644
--- a/drivers/soc/qcom/dcc_v2.c
+++ b/drivers/soc/qcom/dcc_v2.c
@@ -598,7 +598,7 @@
 				   drvdata->ram_offset/4, DCC_LL_BASE(list));
 			dcc_writel(drvdata, drvdata->ram_start +
 				   drvdata->ram_offset/4, DCC_FD_BASE(list));
-			dcc_writel(drvdata, 0, DCC_LL_TIMEOUT(list));
+			dcc_writel(drvdata, 0xFFF, DCC_LL_TIMEOUT(list));
 		}
 
 		/* 4. Configure trigger, data sink and function type */
diff --git a/drivers/soc/qcom/gladiator_erp.c b/drivers/soc/qcom/gladiator_erp.c
index 835d4b0..3b70ca4 100644
--- a/drivers/soc/qcom/gladiator_erp.c
+++ b/drivers/soc/qcom/gladiator_erp.c
@@ -163,6 +163,7 @@
 	DISCONNECT_ERROR,
 	DIRECTORY_ERROR,
 	PARITY_ERROR,
+	PHYSICAL_ADDRESS_ERROR,
 };
 
 static void clear_gladiator_error(void __iomem *gladiator_virt_base,
@@ -200,12 +201,14 @@
 
 static inline void print_gld_errtype(unsigned int errtype)
 {
+	char *errors = "Disconnect, Directory, Parity, Physical address";
+
 	if (errtype == 0)
 		pr_alert("Error type: Snoop data transfer\n");
 	else if (errtype == 1)
 		pr_alert("Error type: DVM error\n");
 	else if (errtype == 3)
-		pr_alert("Error type: Disconnect, directory, or parity error\n");
+		pr_alert("Error type: %s\n", errors);
 	else
 		pr_alert("Error type: Unknown; value:%u\n", errtype);
 }
@@ -288,7 +291,7 @@
 
 	log_err_type = (err_reg5 & mask_shifts->gld_errlog5_error_type_mask)
 		>> mask_shifts->gld_errlog5_error_type_shift;
-	for (i = 0 ; i <= 6 ; i++) {
+	for (i = 0 ; i <= 7 ; i++) {
 		value = log_err_type & 0x1;
 		switch (i) {
 		case DATA_TRANSFER_ERROR:
@@ -337,7 +340,14 @@
 					mask_shifts);
 			decode_index_parity(err_reg5, mask_shifts);
 			break;
+		case PHYSICAL_ADDRESS_ERROR:
+			if (value == 0)
+				continue;
+			pr_alert("Error type: Physical address error\n");
+			pr_alert("Address is greater than SoC address range\n");
+			break;
 		}
+
 		log_err_type = log_err_type >> 1;
 	}
 }
diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c
index c44aa93..a08c4bf 100644
--- a/drivers/soc/qcom/glink_spi_xprt.c
+++ b/drivers/soc/qcom/glink_spi_xprt.c
@@ -121,6 +121,8 @@
  * @tx_fifo_write_reg_addr:	Address of the TX FIFO Write Index Register.
  * @rx_fifo_read_reg_addr:	Address of the RX FIFO Read Index Register.
  * @rx_fifo_write_reg_addr:	Address of the RX FIFO Write Index Register.
+ * @tx_fifo_write:		Internal write index for TX FIFO.
+ * @rx_fifo_read:		Internal read index for RX FIFO.
  * @kwork:			Work to be executed when receiving data.
  * @kworker:			Handle to the entity processing @kwork.
  * @task:			Handle to the task context that runs @kworker.
@@ -158,6 +160,8 @@
 	unsigned int tx_fifo_write_reg_addr;
 	unsigned int rx_fifo_read_reg_addr;
 	unsigned int rx_fifo_write_reg_addr;
+	uint32_t tx_fifo_write;
+	uint32_t rx_fifo_read;
 
 	struct kthread_work kwork;
 	struct kthread_worker kworker;
@@ -374,6 +378,19 @@
 	int write_avail;
 	int ret;
 
+	if (unlikely(!einfo->tx_fifo_start)) {
+		ret = glink_spi_xprt_reg_read(einfo,
+			einfo->tx_fifo_write_reg_addr, &einfo->tx_fifo_write);
+		if (ret < 0) {
+			pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
+				__func__, ret, einfo->xprt_cfg.edge,
+				einfo->tx_fifo_write_reg_addr);
+			return 0;
+		}
+		einfo->tx_fifo_start = einfo->tx_fifo_write;
+	}
+	write_id = einfo->tx_fifo_write;
+
 	ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_read_reg_addr,
 				   &read_id);
 	if (ret < 0) {
@@ -383,21 +400,9 @@
 		return 0;
 	}
 
-	ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_write_reg_addr,
-				&write_id);
-	if (ret < 0) {
-		pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
-			__func__, ret, einfo->xprt_cfg.edge,
-			einfo->tx_fifo_write_reg_addr);
-		return 0;
-	}
-
 	if (!read_id || !write_id)
 		return 0;
 
-	if (unlikely(!einfo->tx_fifo_start))
-		einfo->tx_fifo_start = write_id;
-
 	if (read_id > write_id)
 		write_avail = read_id - write_id;
 	else
@@ -427,14 +432,18 @@
 	int read_avail;
 	int ret;
 
-	ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_read_reg_addr,
-				   &read_id);
-	if (ret < 0) {
-		pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
-			__func__, ret, einfo->xprt_cfg.edge,
-			einfo->rx_fifo_read_reg_addr);
-		return 0;
+	if (unlikely(!einfo->rx_fifo_start)) {
+		ret = glink_spi_xprt_reg_read(einfo,
+			einfo->rx_fifo_read_reg_addr, &einfo->rx_fifo_read);
+		if (ret < 0) {
+			pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
+				__func__, ret, einfo->xprt_cfg.edge,
+				einfo->rx_fifo_read_reg_addr);
+			return 0;
+		}
+		einfo->rx_fifo_start = einfo->rx_fifo_read;
 	}
+	read_id = einfo->rx_fifo_read;
 
 	ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_write_reg_addr,
 				&write_id);
@@ -448,9 +457,6 @@
 	if (!read_id || !write_id)
 		return 0;
 
-	if (unlikely(!einfo->rx_fifo_start))
-		einfo->rx_fifo_start = read_id;
-
 	if (read_id <= write_id)
 		read_avail = write_id - read_id;
 	else
@@ -477,15 +483,7 @@
 	uint32_t offset = 0;
 	int ret;
 
-	ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_read_reg_addr,
-				   &read_id);
-	if (ret < 0) {
-		pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
-			__func__, ret, einfo->xprt_cfg.edge,
-			einfo->rx_fifo_read_reg_addr);
-		return ret;
-	}
-
+	read_id = einfo->rx_fifo_read;
 	do {
 		if ((read_id + size_to_read) >=
 		    (einfo->rx_fifo_start + einfo->fifo_size))
@@ -510,6 +508,9 @@
 		pr_err("%s: Error %d writing %s rx_fifo_read_reg_addr %d\n",
 			__func__, ret, einfo->xprt_cfg.edge,
 			einfo->rx_fifo_read_reg_addr);
+	else
+		einfo->rx_fifo_read = read_id;
+
 	return ret;
 }
 
@@ -532,15 +533,7 @@
 	uint32_t offset = 0;
 	int ret;
 
-	ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_write_reg_addr,
-				&write_id);
-	if (ret < 0) {
-		pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
-			__func__, ret, einfo->xprt_cfg.edge,
-			einfo->tx_fifo_write_reg_addr);
-		return ret;
-	}
-
+	write_id = einfo->tx_fifo_write;
 	do {
 		if ((write_id + size_to_write) >=
 		    (einfo->tx_fifo_start + einfo->fifo_size))
@@ -565,6 +558,9 @@
 		pr_err("%s: Error %d writing %s tx_fifo_write_reg_addr %d\n",
 			__func__, ret, einfo->xprt_cfg.edge,
 			einfo->tx_fifo_write_reg_addr);
+	else
+		einfo->tx_fifo_write = write_id;
+
 	return ret;
 }
 
@@ -1242,6 +1238,8 @@
 	einfo->tx_blocked_signal_sent = false;
 	einfo->tx_fifo_start = 0;
 	einfo->rx_fifo_start = 0;
+	einfo->tx_fifo_write = 0;
+	einfo->rx_fifo_read = 0;
 	einfo->fifo_size = DEFAULT_FIFO_SIZE;
 	einfo->xprt_if.glink_core_if_ptr->link_down(&einfo->xprt_if);
 
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 38099e9..209209b 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -558,6 +558,12 @@
 	int i;
 	enum icnss_msa_perm old_perm;
 
+	if (priv->nr_mem_region > QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01) {
+		icnss_pr_err("Invalid memory region len %d\n",
+			     priv->nr_mem_region);
+		return -EINVAL;
+	}
+
 	for (i = 0; i < priv->nr_mem_region; i++) {
 		old_perm = priv->mem_region[i].perm;
 		ret = icnss_assign_msa_perm(&priv->mem_region[i], new_perm);
diff --git a/drivers/soc/qcom/jtagv8-etm.c b/drivers/soc/qcom/jtagv8-etm.c
new file mode 100644
index 0000000..ff8cc99
--- /dev/null
+++ b/drivers/soc/qcom/jtagv8-etm.c
@@ -0,0 +1,1722 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/export.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/coresight.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/jtag.h>
+#include <asm/smp_plat.h>
+#include <asm/etmv4x.h>
+#include <soc/qcom/socinfo.h>
+
+#define CORESIGHT_LAR		(0xFB0)
+
+#define TIMEOUT_US		(100)
+
+#define BM(lsb, msb)		((BIT(msb) - BIT(lsb)) + BIT(msb))
+#define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
+#define BVAL(val, n)		((val & BIT(n)) >> n)
+
+/*
+ * ETMv4 registers:
+ * 0x000 - 0x2FC: Trace         registers
+ * 0x300 - 0x314: Management    registers
+ * 0x318 - 0xEFC: Trace         registers
+ * 0xF00: Management		registers
+ * 0xFA0 - 0xFA4: Trace		registers
+ * 0xFA8 - 0xFFC: Management	registers
+ */
+
+/* Trace registers (0x000-0x2FC) */
+/* Main control and configuration registers  */
+#define TRCPRGCTLR			(0x004)
+#define TRCPROCSELR			(0x008)
+#define TRCSTATR			(0x00C)
+#define TRCCONFIGR			(0x010)
+#define TRCAUXCTLR			(0x018)
+#define TRCEVENTCTL0R			(0x020)
+#define TRCEVENTCTL1R			(0x024)
+#define TRCSTALLCTLR			(0x02C)
+#define TRCTSCTLR			(0x030)
+#define TRCSYNCPR			(0x034)
+#define TRCCCCTLR			(0x038)
+#define TRCBBCTLR			(0x03C)
+#define TRCTRACEIDR			(0x040)
+#define TRCQCTLR			(0x044)
+/* Filtering control registers */
+#define TRCVICTLR			(0x080)
+#define TRCVIIECTLR			(0x084)
+#define TRCVISSCTLR			(0x088)
+#define TRCVIPCSSCTLR			(0x08C)
+#define TRCVDCTLR			(0x0A0)
+#define TRCVDSACCTLR			(0x0A4)
+#define TRCVDARCCTLR			(0x0A8)
+/* Derived resources registers */
+#define TRCSEQEVRn(n)			(0x100 + (n * 4))
+#define TRCSEQRSTEVR			(0x118)
+#define TRCSEQSTR			(0x11C)
+#define TRCEXTINSELR			(0x120)
+#define TRCCNTRLDVRn(n)			(0x140 + (n * 4))
+#define TRCCNTCTLRn(n)			(0x150 + (n * 4))
+#define TRCCNTVRn(n)			(0x160 + (n * 4))
+/* ID registers */
+#define TRCIDR8				(0x180)
+#define TRCIDR9				(0x184)
+#define TRCIDR10			(0x188)
+#define TRCIDR11			(0x18C)
+#define TRCIDR12			(0x190)
+#define TRCIDR13			(0x194)
+#define TRCIMSPEC0			(0x1C0)
+#define TRCIMSPECn(n)			(0x1C0 + (n * 4))
+#define TRCIDR0				(0x1E0)
+#define TRCIDR1				(0x1E4)
+#define TRCIDR2				(0x1E8)
+#define TRCIDR3				(0x1EC)
+#define TRCIDR4				(0x1F0)
+#define TRCIDR5				(0x1F4)
+#define TRCIDR6				(0x1F8)
+#define TRCIDR7				(0x1FC)
+/* Resource selection registers */
+#define TRCRSCTLRn(n)			(0x200 + (n * 4))
+/* Single-shot comparator registers */
+#define TRCSSCCRn(n)			(0x280 + (n * 4))
+#define TRCSSCSRn(n)			(0x2A0 + (n * 4))
+#define TRCSSPCICRn(n)			(0x2C0 + (n * 4))
+/* Management registers (0x300-0x314) */
+#define TRCOSLAR			(0x300)
+#define TRCOSLSR			(0x304)
+#define TRCPDCR				(0x310)
+#define TRCPDSR				(0x314)
+/* Trace registers (0x318-0xEFC) */
+/* Comparator registers */
+#define TRCACVRn(n)			(0x400 + (n * 8))
+#define TRCACATRn(n)			(0x480 + (n * 8))
+#define TRCDVCVRn(n)			(0x500 + (n * 16))
+#define TRCDVCMRn(n)			(0x580 + (n * 16))
+#define TRCCIDCVRn(n)			(0x600 + (n * 8))
+#define TRCVMIDCVRn(n)			(0x640 + (n * 8))
+#define TRCCIDCCTLR0			(0x680)
+#define TRCCIDCCTLR1			(0x684)
+#define TRCVMIDCCTLR0			(0x688)
+#define TRCVMIDCCTLR1			(0x68C)
+/* Management register (0xF00) */
+/* Integration control registers */
+#define TRCITCTRL			(0xF00)
+/* Trace registers (0xFA0-0xFA4) */
+/* Claim tag registers */
+#define TRCCLAIMSET			(0xFA0)
+#define TRCCLAIMCLR			(0xFA4)
+/* Management registers (0xFA8-0xFFC) */
+#define TRCDEVAFF0			(0xFA8)
+#define TRCDEVAFF1			(0xFAC)
+#define TRCLAR				(0xFB0)
+#define TRCLSR				(0xFB4)
+#define TRCAUTHSTATUS			(0xFB8)
+#define TRCDEVARCH			(0xFBC)
+#define TRCDEVID			(0xFC8)
+#define TRCDEVTYPE			(0xFCC)
+#define TRCPIDR4			(0xFD0)
+#define TRCPIDR5			(0xFD4)
+#define TRCPIDR6			(0xFD8)
+#define TRCPIDR7			(0xFDC)
+#define TRCPIDR0			(0xFE0)
+#define TRCPIDR1			(0xFE4)
+#define TRCPIDR2			(0xFE8)
+#define TRCPIDR3			(0xFEC)
+#define TRCCIDR0			(0xFF0)
+#define TRCCIDR1			(0xFF4)
+#define TRCCIDR2			(0xFF8)
+#define TRCCIDR3			(0xFFC)
+
+/* ETMv4 resources */
+#define ETM_MAX_NR_PE			(8)
+#define ETM_MAX_CNTR			(4)
+#define ETM_MAX_SEQ_STATES		(4)
+#define ETM_MAX_EXT_INP_SEL		(4)
+#define ETM_MAX_EXT_INP			(256)
+#define ETM_MAX_EXT_OUT			(4)
+#define ETM_MAX_SINGLE_ADDR_CMP		(16)
+#define ETM_MAX_ADDR_RANGE_CMP		(ETM_MAX_SINGLE_ADDR_CMP / 2)
+#define ETM_MAX_DATA_VAL_CMP		(8)
+#define ETM_MAX_CTXID_CMP		(8)
+#define ETM_MAX_VMID_CMP		(8)
+#define ETM_MAX_PE_CMP			(8)
+#define ETM_MAX_RES_SEL			(32)
+#define ETM_MAX_SS_CMP			(8)
+
+#define ETM_CPMR_CLKEN			(0x4)
+#define ETM_ARCH_V4			(0x40)
+#define ETM_ARCH_V4_2			(0x42)
+
+#define MAX_ETM_STATE_SIZE	(165)
+
+#define TZ_DBG_ETM_FEAT_ID	(0x8)
+#define TZ_DBG_ETM_VER		(0x400000)
+#define HW_SOC_ID_M8953		(293)
+
+#define etm_writel(etm, val, off)	\
+		   __raw_writel(val, etm->base + off)
+#define etm_readl(etm, off)		\
+		  __raw_readl(etm->base + off)
+
+#define etm_writeq(etm, val, off)	\
+		   __raw_writeq(val, etm->base + off)
+#define etm_readq(etm, off)		\
+		  __raw_readq(etm->base + off)
+
+#define ETM_LOCK(base)							\
+do {									\
+	mb(); /* ensure configuration take effect before we lock it */	\
+	etm_writel(base, 0x0, CORESIGHT_LAR);				\
+} while (0)
+
+#define ETM_UNLOCK(base)						\
+do {									\
+	etm_writel(base, CORESIGHT_UNLOCK, CORESIGHT_LAR);		\
+	mb(); /* ensure unlock take effect before we configure */	\
+} while (0)
+
+struct etm_ctx {
+	uint8_t			arch;
+	uint8_t			nr_pe;
+	uint8_t			nr_pe_cmp;
+	uint8_t			nr_addr_cmp;
+	uint8_t			nr_data_cmp;
+	uint8_t			nr_cntr;
+	uint8_t			nr_ext_inp;
+	uint8_t			nr_ext_inp_sel;
+	uint8_t			nr_ext_out;
+	uint8_t			nr_ctxid_cmp;
+	uint8_t			nr_vmid_cmp;
+	uint8_t			nr_seq_state;
+	uint8_t			nr_event;
+	uint8_t			nr_resource;
+	uint8_t			nr_ss_cmp;
+	bool			si_enable;
+	bool			save_restore_disabled;
+	bool			save_restore_enabled;
+	bool			os_lock_present;
+	bool			init;
+	bool			enable;
+	void __iomem		*base;
+	struct device		*dev;
+	uint64_t		*state;
+	spinlock_t		spinlock;
+	struct mutex		mutex;
+};
+
+static struct etm_ctx *etm[NR_CPUS];
+static int cnt;
+
+static struct clk *clock[NR_CPUS];
+
+static ATOMIC_NOTIFIER_HEAD(etm_save_notifier_list);
+static ATOMIC_NOTIFIER_HEAD(etm_restore_notifier_list);
+
+int msm_jtag_save_register(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&etm_save_notifier_list, nb);
+}
+EXPORT_SYMBOL(msm_jtag_save_register);
+
+int msm_jtag_save_unregister(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&etm_save_notifier_list, nb);
+}
+EXPORT_SYMBOL(msm_jtag_save_unregister);
+
+int msm_jtag_restore_register(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_register(&etm_restore_notifier_list, nb);
+}
+EXPORT_SYMBOL(msm_jtag_restore_register);
+
+int msm_jtag_restore_unregister(struct notifier_block *nb)
+{
+	return atomic_notifier_chain_unregister(&etm_restore_notifier_list, nb);
+}
+EXPORT_SYMBOL(msm_jtag_restore_unregister);
+
+static void etm_os_lock(struct etm_ctx *etmdata)
+{
+	if (etmdata->os_lock_present) {
+		etm_writel(etmdata, 0x1, TRCOSLAR);
+		/* Ensure OS lock is set before proceeding */
+		mb();
+	}
+}
+
+static void etm_os_unlock(struct etm_ctx *etmdata)
+{
+	if (etmdata->os_lock_present) {
+		/* Ensure all writes are complete before clearing OS lock */
+		mb();
+		etm_writel(etmdata, 0x0, TRCOSLAR);
+	}
+}
+
+static inline void etm_mm_save_state(struct etm_ctx *etmdata)
+{
+	int i, j, count;
+
+	i = 0;
+	mb(); /* ensure all register writes complete before saving them */
+	isb();
+	ETM_UNLOCK(etmdata);
+
+	switch (etmdata->arch) {
+	case ETM_ARCH_V4_2:
+	case ETM_ARCH_V4:
+		etm_os_lock(etmdata);
+
+		/* poll until programmers' model becomes stable */
+		for (count = TIMEOUT_US; (BVAL(etm_readl(etmdata, TRCSTATR), 1)
+		     != 1) && count > 0; count--)
+			udelay(1);
+		if (count == 0)
+			pr_err_ratelimited("programmers model is not stable\n"
+					   );
+
+		/* main control and configuration registers */
+		etmdata->state[i++] = etm_readl(etmdata, TRCPROCSELR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCCONFIGR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCAUXCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCEVENTCTL0R);
+		etmdata->state[i++] = etm_readl(etmdata, TRCEVENTCTL1R);
+		etmdata->state[i++] = etm_readl(etmdata, TRCSTALLCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCTSCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCSYNCPR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCCCCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCBBCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCTRACEIDR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCQCTLR);
+		/* filtering control registers */
+		etmdata->state[i++] = etm_readl(etmdata, TRCVICTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCVIIECTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCVISSCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCVIPCSSCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCVDCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCVDSACCTLR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCVDARCCTLR);
+		/* derived resource registers */
+		for (j = 0; j < etmdata->nr_seq_state-1; j++)
+			etmdata->state[i++] = etm_readl(etmdata, TRCSEQEVRn(j));
+		etmdata->state[i++] = etm_readl(etmdata, TRCSEQRSTEVR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCSEQSTR);
+		etmdata->state[i++] = etm_readl(etmdata, TRCEXTINSELR);
+		for (j = 0; j < etmdata->nr_cntr; j++)  {
+			etmdata->state[i++] = etm_readl(etmdata,
+						       TRCCNTRLDVRn(j));
+			etmdata->state[i++] = etm_readl(etmdata,
+						       TRCCNTCTLRn(j));
+			etmdata->state[i++] = etm_readl(etmdata,
+						       TRCCNTVRn(j));
+		}
+		/* resource selection registers */
+		for (j = 0; j < etmdata->nr_resource; j++)
+			etmdata->state[i++] = etm_readl(etmdata, TRCRSCTLRn(j));
+		/* comparator registers */
+		for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) {
+			etmdata->state[i++] = etm_readq(etmdata, TRCACVRn(j));
+			etmdata->state[i++] = etm_readq(etmdata, TRCACATRn(j));
+		}
+		for (j = 0; j < etmdata->nr_data_cmp; j++) {
+			etmdata->state[i++] = etm_readq(etmdata, TRCDVCVRn(j));
+			etmdata->state[i++] = etm_readq(etmdata, TRCDVCMRn(i));
+		}
+		for (j = 0; j < etmdata->nr_ctxid_cmp; j++)
+			etmdata->state[i++] = etm_readq(etmdata, TRCCIDCVRn(j));
+		etmdata->state[i++] = etm_readl(etmdata, TRCCIDCCTLR0);
+		etmdata->state[i++] = etm_readl(etmdata, TRCCIDCCTLR1);
+		for (j = 0; j < etmdata->nr_vmid_cmp; j++)
+			etmdata->state[i++] = etm_readq(etmdata,
+							TRCVMIDCVRn(j));
+		etmdata->state[i++] = etm_readl(etmdata, TRCVMIDCCTLR0);
+		etmdata->state[i++] = etm_readl(etmdata, TRCVMIDCCTLR1);
+		/* single-shot comparator registers */
+		for (j = 0; j < etmdata->nr_ss_cmp; j++) {
+			etmdata->state[i++] = etm_readl(etmdata, TRCSSCCRn(j));
+			etmdata->state[i++] = etm_readl(etmdata, TRCSSCSRn(j));
+			etmdata->state[i++] = etm_readl(etmdata,
+							TRCSSPCICRn(j));
+		}
+		/* claim tag registers */
+		etmdata->state[i++] = etm_readl(etmdata, TRCCLAIMCLR);
+		/* program ctrl register */
+		etmdata->state[i++] = etm_readl(etmdata, TRCPRGCTLR);
+
+		/* ensure trace unit is idle to be powered down */
+		for (count = TIMEOUT_US; (BVAL(etm_readl(etmdata, TRCSTATR), 0)
+		     != 1) && count > 0; count--)
+			udelay(1);
+		if (count == 0)
+			pr_err_ratelimited("timeout waiting for idle state\n");
+
+		atomic_notifier_call_chain(&etm_save_notifier_list, 0, NULL);
+
+		break;
+	default:
+		pr_err_ratelimited("unsupported etm arch %d in %s\n",
+				   etmdata->arch, __func__);
+	}
+
+	ETM_LOCK(etmdata);
+}
+
+static inline void etm_mm_restore_state(struct etm_ctx *etmdata)
+{
+	int i, j;
+
+	i = 0;
+	ETM_UNLOCK(etmdata);
+
+	switch (etmdata->arch) {
+	case ETM_ARCH_V4_2:
+	case ETM_ARCH_V4:
+		atomic_notifier_call_chain(&etm_restore_notifier_list, 0, NULL);
+
+		/* check OS lock is locked */
+		if (BVAL(etm_readl(etmdata, TRCOSLSR), 1) != 1) {
+			pr_err_ratelimited("OS lock is unlocked\n");
+			etm_os_lock(etmdata);
+		}
+
+		/* main control and configuration registers */
+		etm_writel(etmdata, etmdata->state[i++], TRCPROCSELR);
+		etm_writel(etmdata, etmdata->state[i++], TRCCONFIGR);
+		etm_writel(etmdata, etmdata->state[i++], TRCAUXCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCEVENTCTL0R);
+		etm_writel(etmdata, etmdata->state[i++], TRCEVENTCTL1R);
+		etm_writel(etmdata, etmdata->state[i++], TRCSTALLCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCTSCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCSYNCPR);
+		etm_writel(etmdata, etmdata->state[i++], TRCCCCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCBBCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCTRACEIDR);
+		etm_writel(etmdata, etmdata->state[i++], TRCQCTLR);
+		/* filtering control registers */
+		etm_writel(etmdata, etmdata->state[i++], TRCVICTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCVIIECTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCVISSCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCVIPCSSCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCVDCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCVDSACCTLR);
+		etm_writel(etmdata, etmdata->state[i++], TRCVDARCCTLR);
+		/* derived resources registers */
+		for (j = 0; j < etmdata->nr_seq_state-1; j++)
+			etm_writel(etmdata, etmdata->state[i++], TRCSEQEVRn(j));
+		etm_writel(etmdata, etmdata->state[i++], TRCSEQRSTEVR);
+		etm_writel(etmdata, etmdata->state[i++], TRCSEQSTR);
+		etm_writel(etmdata, etmdata->state[i++], TRCEXTINSELR);
+		for (j = 0; j < etmdata->nr_cntr; j++)  {
+			etm_writel(etmdata, etmdata->state[i++],
+				  TRCCNTRLDVRn(j));
+			etm_writel(etmdata, etmdata->state[i++],
+				  TRCCNTCTLRn(j));
+			etm_writel(etmdata, etmdata->state[i++], TRCCNTVRn(j));
+		}
+		/* resource selection registers */
+		for (j = 0; j < etmdata->nr_resource; j++)
+			etm_writel(etmdata, etmdata->state[i++], TRCRSCTLRn(j));
+		/* comparator registers */
+		for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) {
+			etm_writeq(etmdata, etmdata->state[i++], TRCACVRn(j));
+			etm_writeq(etmdata, etmdata->state[i++], TRCACATRn(j));
+		}
+		for (j = 0; j < etmdata->nr_data_cmp; j++) {
+			etm_writeq(etmdata, etmdata->state[i++], TRCDVCVRn(j));
+			etm_writeq(etmdata, etmdata->state[i++], TRCDVCMRn(j));
+		}
+		for (j = 0; j < etmdata->nr_ctxid_cmp; j++)
+			etm_writeq(etmdata, etmdata->state[i++], TRCCIDCVRn(j));
+		etm_writel(etmdata, etmdata->state[i++], TRCCIDCCTLR0);
+		etm_writel(etmdata, etmdata->state[i++], TRCCIDCCTLR1);
+		for (j = 0; j < etmdata->nr_vmid_cmp; j++)
+			etm_writeq(etmdata, etmdata->state[i++],
+				   TRCVMIDCVRn(j));
+		etm_writel(etmdata, etmdata->state[i++], TRCVMIDCCTLR0);
+		etm_writel(etmdata, etmdata->state[i++], TRCVMIDCCTLR1);
+		/* e-shot comparator registers */
+		for (j = 0; j < etmdata->nr_ss_cmp; j++) {
+			etm_writel(etmdata, etmdata->state[i++], TRCSSCCRn(j));
+			etm_writel(etmdata, etmdata->state[i++], TRCSSCSRn(j));
+			etm_writel(etmdata, etmdata->state[i++],
+				   TRCSSPCICRn(j));
+		}
+		/* claim tag registers */
+		etm_writel(etmdata, etmdata->state[i++], TRCCLAIMSET);
+		/* program ctrl register */
+		etm_writel(etmdata, etmdata->state[i++], TRCPRGCTLR);
+
+		etm_os_unlock(etmdata);
+		break;
+	default:
+		pr_err_ratelimited("unsupported etm arch %d in %s\n",
+				   etmdata->arch,  __func__);
+	}
+
+	ETM_LOCK(etmdata);
+}
+
+static inline void etm_clk_disable(void)
+{
+	uint32_t cpmr;
+
+	isb();
+	cpmr = trc_readl(CPMR_EL1);
+	cpmr  &= ~ETM_CPMR_CLKEN;
+	trc_write(cpmr, CPMR_EL1);
+}
+
+static inline void etm_clk_enable(void)
+{
+	uint32_t cpmr;
+
+	cpmr = trc_readl(CPMR_EL1);
+	cpmr  |= ETM_CPMR_CLKEN;
+	trc_write(cpmr, CPMR_EL1);
+	isb();
+}
+
+static int etm_read_ssxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = trc_readl(ETMSEQEVR0);
+		break;
+	case 1:
+		state[i++] = trc_readl(ETMSEQEVR1);
+		break;
+	case 2:
+		state[i++] = trc_readl(ETMSEQEVR2);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_crxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = trc_readl(ETMCNTRLDVR0);
+		state[i++] = trc_readl(ETMCNTCTLR0);
+		state[i++] = trc_readl(ETMCNTVR0);
+		break;
+	case 1:
+		state[i++] = trc_readl(ETMCNTRLDVR1);
+		state[i++] = trc_readl(ETMCNTCTLR1);
+		state[i++] = trc_readl(ETMCNTVR1);
+		break;
+	case 2:
+		state[i++] = trc_readl(ETMCNTRLDVR2);
+		state[i++] = trc_readl(ETMCNTCTLR2);
+		state[i++] = trc_readl(ETMCNTVR2);
+		break;
+	case 3:
+		state[i++] = trc_readl(ETMCNTRLDVR3);
+		state[i++] = trc_readl(ETMCNTCTLR3);
+		state[i++] = trc_readl(ETMCNTVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_rsxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 2:
+		state[i++] = trc_readl(ETMRSCTLR2);
+		break;
+	case 3:
+		state[i++] = trc_readl(ETMRSCTLR3);
+		break;
+	case 4:
+		state[i++] = trc_readl(ETMRSCTLR4);
+		break;
+	case 5:
+		state[i++] = trc_readl(ETMRSCTLR5);
+		break;
+	case 6:
+		state[i++] = trc_readl(ETMRSCTLR6);
+		break;
+	case 7:
+		state[i++] = trc_readl(ETMRSCTLR7);
+		break;
+	case 8:
+		state[i++] = trc_readl(ETMRSCTLR8);
+		break;
+	case 9:
+		state[i++] = trc_readl(ETMRSCTLR9);
+		break;
+	case 10:
+		state[i++] = trc_readl(ETMRSCTLR10);
+		break;
+	case 11:
+		state[i++] = trc_readl(ETMRSCTLR11);
+		break;
+	case 12:
+		state[i++] = trc_readl(ETMRSCTLR12);
+		break;
+	case 13:
+		state[i++] = trc_readl(ETMRSCTLR13);
+		break;
+	case 14:
+		state[i++] = trc_readl(ETMRSCTLR14);
+		break;
+	case 15:
+		state[i++] = trc_readl(ETMRSCTLR15);
+		break;
+	case 16:
+		state[i++] = trc_readl(ETMRSCTLR16);
+		break;
+	case 17:
+		state[i++] = trc_readl(ETMRSCTLR17);
+		break;
+	case 18:
+		state[i++] = trc_readl(ETMRSCTLR18);
+		break;
+	case 19:
+		state[i++] = trc_readl(ETMRSCTLR19);
+		break;
+	case 20:
+		state[i++] = trc_readl(ETMRSCTLR20);
+		break;
+	case 21:
+		state[i++] = trc_readl(ETMRSCTLR21);
+		break;
+	case 22:
+		state[i++] = trc_readl(ETMRSCTLR22);
+		break;
+	case 23:
+		state[i++] = trc_readl(ETMRSCTLR23);
+		break;
+	case 24:
+		state[i++] = trc_readl(ETMRSCTLR24);
+		break;
+	case 25:
+		state[i++] = trc_readl(ETMRSCTLR25);
+		break;
+	case 26:
+		state[i++] = trc_readl(ETMRSCTLR26);
+		break;
+	case 27:
+		state[i++] = trc_readl(ETMRSCTLR27);
+		break;
+	case 28:
+		state[i++] = trc_readl(ETMRSCTLR28);
+		break;
+	case 29:
+		state[i++] = trc_readl(ETMRSCTLR29);
+		break;
+	case 30:
+		state[i++] = trc_readl(ETMRSCTLR30);
+		break;
+	case 31:
+		state[i++] = trc_readl(ETMRSCTLR31);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_acr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = trc_readq(ETMACVR0);
+		state[i++] = trc_readq(ETMACATR0);
+		break;
+	case 1:
+		state[i++] = trc_readq(ETMACVR1);
+		state[i++] = trc_readq(ETMACATR1);
+		break;
+	case 2:
+		state[i++] = trc_readq(ETMACVR2);
+		state[i++] = trc_readq(ETMACATR2);
+		break;
+	case 3:
+		state[i++] = trc_readq(ETMACVR3);
+		state[i++] = trc_readq(ETMACATR3);
+		break;
+	case 4:
+		state[i++] = trc_readq(ETMACVR4);
+		state[i++] = trc_readq(ETMACATR4);
+		break;
+	case 5:
+		state[i++] = trc_readq(ETMACVR5);
+		state[i++] = trc_readq(ETMACATR5);
+		break;
+	case 6:
+		state[i++] = trc_readq(ETMACVR6);
+		state[i++] = trc_readq(ETMACATR6);
+		break;
+	case 7:
+		state[i++] = trc_readq(ETMACVR7);
+		state[i++] = trc_readq(ETMACATR7);
+		break;
+	case 8:
+		state[i++] = trc_readq(ETMACVR8);
+		state[i++] = trc_readq(ETMACATR8);
+		break;
+	case 9:
+		state[i++] = trc_readq(ETMACVR9);
+		state[i++] = trc_readq(ETMACATR9);
+		break;
+	case 10:
+		state[i++] = trc_readq(ETMACVR10);
+		state[i++] = trc_readq(ETMACATR10);
+		break;
+	case 11:
+		state[i++] = trc_readq(ETMACVR11);
+		state[i++] = trc_readq(ETMACATR11);
+		break;
+	case 12:
+		state[i++] = trc_readq(ETMACVR12);
+		state[i++] = trc_readq(ETMACATR12);
+		break;
+	case 13:
+		state[i++] = trc_readq(ETMACVR13);
+		state[i++] = trc_readq(ETMACATR13);
+		break;
+	case 14:
+		state[i++] = trc_readq(ETMACVR14);
+		state[i++] = trc_readq(ETMACATR14);
+		break;
+	case 15:
+		state[i++] = trc_readq(ETMACVR15);
+		state[i++] = trc_readq(ETMACATR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_dvcr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = trc_readq(ETMDVCVR0);
+		state[i++] = trc_readq(ETMDVCMR0);
+		break;
+	case 1:
+		state[i++] = trc_readq(ETMDVCVR1);
+		state[i++] = trc_readq(ETMDVCMR1);
+		break;
+	case 2:
+		state[i++] = trc_readq(ETMDVCVR2);
+		state[i++] = trc_readq(ETMDVCMR2);
+		break;
+	case 3:
+		state[i++] = trc_readq(ETMDVCVR3);
+		state[i++] = trc_readq(ETMDVCMR3);
+		break;
+	case 4:
+		state[i++] = trc_readq(ETMDVCVR4);
+		state[i++] = trc_readq(ETMDVCMR4);
+		break;
+	case 5:
+		state[i++] = trc_readq(ETMDVCVR5);
+		state[i++] = trc_readq(ETMDVCMR5);
+		break;
+	case 6:
+		state[i++] = trc_readq(ETMDVCVR6);
+		state[i++] = trc_readq(ETMDVCMR6);
+		break;
+	case 7:
+		state[i++] = trc_readq(ETMDVCVR7);
+		state[i++] = trc_readq(ETMDVCMR7);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_ccvr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = trc_readq(ETMCIDCVR0);
+		break;
+	case 1:
+		state[i++] = trc_readq(ETMCIDCVR1);
+		break;
+	case 2:
+		state[i++] = trc_readq(ETMCIDCVR2);
+		break;
+	case 3:
+		state[i++] = trc_readq(ETMCIDCVR3);
+		break;
+	case 4:
+		state[i++] = trc_readq(ETMCIDCVR4);
+		break;
+	case 5:
+		state[i++] = trc_readq(ETMCIDCVR5);
+		break;
+	case 6:
+		state[i++] = trc_readq(ETMCIDCVR6);
+		break;
+	case 7:
+		state[i++] = trc_readq(ETMCIDCVR7);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_vcvr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = trc_readq(ETMVMIDCVR0);
+		break;
+	case 1:
+		state[i++] = trc_readq(ETMVMIDCVR1);
+		break;
+	case 2:
+		state[i++] = trc_readq(ETMVMIDCVR2);
+		break;
+	case 3:
+		state[i++] = trc_readq(ETMVMIDCVR3);
+		break;
+	case 4:
+		state[i++] = trc_readq(ETMVMIDCVR4);
+		break;
+	case 5:
+		state[i++] = trc_readq(ETMVMIDCVR5);
+		break;
+	case 6:
+		state[i++] = trc_readq(ETMVMIDCVR6);
+		break;
+	case 7:
+		state[i++] = trc_readq(ETMVMIDCVR7);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_sscr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = trc_readl(ETMSSCCR0);
+		state[i++] = trc_readl(ETMSSCSR0);
+		state[i++] = trc_readl(ETMSSPCICR0);
+		break;
+	case 1:
+		state[i++] = trc_readl(ETMSSCCR1);
+		state[i++] = trc_readl(ETMSSCSR1);
+		state[i++] = trc_readl(ETMSSPCICR1);
+		break;
+	case 2:
+		state[i++] = trc_readl(ETMSSCCR2);
+		state[i++] = trc_readl(ETMSSCSR2);
+		state[i++] = trc_readl(ETMSSPCICR2);
+		break;
+	case 3:
+		state[i++] = trc_readl(ETMSSCCR3);
+		state[i++] = trc_readl(ETMSSCSR3);
+		state[i++] = trc_readl(ETMSSPCICR3);
+		break;
+	case 4:
+		state[i++] = trc_readl(ETMSSCCR4);
+		state[i++] = trc_readl(ETMSSCSR4);
+		state[i++] = trc_readl(ETMSSPCICR4);
+		break;
+	case 5:
+		state[i++] = trc_readl(ETMSSCCR5);
+		state[i++] = trc_readl(ETMSSCSR5);
+		state[i++] = trc_readl(ETMSSPCICR5);
+		break;
+	case 6:
+		state[i++] = trc_readl(ETMSSCCR6);
+		state[i++] = trc_readl(ETMSSCSR6);
+		state[i++] = trc_readl(ETMSSPCICR6);
+		break;
+	case 7:
+		state[i++] = trc_readl(ETMSSCCR7);
+		state[i++] = trc_readl(ETMSSCSR7);
+		state[i++] = trc_readl(ETMSSPCICR7);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static inline void etm_si_save_state(struct etm_ctx *etmdata)
+{
+	int i, j, count;
+
+	i = 0;
+	/* Ensure all writes are complete before saving ETM registers */
+	mb();
+	isb();
+
+	/* Vote for ETM power/clock enable */
+	etm_clk_enable();
+
+	switch (etmdata->arch) {
+	case ETM_ARCH_V4_2:
+	case ETM_ARCH_V4:
+		trc_write(0x1, ETMOSLAR);
+		isb();
+
+		/* poll until programmers' model becomes stable */
+		for (count = TIMEOUT_US; (BVAL(trc_readl(ETMSTATR), 1)
+		     != 1) && count > 0; count--)
+			udelay(1);
+		if (count == 0)
+			pr_err_ratelimited("programmers model is not stable\n");
+
+		/* main control and configuration registers */
+		etmdata->state[i++] = trc_readl(ETMCONFIGR);
+		etmdata->state[i++] = trc_readl(ETMEVENTCTL0R);
+		etmdata->state[i++] = trc_readl(ETMEVENTCTL1R);
+		etmdata->state[i++] = trc_readl(ETMSTALLCTLR);
+		etmdata->state[i++] = trc_readl(ETMTSCTLR);
+		etmdata->state[i++] = trc_readl(ETMSYNCPR);
+		etmdata->state[i++] = trc_readl(ETMCCCTLR);
+		etmdata->state[i++] = trc_readl(ETMTRACEIDR);
+		/* filtering control registers */
+		etmdata->state[i++] = trc_readl(ETMVICTLR);
+		etmdata->state[i++] = trc_readl(ETMVIIECTLR);
+		etmdata->state[i++] = trc_readl(ETMVISSCTLR);
+		/* derived resource registers */
+		for (j = 0; j < etmdata->nr_seq_state-1; j++)
+			i = etm_read_ssxr(etmdata->state, i, j);
+		etmdata->state[i++] = trc_readl(ETMSEQRSTEVR);
+		etmdata->state[i++] = trc_readl(ETMSEQSTR);
+		etmdata->state[i++] = trc_readl(ETMEXTINSELR);
+		for (j = 0; j < etmdata->nr_cntr; j++)
+			i = etm_read_crxr(etmdata->state, i, j);
+		/* resource selection registers */
+		for (j = 0; j < etmdata->nr_resource; j++)
+			i = etm_read_rsxr(etmdata->state, i, j + 2);
+		/* comparator registers */
+		for (j = 0; j < etmdata->nr_addr_cmp * 2; j++)
+			i = etm_read_acr(etmdata->state, i, j);
+		for (j = 0; j < etmdata->nr_data_cmp; j++)
+			i = etm_read_dvcr(etmdata->state, i, j);
+		for (j = 0; j < etmdata->nr_ctxid_cmp; j++)
+			i = etm_read_ccvr(etmdata->state, i, j);
+		etmdata->state[i++] = trc_readl(ETMCIDCCTLR0);
+		for (j = 0; j < etmdata->nr_vmid_cmp; j++)
+			i = etm_read_vcvr(etmdata->state, i, j);
+		/* single-shot comparator registers */
+		for (j = 0; j < etmdata->nr_ss_cmp; j++)
+			i = etm_read_sscr(etmdata->state, i, j);
+		/* program ctrl register */
+		etmdata->state[i++] = trc_readl(ETMPRGCTLR);
+
+		/* ensure trace unit is idle to be powered down */
+		for (count = TIMEOUT_US; (BVAL(trc_readl(ETMSTATR), 0)
+		     != 1) && count > 0; count--)
+			udelay(1);
+		if (count == 0)
+			pr_err_ratelimited("timeout waiting for idle state\n");
+
+		atomic_notifier_call_chain(&etm_save_notifier_list, 0, NULL);
+
+		break;
+	default:
+		pr_err_ratelimited("unsupported etm arch %d in %s\n",
+				   etmdata->arch, __func__);
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_clk_disable();
+}
+
+static int etm_write_ssxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		trc_write(state[i++], ETMSEQEVR0);
+		break;
+	case 1:
+		trc_write(state[i++], ETMSEQEVR1);
+		break;
+	case 2:
+		trc_write(state[i++], ETMSEQEVR2);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_crxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		trc_write(state[i++], ETMCNTRLDVR0);
+		trc_write(state[i++], ETMCNTCTLR0);
+		trc_write(state[i++], ETMCNTVR0);
+		break;
+	case 1:
+		trc_write(state[i++], ETMCNTRLDVR1);
+		trc_write(state[i++], ETMCNTCTLR1);
+		trc_write(state[i++], ETMCNTVR1);
+		break;
+	case 2:
+		trc_write(state[i++], ETMCNTRLDVR2);
+		trc_write(state[i++], ETMCNTCTLR2);
+		trc_write(state[i++], ETMCNTVR2);
+		break;
+	case 3:
+		trc_write(state[i++], ETMCNTRLDVR3);
+		trc_write(state[i++], ETMCNTCTLR3);
+		trc_write(state[i++], ETMCNTVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_rsxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 2:
+		trc_write(state[i++], ETMRSCTLR2);
+		break;
+	case 3:
+		trc_write(state[i++], ETMRSCTLR3);
+		break;
+	case 4:
+		trc_write(state[i++], ETMRSCTLR4);
+		break;
+	case 5:
+		trc_write(state[i++], ETMRSCTLR5);
+		break;
+	case 6:
+		trc_write(state[i++], ETMRSCTLR6);
+		break;
+	case 7:
+		trc_write(state[i++], ETMRSCTLR7);
+		break;
+	case 8:
+		trc_write(state[i++], ETMRSCTLR8);
+		break;
+	case 9:
+		trc_write(state[i++], ETMRSCTLR9);
+		break;
+	case 10:
+		trc_write(state[i++], ETMRSCTLR10);
+		break;
+	case 11:
+		trc_write(state[i++], ETMRSCTLR11);
+		break;
+	case 12:
+		trc_write(state[i++], ETMRSCTLR12);
+		break;
+	case 13:
+		trc_write(state[i++], ETMRSCTLR13);
+		break;
+	case 14:
+		trc_write(state[i++], ETMRSCTLR14);
+		break;
+	case 15:
+		trc_write(state[i++], ETMRSCTLR15);
+		break;
+	case 16:
+		trc_write(state[i++], ETMRSCTLR16);
+		break;
+	case 17:
+		trc_write(state[i++], ETMRSCTLR17);
+		break;
+	case 18:
+		trc_write(state[i++], ETMRSCTLR18);
+		break;
+	case 19:
+		trc_write(state[i++], ETMRSCTLR19);
+		break;
+	case 20:
+		trc_write(state[i++], ETMRSCTLR20);
+		break;
+	case 21:
+		trc_write(state[i++], ETMRSCTLR21);
+		break;
+	case 22:
+		trc_write(state[i++], ETMRSCTLR22);
+		break;
+	case 23:
+		trc_write(state[i++], ETMRSCTLR23);
+		break;
+	case 24:
+		trc_write(state[i++], ETMRSCTLR24);
+		break;
+	case 25:
+		trc_write(state[i++], ETMRSCTLR25);
+		break;
+	case 26:
+		trc_write(state[i++], ETMRSCTLR26);
+		break;
+	case 27:
+		trc_write(state[i++], ETMRSCTLR27);
+		break;
+	case 28:
+		trc_write(state[i++], ETMRSCTLR28);
+		break;
+	case 29:
+		trc_write(state[i++], ETMRSCTLR29);
+		break;
+	case 30:
+		trc_write(state[i++], ETMRSCTLR30);
+		break;
+	case 31:
+		trc_write(state[i++], ETMRSCTLR31);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_acr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		trc_write(state[i++], ETMACVR0);
+		trc_write(state[i++], ETMACATR0);
+		break;
+	case 1:
+		trc_write(state[i++], ETMACVR1);
+		trc_write(state[i++], ETMACATR1);
+		break;
+	case 2:
+		trc_write(state[i++], ETMACVR2);
+		trc_write(state[i++], ETMACATR2);
+		break;
+	case 3:
+		trc_write(state[i++], ETMACVR3);
+		trc_write(state[i++], ETMACATR3);
+		break;
+	case 4:
+		trc_write(state[i++], ETMACVR4);
+		trc_write(state[i++], ETMACATR4);
+		break;
+	case 5:
+		trc_write(state[i++], ETMACVR5);
+		trc_write(state[i++], ETMACATR5);
+		break;
+	case 6:
+		trc_write(state[i++], ETMACVR6);
+		trc_write(state[i++], ETMACATR6);
+		break;
+	case 7:
+		trc_write(state[i++], ETMACVR7);
+		trc_write(state[i++], ETMACATR7);
+		break;
+	case 8:
+		trc_write(state[i++], ETMACVR8);
+		trc_write(state[i++], ETMACATR8);
+		break;
+	case 9:
+		trc_write(state[i++], ETMACVR9);
+		trc_write(state[i++], ETMACATR9);
+		break;
+	case 10:
+		trc_write(state[i++], ETMACVR10);
+		trc_write(state[i++], ETMACATR10);
+		break;
+	case 11:
+		trc_write(state[i++], ETMACVR11);
+		trc_write(state[i++], ETMACATR11);
+		break;
+	case 12:
+		trc_write(state[i++], ETMACVR12);
+		trc_write(state[i++], ETMACATR12);
+		break;
+	case 13:
+		trc_write(state[i++], ETMACVR13);
+		trc_write(state[i++], ETMACATR13);
+		break;
+	case 14:
+		trc_write(state[i++], ETMACVR14);
+		trc_write(state[i++], ETMACATR14);
+		break;
+	case 15:
+		trc_write(state[i++], ETMACVR15);
+		trc_write(state[i++], ETMACATR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_dvcr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		trc_write(state[i++], ETMDVCVR0);
+		trc_write(state[i++], ETMDVCMR0);
+		break;
+	case 1:
+		trc_write(state[i++], ETMDVCVR1);
+		trc_write(state[i++], ETMDVCMR1);
+		break;
+	case 2:
+		trc_write(state[i++], ETMDVCVR2);
+		trc_write(state[i++], ETMDVCMR2);
+		break;
+	case 3:
+		trc_write(state[i++], ETMDVCVR3);
+		trc_write(state[i++], ETMDVCMR3);
+		break;
+	case 4:
+		trc_write(state[i++], ETMDVCVR4);
+		trc_write(state[i++], ETMDVCMR4);
+		break;
+	case 5:
+		trc_write(state[i++], ETMDVCVR5);
+		trc_write(state[i++], ETMDVCMR5);
+		break;
+	case 6:
+		trc_write(state[i++], ETMDVCVR6);
+		trc_write(state[i++], ETMDVCMR6);
+		break;
+	case 7:
+		trc_write(state[i++], ETMDVCVR7);
+		trc_write(state[i++], ETMDVCMR7);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_ccvr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		trc_write(state[i++], ETMCIDCVR0);
+		break;
+	case 1:
+		trc_write(state[i++], ETMCIDCVR1);
+		break;
+	case 2:
+		trc_write(state[i++], ETMCIDCVR2);
+		break;
+	case 3:
+		trc_write(state[i++], ETMCIDCVR3);
+		break;
+	case 4:
+		trc_write(state[i++], ETMCIDCVR4);
+		break;
+	case 5:
+		trc_write(state[i++], ETMCIDCVR5);
+		break;
+	case 6:
+		trc_write(state[i++], ETMCIDCVR6);
+		break;
+	case 7:
+		trc_write(state[i++], ETMCIDCVR7);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_vcvr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		trc_write(state[i++], ETMVMIDCVR0);
+		break;
+	case 1:
+		trc_write(state[i++], ETMVMIDCVR1);
+		break;
+	case 2:
+		trc_write(state[i++], ETMVMIDCVR2);
+		break;
+	case 3:
+		trc_write(state[i++], ETMVMIDCVR3);
+		break;
+	case 4:
+		trc_write(state[i++], ETMVMIDCVR4);
+		break;
+	case 5:
+		trc_write(state[i++], ETMVMIDCVR5);
+		break;
+	case 6:
+		trc_write(state[i++], ETMVMIDCVR6);
+		break;
+	case 7:
+		trc_write(state[i++], ETMVMIDCVR7);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_sscr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		trc_write(state[i++], ETMSSCCR0);
+		trc_write(state[i++], ETMSSCSR0);
+		trc_write(state[i++], ETMSSPCICR0);
+		break;
+	case 1:
+		trc_write(state[i++], ETMSSCCR1);
+		trc_write(state[i++], ETMSSCSR1);
+		trc_write(state[i++], ETMSSPCICR1);
+		break;
+	case 2:
+		trc_write(state[i++], ETMSSCCR2);
+		trc_write(state[i++], ETMSSCSR2);
+		trc_write(state[i++], ETMSSPCICR2);
+		break;
+	case 3:
+		trc_write(state[i++], ETMSSCCR3);
+		trc_write(state[i++], ETMSSCSR3);
+		trc_write(state[i++], ETMSSPCICR3);
+		break;
+	case 4:
+		trc_write(state[i++], ETMSSCCR4);
+		trc_write(state[i++], ETMSSCSR4);
+		trc_write(state[i++], ETMSSPCICR4);
+		break;
+	case 5:
+		trc_write(state[i++], ETMSSCCR5);
+		trc_write(state[i++], ETMSSCSR5);
+		trc_write(state[i++], ETMSSPCICR5);
+		break;
+	case 6:
+		trc_write(state[i++], ETMSSCCR6);
+		trc_write(state[i++], ETMSSCSR6);
+		trc_write(state[i++], ETMSSPCICR6);
+		break;
+	case 7:
+		trc_write(state[i++], ETMSSCCR7);
+		trc_write(state[i++], ETMSSCSR7);
+		trc_write(state[i++], ETMSSPCICR7);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static inline void etm_si_restore_state(struct etm_ctx *etmdata)
+{
+	int i, j;
+
+	i = 0;
+
+	/* Vote for ETM power/clock enable */
+	etm_clk_enable();
+
+	switch (etmdata->arch) {
+	case ETM_ARCH_V4_2:
+	case ETM_ARCH_V4:
+		atomic_notifier_call_chain(&etm_restore_notifier_list, 0, NULL);
+
+		/* check OS lock is locked */
+		if (BVAL(trc_readl(ETMOSLSR), 1) != 1) {
+			pr_err_ratelimited("OS lock is unlocked\n");
+			trc_write(0x1, ETMOSLAR);
+			isb();
+		}
+
+		/* main control and configuration registers */
+		trc_write(etmdata->state[i++], ETMCONFIGR);
+		trc_write(etmdata->state[i++], ETMEVENTCTL0R);
+		trc_write(etmdata->state[i++], ETMEVENTCTL1R);
+		trc_write(etmdata->state[i++], ETMSTALLCTLR);
+		trc_write(etmdata->state[i++], ETMTSCTLR);
+		trc_write(etmdata->state[i++], ETMSYNCPR);
+		trc_write(etmdata->state[i++], ETMCCCTLR);
+		trc_write(etmdata->state[i++], ETMTRACEIDR);
+		/* filtering control registers */
+		trc_write(etmdata->state[i++], ETMVICTLR);
+		trc_write(etmdata->state[i++], ETMVIIECTLR);
+		trc_write(etmdata->state[i++], ETMVISSCTLR);
+		/* derived resources registers */
+		for (j = 0; j < etmdata->nr_seq_state-1; j++)
+			i = etm_write_ssxr(etmdata->state, i, j);
+		trc_write(etmdata->state[i++], ETMSEQRSTEVR);
+		trc_write(etmdata->state[i++], ETMSEQSTR);
+		trc_write(etmdata->state[i++], ETMEXTINSELR);
+		for (j = 0; j < etmdata->nr_cntr; j++)
+			i = etm_write_crxr(etmdata->state, i, j);
+		/* resource selection registers */
+		for (j = 0; j < etmdata->nr_resource; j++)
+			i = etm_write_rsxr(etmdata->state, i, j + 2);
+		/* comparator registers */
+		for (j = 0; j < etmdata->nr_addr_cmp * 2; j++)
+			i = etm_write_acr(etmdata->state, i, j);
+		for (j = 0; j < etmdata->nr_data_cmp; j++)
+			i = etm_write_dvcr(etmdata->state, i, j);
+		for (j = 0; j < etmdata->nr_ctxid_cmp; j++)
+			i = etm_write_ccvr(etmdata->state, i, j);
+		trc_write(etmdata->state[i++], ETMCIDCCTLR0);
+		for (j = 0; j < etmdata->nr_vmid_cmp; j++)
+			i = etm_write_vcvr(etmdata->state, i, j);
+		/* single-shot comparator registers */
+		for (j = 0; j < etmdata->nr_ss_cmp; j++)
+			i = etm_write_sscr(etmdata->state, i, j);
+		/* program ctrl register */
+		trc_write(etmdata->state[i++], ETMPRGCTLR);
+
+		isb();
+		trc_write(0x0, ETMOSLAR);
+		break;
+	default:
+		pr_err_ratelimited("unsupported etm arch %d in %s\n",
+				   etmdata->arch,  __func__);
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_clk_disable();
+}
+
+void msm_jtag_etm_save_state(void)
+{
+	int cpu;
+
+	cpu = raw_smp_processor_id();
+
+	if (!etm[cpu] || etm[cpu]->save_restore_disabled)
+		return;
+
+	if (etm[cpu]->save_restore_enabled) {
+		if (etm[cpu]->si_enable)
+			etm_si_save_state(etm[cpu]);
+		else
+			etm_mm_save_state(etm[cpu]);
+	}
+}
+EXPORT_SYMBOL(msm_jtag_etm_save_state);
+
+void msm_jtag_etm_restore_state(void)
+{
+	int cpu;
+
+	cpu = raw_smp_processor_id();
+
+	if (!etm[cpu] || etm[cpu]->save_restore_disabled)
+		return;
+
+	/*
+	 * Check to ensure we attempt to restore only when save
+	 * has been done is accomplished by callee function.
+	 */
+	if (etm[cpu]->save_restore_enabled) {
+		if (etm[cpu]->si_enable)
+			etm_si_restore_state(etm[cpu]);
+		else
+			etm_mm_restore_state(etm[cpu]);
+	}
+}
+EXPORT_SYMBOL(msm_jtag_etm_restore_state);
+
+static inline bool etm_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case ETM_ARCH_V4_2:
+	case ETM_ARCH_V4:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static void etm_os_lock_init(struct etm_ctx *etmdata)
+{
+	uint32_t etmoslsr;
+
+	etmoslsr = etm_readl(etmdata, TRCOSLSR);
+	if ((BVAL(etmoslsr, 0) == 0)  && BVAL(etmoslsr, 3))
+		etmdata->os_lock_present = true;
+	else
+		etmdata->os_lock_present = false;
+}
+
+static void etm_init_arch_data(void *info)
+{
+	uint32_t val;
+	struct etm_ctx  *etmdata = info;
+
+	ETM_UNLOCK(etmdata);
+
+	etm_os_lock_init(etmdata);
+
+	val = etm_readl(etmdata, TRCIDR1);
+	etmdata->arch = BMVAL(val, 4, 11);
+
+	/* number of resources trace unit supports */
+	val = etm_readl(etmdata, TRCIDR4);
+	etmdata->nr_addr_cmp = BMVAL(val, 0, 3);
+	etmdata->nr_data_cmp = BMVAL(val, 4, 7);
+	etmdata->nr_resource = BMVAL(val, 16, 19);
+	etmdata->nr_ss_cmp = BMVAL(val, 20, 23);
+	etmdata->nr_ctxid_cmp = BMVAL(val, 24, 27);
+	etmdata->nr_vmid_cmp = BMVAL(val, 28, 31);
+
+	val = etm_readl(etmdata, TRCIDR5);
+	etmdata->nr_seq_state = BMVAL(val, 25, 27);
+	etmdata->nr_cntr = BMVAL(val, 28, 30);
+
+	ETM_LOCK(etmdata);
+}
+
+static int jtag_mm_etm_starting(unsigned int cpu)
+{
+	if (!etm[cpu])
+		return 0;
+
+	spin_lock(&etm[cpu]->spinlock);
+	if (!etm[cpu]->init) {
+		etm_init_arch_data(etm[cpu]);
+		etm[cpu]->init = true;
+	}
+	spin_unlock(&etm[cpu]->spinlock);
+
+	return 0;
+}
+
+static int jtag_mm_etm_online(unsigned int cpu)
+{
+	if (!etm[cpu])
+		return 0;
+
+	mutex_lock(&etm[cpu]->mutex);
+	if (etm[cpu]->enable) {
+		mutex_unlock(&etm[cpu]->mutex);
+		return 0;
+	}
+	if (etm_arch_supported(etm[cpu]->arch)) {
+		if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) <
+		    TZ_DBG_ETM_VER)
+			etm[cpu]->save_restore_enabled = true;
+		else
+			pr_info("etm save-restore supported by TZ\n");
+	} else
+		pr_info("etm arch %u not supported\n", etm[cpu]->arch);
+	etm[cpu]->enable = true;
+	mutex_unlock(&etm[cpu]->mutex);
+
+	return 0;
+}
+
+static bool skip_etm_save_restore(void)
+{
+	uint32_t id;
+	uint32_t version;
+
+	id = socinfo_get_id();
+	version = socinfo_get_version();
+
+	if (id == HW_SOC_ID_M8953 && SOCINFO_VERSION_MAJOR(version) == 1 &&
+	    SOCINFO_VERSION_MINOR(version) == 0)
+		return true;
+
+	return false;
+}
+
+static int jtag_mm_etm_probe(struct platform_device *pdev, uint32_t cpu)
+{
+	struct etm_ctx *etmdata;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	/* Allocate memory per cpu */
+	etmdata = devm_kzalloc(dev, sizeof(struct etm_ctx), GFP_KERNEL);
+	if (!etmdata)
+		return -ENOMEM;
+
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "etm-base");
+	if (!res)
+		return -ENODEV;
+
+	etmdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!etmdata->base)
+		return -EINVAL;
+
+	etmdata->si_enable = of_property_read_bool(pdev->dev.of_node,
+						   "qcom,si-enable");
+	etmdata->save_restore_disabled = of_property_read_bool(
+					 pdev->dev.of_node,
+					 "qcom,save-restore-disable");
+
+	if (skip_etm_save_restore())
+		etmdata->save_restore_disabled = 1;
+
+	/* Allocate etm state save space per core */
+	etmdata->state = devm_kzalloc(dev,
+				      MAX_ETM_STATE_SIZE * sizeof(uint64_t),
+				      GFP_KERNEL);
+	if (!etmdata->state)
+		return -ENOMEM;
+
+	spin_lock_init(&etmdata->spinlock);
+	mutex_init(&etmdata->mutex);
+
+	if (cnt++ == 0) {
+		cpuhp_setup_state_nocalls(CPUHP_AP_ARM_MM_CORESIGHT4_STARTING,
+					  "AP_ARM_CORESIGHT4_STARTING",
+					  jtag_mm_etm_starting, NULL);
+		ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
+						"AP_ARM_CORESIGHT4_ONLINE",
+						jtag_mm_etm_online, NULL);
+	}
+
+	get_online_cpus();
+
+	if (!smp_call_function_single(cpu, etm_init_arch_data, etmdata,
+				      1))
+		etmdata->init = true;
+
+	etm[cpu] = etmdata;
+
+	put_online_cpus();
+
+	mutex_lock(&etmdata->mutex);
+	if (etmdata->init && !etmdata->enable) {
+		if (etm_arch_supported(etmdata->arch)) {
+			if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) <
+			    TZ_DBG_ETM_VER)
+				etmdata->save_restore_enabled = true;
+			else
+				pr_info("etm save-restore supported by TZ\n");
+		} else
+			pr_info("etm arch %u not supported\n", etmdata->arch);
+		etmdata->enable = true;
+	}
+	mutex_unlock(&etmdata->mutex);
+	return 0;
+}
+
+static int jtag_mm_probe(struct platform_device *pdev)
+{
+	int ret, i, cpu = -1;
+	struct device *dev = &pdev->dev;
+	struct device_node *cpu_node;
+
+	cpu_node = of_parse_phandle(pdev->dev.of_node,
+				    "qcom,coresight-jtagmm-cpu", 0);
+	if (!cpu_node) {
+		dev_err(dev, "Jtag-mm cpu handle not specified\n");
+		return -ENODEV;
+	}
+	for_each_possible_cpu(i) {
+		if (cpu_node == of_get_cpu_node(i, NULL)) {
+			cpu = i;
+			break;
+		}
+	}
+
+	if (cpu == -1) {
+		dev_err(dev, "invalid Jtag-mm cpu handle\n");
+		return -EINVAL;
+	}
+
+	clock[cpu] = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(clock[cpu])) {
+		ret = PTR_ERR(clock[cpu]);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(clock[cpu]);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, clock[cpu]);
+
+	ret  = jtag_mm_etm_probe(pdev, cpu);
+	if (ret)
+		clk_disable_unprepare(clock[cpu]);
+
+	return ret;
+}
+
+static void jtag_mm_etm_remove(void)
+{
+	cpuhp_remove_state_nocalls(CPUHP_AP_ARM_MM_CORESIGHT4_STARTING);
+}
+
+static int jtag_mm_remove(struct platform_device *pdev)
+{
+	struct clk *clock = platform_get_drvdata(pdev);
+
+	if (--cnt == 0)
+		jtag_mm_etm_remove();
+	clk_disable_unprepare(clock);
+	return 0;
+}
+
+static const struct of_device_id msm_qdss_mm_match[] = {
+	{ .compatible = "qcom,jtagv8-mm"},
+	{}
+};
+
+static struct platform_driver jtag_mm_driver = {
+	.probe          = jtag_mm_probe,
+	.remove         = jtag_mm_remove,
+	.driver         = {
+		.name   = "msm-jtagv8-mm",
+		.owner	= THIS_MODULE,
+		.of_match_table	= msm_qdss_mm_match,
+		},
+};
+
+static int __init jtag_mm_init(void)
+{
+	return platform_driver_register(&jtag_mm_driver);
+}
+module_init(jtag_mm_init);
+
+static void __exit jtag_mm_exit(void)
+{
+	platform_driver_unregister(&jtag_mm_driver);
+}
+module_exit(jtag_mm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight DEBUGv8 and ETMv4 save-restore driver");
diff --git a/drivers/soc/qcom/jtagv8.c b/drivers/soc/qcom/jtagv8.c
new file mode 100644
index 0000000..94dffd1
--- /dev/null
+++ b/drivers/soc/qcom/jtagv8.c
@@ -0,0 +1,1000 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/cpu_pm.h>
+#include <linux/export.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/coresight.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/jtag.h>
+#ifdef CONFIG_ARM64
+#include <asm/debugv8.h>
+#else
+#include <asm/hardware/debugv8.h>
+#endif
+
+#define TIMEOUT_US		(100)
+
+#define BM(lsb, msb)		((BIT(msb) - BIT(lsb)) + BIT(msb))
+#define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
+#define BVAL(val, n)		((val & BIT(n)) >> n)
+
+#ifdef CONFIG_ARM64
+#define ARM_DEBUG_ARCH_V8_8	(0x8)
+#define ARM_DEBUG_ARCH_V8	(0x6)
+#endif
+
+#define MAX_DBG_REGS		(66)
+#define MAX_DBG_STATE_SIZE	(MAX_DBG_REGS * num_possible_cpus())
+
+#define OSLOCK_MAGIC		(0xC5ACCE55)
+#define TZ_DBG_ETM_FEAT_ID	(0x8)
+#define TZ_DBG_ETM_VER		(0x400000)
+
+static uint32_t msm_jtag_save_cntr[NR_CPUS];
+static uint32_t msm_jtag_restore_cntr[NR_CPUS];
+
+/* access debug registers using system instructions */
+struct dbg_cpu_ctx {
+	uint32_t		*state;
+};
+
+struct dbg_ctx {
+	uint8_t			arch;
+	bool			save_restore_enabled;
+	uint8_t			nr_wp;
+	uint8_t			nr_bp;
+	uint8_t			nr_ctx_cmp;
+#ifdef CONFIG_ARM64
+	uint64_t		*state;
+#else
+	uint32_t		*state;
+#endif
+};
+
+static struct dbg_ctx dbg;
+static struct notifier_block jtag_cpu_pm_notifier;
+
+#ifdef CONFIG_ARM64
+static int dbg_read_arch64_bxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = dbg_readq(DBGBVR0_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR0_EL1);
+		break;
+	case 1:
+		state[i++] = dbg_readq(DBGBVR1_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR1_EL1);
+		break;
+	case 2:
+		state[i++] = dbg_readq(DBGBVR2_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR2_EL1);
+		break;
+	case 3:
+		state[i++] = dbg_readq(DBGBVR3_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR3_EL1);
+		break;
+	case 4:
+		state[i++] = dbg_readq(DBGBVR4_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR4_EL1);
+		break;
+	case 5:
+		state[i++] = dbg_readq(DBGBVR5_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR5_EL1);
+		break;
+	case 6:
+		state[i++] = dbg_readq(DBGBVR6_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR6_EL1);
+		break;
+	case 7:
+		state[i++] = dbg_readq(DBGBVR7_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR7_EL1);
+		break;
+	case 8:
+		state[i++] = dbg_readq(DBGBVR8_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR8_EL1);
+		break;
+	case 9:
+		state[i++] = dbg_readq(DBGBVR9_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR9_EL1);
+		break;
+	case 10:
+		state[i++] = dbg_readq(DBGBVR10_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR10_EL1);
+		break;
+	case 11:
+		state[i++] = dbg_readq(DBGBVR11_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR11_EL1);
+		break;
+	case 12:
+		state[i++] = dbg_readq(DBGBVR12_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR12_EL1);
+		break;
+	case 13:
+		state[i++] = dbg_readq(DBGBVR13_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR13_EL1);
+		break;
+	case 14:
+		state[i++] = dbg_readq(DBGBVR14_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR14_EL1);
+		break;
+	case 15:
+		state[i++] = dbg_readq(DBGBVR15_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGBCR15_EL1);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_write_arch64_bxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		dbg_write(state[i++], DBGBVR0_EL1);
+		dbg_write(state[i++], DBGBCR0_EL1);
+		break;
+	case 1:
+		dbg_write(state[i++], DBGBVR1_EL1);
+		dbg_write(state[i++], DBGBCR1_EL1);
+		break;
+	case 2:
+		dbg_write(state[i++], DBGBVR2_EL1);
+		dbg_write(state[i++], DBGBCR2_EL1);
+		break;
+	case 3:
+		dbg_write(state[i++], DBGBVR3_EL1);
+		dbg_write(state[i++], DBGBCR3_EL1);
+		break;
+	case 4:
+		dbg_write(state[i++], DBGBVR4_EL1);
+		dbg_write(state[i++], DBGBCR4_EL1);
+		break;
+	case 5:
+		dbg_write(state[i++], DBGBVR5_EL1);
+		dbg_write(state[i++], DBGBCR5_EL1);
+		break;
+	case 6:
+		dbg_write(state[i++], DBGBVR6_EL1);
+		dbg_write(state[i++], DBGBCR6_EL1);
+		break;
+	case 7:
+		dbg_write(state[i++], DBGBVR7_EL1);
+		dbg_write(state[i++], DBGBCR7_EL1);
+		break;
+	case 8:
+		dbg_write(state[i++], DBGBVR8_EL1);
+		dbg_write(state[i++], DBGBCR8_EL1);
+		break;
+	case 9:
+		dbg_write(state[i++], DBGBVR9_EL1);
+		dbg_write(state[i++], DBGBCR9_EL1);
+		break;
+	case 10:
+		dbg_write(state[i++], DBGBVR10_EL1);
+		dbg_write(state[i++], DBGBCR10_EL1);
+		break;
+	case 11:
+		dbg_write(state[i++], DBGBVR11_EL1);
+		dbg_write(state[i++], DBGBCR11_EL1);
+		break;
+	case 12:
+		dbg_write(state[i++], DBGBVR12_EL1);
+		dbg_write(state[i++], DBGBCR12_EL1);
+		break;
+	case 13:
+		dbg_write(state[i++], DBGBVR13_EL1);
+		dbg_write(state[i++], DBGBCR13_EL1);
+		break;
+	case 14:
+		dbg_write(state[i++], DBGBVR14_EL1);
+		dbg_write(state[i++], DBGBCR14_EL1);
+		break;
+	case 15:
+		dbg_write(state[i++], DBGBVR15_EL1);
+		dbg_write(state[i++], DBGBCR15_EL1);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_read_arch64_wxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = dbg_readq(DBGWVR0_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR0_EL1);
+		break;
+	case 1:
+		state[i++] = dbg_readq(DBGWVR1_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR1_EL1);
+		break;
+	case 2:
+		state[i++] = dbg_readq(DBGWVR2_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR2_EL1);
+		break;
+	case 3:
+		state[i++] = dbg_readq(DBGWVR3_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR3_EL1);
+		break;
+	case 4:
+		state[i++] = dbg_readq(DBGWVR4_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR4_EL1);
+		break;
+	case 5:
+		state[i++] = dbg_readq(DBGWVR5_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR5_EL1);
+		break;
+	case 6:
+		state[i++] = dbg_readq(DBGWVR6_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR6_EL1);
+		break;
+	case 7:
+		state[i++] = dbg_readq(DBGWVR7_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR7_EL1);
+		break;
+	case 8:
+		state[i++] = dbg_readq(DBGWVR8_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR8_EL1);
+		break;
+	case 9:
+		state[i++] = dbg_readq(DBGWVR9_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR9_EL1);
+		break;
+	case 10:
+		state[i++] = dbg_readq(DBGWVR10_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR10_EL1);
+		break;
+	case 11:
+		state[i++] = dbg_readq(DBGWVR11_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR11_EL1);
+		break;
+	case 12:
+		state[i++] = dbg_readq(DBGWVR12_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR12_EL1);
+		break;
+	case 13:
+		state[i++] = dbg_readq(DBGWVR13_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR13_EL1);
+		break;
+	case 14:
+		state[i++] = dbg_readq(DBGWVR14_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR14_EL1);
+		break;
+	case 15:
+		state[i++] = dbg_readq(DBGWVR15_EL1);
+		state[i++] = (uint64_t)dbg_readl(DBGWCR15_EL1);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_write_arch64_wxr(uint64_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		dbg_write(state[i++], DBGWVR0_EL1);
+		dbg_write(state[i++], DBGWCR0_EL1);
+		break;
+	case 1:
+		dbg_write(state[i++], DBGWVR1_EL1);
+		dbg_write(state[i++], DBGWCR1_EL1);
+		break;
+	case 2:
+		dbg_write(state[i++], DBGWVR2_EL1);
+		dbg_write(state[i++], DBGWCR2_EL1);
+		break;
+	case 3:
+		dbg_write(state[i++], DBGWVR3_EL1);
+		dbg_write(state[i++], DBGWCR3_EL1);
+		break;
+	case 4:
+		dbg_write(state[i++], DBGWVR4_EL1);
+		dbg_write(state[i++], DBGWCR4_EL1);
+		break;
+	case 5:
+		dbg_write(state[i++], DBGWVR5_EL1);
+		dbg_write(state[i++], DBGWCR5_EL1);
+		break;
+	case 6:
+		dbg_write(state[i++], DBGWVR0_EL1);
+		dbg_write(state[i++], DBGWCR6_EL1);
+		break;
+	case 7:
+		dbg_write(state[i++], DBGWVR7_EL1);
+		dbg_write(state[i++], DBGWCR7_EL1);
+		break;
+	case 8:
+		dbg_write(state[i++], DBGWVR8_EL1);
+		dbg_write(state[i++], DBGWCR8_EL1);
+		break;
+	case 9:
+		dbg_write(state[i++], DBGWVR9_EL1);
+		dbg_write(state[i++], DBGWCR9_EL1);
+		break;
+	case 10:
+		dbg_write(state[i++], DBGWVR10_EL1);
+		dbg_write(state[i++], DBGWCR10_EL1);
+		break;
+	case 11:
+		dbg_write(state[i++], DBGWVR11_EL1);
+		dbg_write(state[i++], DBGWCR11_EL1);
+		break;
+	case 12:
+		dbg_write(state[i++], DBGWVR12_EL1);
+		dbg_write(state[i++], DBGWCR12_EL1);
+		break;
+	case 13:
+		dbg_write(state[i++], DBGWVR13_EL1);
+		dbg_write(state[i++], DBGWCR13_EL1);
+		break;
+	case 14:
+		dbg_write(state[i++], DBGWVR14_EL1);
+		dbg_write(state[i++], DBGWCR14_EL1);
+		break;
+	case 15:
+		dbg_write(state[i++], DBGWVR15_EL1);
+		dbg_write(state[i++], DBGWCR15_EL1);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static inline void dbg_save_state(int cpu)
+{
+	int i, j;
+
+	i = cpu * MAX_DBG_REGS;
+
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V8_8:
+	case ARM_DEBUG_ARCH_V8:
+		/* Set OS Lock to inform the debugger that the OS is in the
+		 * process of saving debug registers. It prevents accidental
+		 * modification of the debug regs by the external debugger.
+		 */
+		dbg_write(0x1, OSLAR_EL1);
+		/* Ensure OS lock is set before proceeding */
+		isb();
+
+		dbg.state[i++] =  (uint32_t)dbg_readl(MDSCR_EL1);
+		for (j = 0; j < dbg.nr_bp; j++)
+			i = dbg_read_arch64_bxr((uint64_t *)dbg.state, i, j);
+		for (j = 0; j < dbg.nr_wp; j++)
+			i = dbg_read_arch64_wxr((uint64_t *)dbg.state, i, j);
+		dbg.state[i++] =  (uint32_t)dbg_readl(MDCCINT_EL1);
+		dbg.state[i++] =  (uint32_t)dbg_readl(DBGCLAIMCLR_EL1);
+		dbg.state[i++] =  (uint32_t)dbg_readl(OSECCR_EL1);
+		dbg.state[i++] =  (uint32_t)dbg_readl(OSDTRRX_EL1);
+		dbg.state[i++] =  (uint32_t)dbg_readl(OSDTRTX_EL1);
+
+		/* Set the OS double lock */
+		isb();
+		dbg_write(0x1, OSDLR_EL1);
+		isb();
+		break;
+	default:
+		pr_err_ratelimited("unsupported dbg arch %d in %s\n", dbg.arch,
+				   __func__);
+	}
+}
+
+static inline void dbg_restore_state(int cpu)
+{
+	int i, j;
+
+	i = cpu * MAX_DBG_REGS;
+
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V8_8:
+	case ARM_DEBUG_ARCH_V8:
+		/* Clear the OS double lock */
+		isb();
+		dbg_write(0x0, OSDLR_EL1);
+		isb();
+
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is included to ensure it is set.
+		 */
+		dbg_write(0x1, OSLAR_EL1);
+		isb();
+
+		dbg_write(dbg.state[i++], MDSCR_EL1);
+		for (j = 0; j < dbg.nr_bp; j++)
+			i = dbg_write_arch64_bxr((uint64_t *)dbg.state, i, j);
+		for (j = 0; j < dbg.nr_wp; j++)
+			i = dbg_write_arch64_wxr((uint64_t *)dbg.state, i, j);
+		dbg_write(dbg.state[i++], MDCCINT_EL1);
+		dbg_write(dbg.state[i++], DBGCLAIMSET_EL1);
+		dbg_write(dbg.state[i++], OSECCR_EL1);
+		dbg_write(dbg.state[i++], OSDTRRX_EL1);
+		dbg_write(dbg.state[i++], OSDTRTX_EL1);
+
+		isb();
+		dbg_write(0x0, OSLAR_EL1);
+		isb();
+		break;
+	default:
+		pr_err_ratelimited("unsupported dbg arch %d in %s\n", dbg.arch,
+				   __func__);
+	}
+}
+
+static void dbg_init_arch_data(void)
+{
+	uint64_t dbgfr;
+
+	/* This will run on core0 so use it to populate parameters */
+	dbgfr = dbg_readq(ID_AA64DFR0_EL1);
+	dbg.arch = BMVAL(dbgfr, 0, 3);
+	dbg.nr_bp = BMVAL(dbgfr, 12, 15) + 1;
+	dbg.nr_wp = BMVAL(dbgfr, 20, 23) + 1;
+	dbg.nr_ctx_cmp = BMVAL(dbgfr, 28, 31) + 1;
+}
+#else
+
+static int dbg_read_arch32_bxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = dbg_read(DBGBVR0);
+		state[i++] = dbg_read(DBGBCR0);
+		break;
+	case 1:
+		state[i++] = dbg_read(DBGBVR1);
+		state[i++] = dbg_read(DBGBCR1);
+		break;
+	case 2:
+		state[i++] = dbg_read(DBGBVR2);
+		state[i++] = dbg_read(DBGBCR2);
+		break;
+	case 3:
+		state[i++] = dbg_read(DBGBVR3);
+		state[i++] = dbg_read(DBGBCR3);
+		break;
+	case 4:
+		state[i++] = dbg_read(DBGBVR4);
+		state[i++] = dbg_read(DBGBCR4);
+		break;
+	case 5:
+		state[i++] = dbg_read(DBGBVR5);
+		state[i++] = dbg_read(DBGBCR5);
+		break;
+	case 6:
+		state[i++] = dbg_read(DBGBVR6);
+		state[i++] = dbg_read(DBGBCR6);
+		break;
+	case 7:
+		state[i++] = dbg_read(DBGBVR7);
+		state[i++] = dbg_read(DBGBCR7);
+		break;
+	case 8:
+		state[i++] = dbg_read(DBGBVR8);
+		state[i++] = dbg_read(DBGBCR8);
+		break;
+	case 9:
+		state[i++] = dbg_read(DBGBVR9);
+		state[i++] = dbg_read(DBGBCR9);
+		break;
+	case 10:
+		state[i++] = dbg_read(DBGBVR10);
+		state[i++] = dbg_read(DBGBCR10);
+		break;
+	case 11:
+		state[i++] = dbg_read(DBGBVR11);
+		state[i++] = dbg_read(DBGBCR11);
+		break;
+	case 12:
+		state[i++] = dbg_read(DBGBVR12);
+		state[i++] = dbg_read(DBGBCR12);
+		break;
+	case 13:
+		state[i++] = dbg_read(DBGBVR13);
+		state[i++] = dbg_read(DBGBCR13);
+		break;
+	case 14:
+		state[i++] = dbg_read(DBGBVR14);
+		state[i++] = dbg_read(DBGBCR14);
+		break;
+	case 15:
+		state[i++] = dbg_read(DBGBVR15);
+		state[i++] = dbg_read(DBGBCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_write_arch32_bxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		dbg_write(state[i++], DBGBVR0);
+		dbg_write(state[i++], DBGBCR0);
+		break;
+	case 1:
+		dbg_write(state[i++], DBGBVR1);
+		dbg_write(state[i++], DBGBCR1);
+		break;
+	case 2:
+		dbg_write(state[i++], DBGBVR2);
+		dbg_write(state[i++], DBGBCR2);
+		break;
+	case 3:
+		dbg_write(state[i++], DBGBVR3);
+		dbg_write(state[i++], DBGBCR3);
+		break;
+	case 4:
+		dbg_write(state[i++], DBGBVR4);
+		dbg_write(state[i++], DBGBCR4);
+		break;
+	case 5:
+		dbg_write(state[i++], DBGBVR5);
+		dbg_write(state[i++], DBGBCR5);
+		break;
+	case 6:
+		dbg_write(state[i++], DBGBVR6);
+		dbg_write(state[i++], DBGBCR6);
+		break;
+	case 7:
+		dbg_write(state[i++], DBGBVR7);
+		dbg_write(state[i++], DBGBCR7);
+		break;
+	case 8:
+		dbg_write(state[i++], DBGBVR8);
+		dbg_write(state[i++], DBGBCR8);
+		break;
+	case 9:
+		dbg_write(state[i++], DBGBVR9);
+		dbg_write(state[i++], DBGBCR9);
+		break;
+	case 10:
+		dbg_write(state[i++], DBGBVR10);
+		dbg_write(state[i++], DBGBCR10);
+		break;
+	case 11:
+		dbg_write(state[i++], DBGBVR11);
+		dbg_write(state[i++], DBGBCR11);
+		break;
+	case 12:
+		dbg_write(state[i++], DBGBVR12);
+		dbg_write(state[i++], DBGBCR12);
+		break;
+	case 13:
+		dbg_write(state[i++], DBGBVR13);
+		dbg_write(state[i++], DBGBCR13);
+		break;
+	case 14:
+		dbg_write(state[i++], DBGBVR14);
+		dbg_write(state[i++], DBGBCR14);
+		break;
+	case 15:
+		dbg_write(state[i++], DBGBVR15);
+		dbg_write(state[i++], DBGBCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_read_arch32_wxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = dbg_read(DBGWVR0);
+		state[i++] = dbg_read(DBGWCR0);
+		break;
+	case 1:
+		state[i++] = dbg_read(DBGWVR1);
+		state[i++] = dbg_read(DBGWCR1);
+		break;
+	case 2:
+		state[i++] = dbg_read(DBGWVR2);
+		state[i++] = dbg_read(DBGWCR2);
+		break;
+	case 3:
+		state[i++] = dbg_read(DBGWVR3);
+		state[i++] = dbg_read(DBGWCR3);
+		break;
+	case 4:
+		state[i++] = dbg_read(DBGWVR4);
+		state[i++] = dbg_read(DBGWCR4);
+		break;
+	case 5:
+		state[i++] = dbg_read(DBGWVR5);
+		state[i++] = dbg_read(DBGWCR5);
+		break;
+	case 6:
+		state[i++] = dbg_read(DBGWVR6);
+		state[i++] = dbg_read(DBGWCR6);
+		break;
+	case 7:
+		state[i++] = dbg_read(DBGWVR7);
+		state[i++] = dbg_read(DBGWCR7);
+		break;
+	case 8:
+		state[i++] = dbg_read(DBGWVR8);
+		state[i++] = dbg_read(DBGWCR8);
+		break;
+	case 9:
+		state[i++] = dbg_read(DBGWVR9);
+		state[i++] = dbg_read(DBGWCR9);
+		break;
+	case 10:
+		state[i++] = dbg_read(DBGWVR10);
+		state[i++] = dbg_read(DBGWCR10);
+		break;
+	case 11:
+		state[i++] = dbg_read(DBGWVR11);
+		state[i++] = dbg_read(DBGWCR11);
+		break;
+	case 12:
+		state[i++] = dbg_read(DBGWVR12);
+		state[i++] = dbg_read(DBGWCR12);
+		break;
+	case 13:
+		state[i++] = dbg_read(DBGWVR13);
+		state[i++] = dbg_read(DBGWCR13);
+		break;
+	case 14:
+		state[i++] = dbg_read(DBGWVR14);
+		state[i++] = dbg_read(DBGWCR14);
+		break;
+	case 15:
+		state[i++] = dbg_read(DBGWVR15);
+		state[i++] = dbg_read(DBGWCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_write_arch32_wxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		dbg_write(state[i++], DBGWVR0);
+		dbg_write(state[i++], DBGWCR0);
+		break;
+	case 1:
+		dbg_write(state[i++], DBGWVR1);
+		dbg_write(state[i++], DBGWCR1);
+		break;
+	case 2:
+		dbg_write(state[i++], DBGWVR2);
+		dbg_write(state[i++], DBGWCR2);
+		break;
+	case 3:
+		dbg_write(state[i++], DBGWVR3);
+		dbg_write(state[i++], DBGWCR3);
+		break;
+	case 4:
+		dbg_write(state[i++], DBGWVR4);
+		dbg_write(state[i++], DBGWCR4);
+		break;
+	case 5:
+		dbg_write(state[i++], DBGWVR5);
+		dbg_write(state[i++], DBGWCR5);
+		break;
+	case 6:
+		dbg_write(state[i++], DBGWVR6);
+		dbg_write(state[i++], DBGWCR6);
+		break;
+	case 7:
+		dbg_write(state[i++], DBGWVR7);
+		dbg_write(state[i++], DBGWCR7);
+		break;
+	case 8:
+		dbg_write(state[i++], DBGWVR8);
+		dbg_write(state[i++], DBGWCR8);
+		break;
+	case 9:
+		dbg_write(state[i++], DBGWVR9);
+		dbg_write(state[i++], DBGWCR9);
+		break;
+	case 10:
+		dbg_write(state[i++], DBGWVR10);
+		dbg_write(state[i++], DBGWCR10);
+		break;
+	case 11:
+		dbg_write(state[i++], DBGWVR11);
+		dbg_write(state[i++], DBGWCR11);
+		break;
+	case 12:
+		dbg_write(state[i++], DBGWVR12);
+		dbg_write(state[i++], DBGWCR12);
+		break;
+	case 13:
+		dbg_write(state[i++], DBGWVR13);
+		dbg_write(state[i++], DBGWCR13);
+		break;
+	case 14:
+		dbg_write(state[i++], DBGWVR14);
+		dbg_write(state[i++], DBGWCR14);
+		break;
+	case 15:
+		dbg_write(state[i++], DBGWVR15);
+		dbg_write(state[i++], DBGWCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static inline void dbg_save_state(int cpu)
+{
+	int i, j;
+
+	i = cpu * MAX_DBG_REGS;
+
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V8_8:
+	case ARM_DEBUG_ARCH_V8:
+		/* Set OS Lock to inform the debugger that the OS is in the
+		 * process of saving debug registers. It prevents accidental
+		 * modification of the debug regs by the external debugger.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		/* Ensure OS lock is set before proceeding */
+		isb();
+
+		dbg.state[i++] =  dbg_read(DBGDSCRext);
+		for (j = 0; j < dbg.nr_bp; j++)
+			i = dbg_read_arch32_bxr(dbg.state, i, j);
+		for (j = 0; j < dbg.nr_wp; j++)
+			i = dbg_read_arch32_wxr(dbg.state, i, j);
+		dbg.state[i++] =  dbg_read(DBGDCCINT);
+		dbg.state[i++] =  dbg_read(DBGCLAIMCLR);
+		dbg.state[i++] =  dbg_read(DBGOSECCR);
+		dbg.state[i++] =  dbg_read(DBGDTRRXext);
+		dbg.state[i++] =  dbg_read(DBGDTRTXext);
+
+		/* Set the OS double lock */
+		isb();
+		dbg_write(0x1, DBGOSDLR);
+		isb();
+		break;
+	default:
+		pr_err_ratelimited("unsupported dbg arch %d in %s\n", dbg.arch,
+				   __func__);
+	}
+}
+
+static inline void dbg_restore_state(int cpu)
+{
+	int i, j;
+
+	i = cpu * MAX_DBG_REGS;
+
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V8_8:
+	case ARM_DEBUG_ARCH_V8:
+		/* Clear the OS double lock */
+		isb();
+		dbg_write(0x0, DBGOSDLR);
+		isb();
+
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is included to ensure it is set.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		dbg_write(dbg.state[i++], DBGDSCRext);
+		for (j = 0; j < dbg.nr_bp; j++)
+			i = dbg_write_arch32_bxr((uint32_t *)dbg.state, i, j);
+		for (j = 0; j < dbg.nr_wp; j++)
+			i = dbg_write_arch32_wxr((uint32_t *)dbg.state, i, j);
+		dbg_write(dbg.state[i++], DBGDCCINT);
+		dbg_write(dbg.state[i++], DBGCLAIMSET);
+		dbg_write(dbg.state[i++], DBGOSECCR);
+		dbg_write(dbg.state[i++], DBGDTRRXext);
+		dbg_write(dbg.state[i++], DBGDTRTXext);
+
+		isb();
+		dbg_write(0x0, DBGOSLAR);
+		isb();
+		break;
+	default:
+		pr_err_ratelimited("unsupported dbg arch %d in %s\n", dbg.arch,
+				   __func__);
+	}
+}
+
+static void dbg_init_arch_data(void)
+{
+	uint32_t dbgdidr;
+
+	/* This will run on core0 so use it to populate parameters */
+	dbgdidr = dbg_read(DBGDIDR);
+	dbg.arch = BMVAL(dbgdidr, 16, 19);
+	dbg.nr_ctx_cmp = BMVAL(dbgdidr, 20, 23) + 1;
+	dbg.nr_bp = BMVAL(dbgdidr, 24, 27) + 1;
+	dbg.nr_wp = BMVAL(dbgdidr, 28, 31) + 1;
+}
+#endif
+
+/*
+ * msm_jtag_save_state - save debug registers
+ *
+ * Debug registers are saved before power collapse if debug
+ * architecture is supported respectively and TZ isn't supporting
+ * the save and restore of debug registers.
+ *
+ * CONTEXT:
+ * Called with preemption off and interrupts locked from:
+ * 1. per_cpu idle thread context for idle power collapses
+ * or
+ * 2. per_cpu idle thread context for hotplug/suspend power collapse
+ *    for nonboot cpus
+ * or
+ * 3. suspend thread context for suspend power collapse for core0
+ *
+ * In all cases we will run on the same cpu for the entire duration.
+ */
+void msm_jtag_save_state(void)
+{
+	int cpu;
+
+	cpu = raw_smp_processor_id();
+
+	msm_jtag_save_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
+	msm_jtag_etm_save_state();
+	if (dbg.save_restore_enabled)
+		dbg_save_state(cpu);
+}
+EXPORT_SYMBOL(msm_jtag_save_state);
+
+void msm_jtag_restore_state(void)
+{
+	int cpu;
+
+	cpu = raw_smp_processor_id();
+
+	/* Attempt restore only if save has been done. If power collapse
+	 * is disabled, hotplug off of non-boot core will result in WFI
+	 * and hence msm_jtag_save_state will not occur. Subsequently,
+	 * during hotplug on of non-boot core when msm_jtag_restore_state
+	 * is called via msm_platform_secondary_init, this check will help
+	 * bail us out without restoring.
+	 */
+	if (msm_jtag_save_cntr[cpu] == msm_jtag_restore_cntr[cpu])
+		return;
+	else if (msm_jtag_save_cntr[cpu] != msm_jtag_restore_cntr[cpu] + 1)
+		pr_err_ratelimited("jtag imbalance, save:%lu, restore:%lu\n",
+				   (unsigned long)msm_jtag_save_cntr[cpu],
+				   (unsigned long)msm_jtag_restore_cntr[cpu]);
+
+	msm_jtag_restore_cntr[cpu]++;
+	/* ensure counter is updated before moving forward */
+	mb();
+
+	if (dbg.save_restore_enabled)
+		dbg_restore_state(cpu);
+	msm_jtag_etm_restore_state();
+}
+EXPORT_SYMBOL(msm_jtag_restore_state);
+
+static inline bool dbg_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case ARM_DEBUG_ARCH_V8_8:
+	case ARM_DEBUG_ARCH_V8:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static int jtag_hotcpu_save_callback(unsigned int cpu)
+{
+	msm_jtag_save_state();
+	return 0;
+}
+
+static int jtag_hotcpu_restore_callback(unsigned int cpu)
+{
+	msm_jtag_restore_state();
+	return 0;
+}
+
+static int jtag_cpu_pm_callback(struct notifier_block *nfb,
+				unsigned long action, void *hcpu)
+{
+	switch (action) {
+	case CPU_PM_ENTER:
+		msm_jtag_save_state();
+		break;
+	case CPU_PM_ENTER_FAILED:
+	case CPU_PM_EXIT:
+		msm_jtag_restore_state();
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block jtag_cpu_pm_notifier = {
+	.notifier_call = jtag_cpu_pm_callback,
+};
+
+static int __init msm_jtag_dbg_init(void)
+{
+	int ret;
+
+	/* This will run on core0 so use it to populate parameters */
+	dbg_init_arch_data();
+
+	if (dbg_arch_supported(dbg.arch)) {
+		if (scm_get_feat_version(TZ_DBG_ETM_FEAT_ID) < TZ_DBG_ETM_VER) {
+			dbg.save_restore_enabled = true;
+		} else {
+			pr_info("dbg save-restore supported by TZ\n");
+			goto dbg_out;
+		}
+	} else {
+		pr_info("dbg arch %u not supported\n", dbg.arch);
+		goto dbg_out;
+	}
+
+	/* Allocate dbg state save space */
+#ifdef CONFIG_ARM64
+	dbg.state = kcalloc(MAX_DBG_STATE_SIZE, sizeof(uint64_t), GFP_KERNEL);
+#else
+	dbg.state = kcalloc(MAX_DBG_STATE_SIZE, sizeof(uint32_t), GFP_KERNEL);
+#endif
+	if (!dbg.state) {
+		ret = -ENOMEM;
+		goto dbg_err;
+	}
+
+	cpuhp_setup_state_nocalls(CPUHP_AP_ARM_SAVE_RESTORE_CORESIGHT4_STARTING,
+				  "AP_ARM_SAVE_RESTORE_CORESIGHT4_STARTING",
+				  jtag_hotcpu_restore_callback,
+				  jtag_hotcpu_save_callback);
+
+	cpu_pm_register_notifier(&jtag_cpu_pm_notifier);
+dbg_out:
+	return 0;
+dbg_err:
+	return ret;
+}
+arch_initcall(msm_jtag_dbg_init);
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 91c9441..a443239 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -55,7 +55,9 @@
 #endif
 
 #define PIL_NUM_DESC		10
+#define NUM_OF_ENCRYPTED_KEY	3
 static void __iomem *pil_info_base;
+static void __iomem *pil_minidump_base;
 
 /**
  * proxy_timeout - Override for proxy vote timeouts
@@ -78,6 +80,18 @@
 };
 
 /**
+ * struct boot_minidump_smem_region - Representation of SMEM TOC
+ * @region_name: Name of modem segment to be dumped
+ * @region_base_address: Where segment start from
+ * @region_size: Size of segment to be dumped
+ */
+struct boot_minidump_smem_region {
+	char region_name[16];
+	u64 region_base_address;
+	u64 region_size;
+};
+
+/**
  * struct pil_seg - memory map representing one segment
  * @next: points to next seg mentor NULL if last segment
  * @paddr: physical start address of segment
@@ -131,11 +145,67 @@
 	phys_addr_t region_end;
 	void *region;
 	struct pil_image_info __iomem *info;
+	struct md_ssr_ss_info __iomem *minidump;
+	int minidump_id;
 	int id;
 	int unvoted_flag;
 	size_t region_size;
 };
 
+static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
+{
+	struct boot_minidump_smem_region __iomem *region_info;
+	struct ramdump_segment *ramdump_segs, *s;
+	struct pil_priv *priv = desc->priv;
+	void __iomem *subsys_smem_base;
+	void __iomem *offset;
+	int ss_mdump_seg_cnt;
+	int ret, i;
+
+	memcpy(&offset, &priv->minidump, sizeof(priv->minidump));
+	offset = offset + sizeof(priv->minidump->md_ss_smem_regions_baseptr);
+	/* There are 3 encryption keys which also need to be dumped */
+	ss_mdump_seg_cnt = readb_relaxed(offset) +
+				NUM_OF_ENCRYPTED_KEY;
+
+	subsys_smem_base = ioremap(__raw_readl(priv->minidump),
+				   ss_mdump_seg_cnt * sizeof(*region_info));
+	region_info =
+		(struct boot_minidump_smem_region __iomem *)subsys_smem_base;
+	ramdump_segs = kcalloc(ss_mdump_seg_cnt,
+			       sizeof(*ramdump_segs), GFP_KERNEL);
+	if (!ramdump_segs)
+		return -ENOMEM;
+
+	if (desc->subsys_vmid > 0)
+		ret = pil_assign_mem_to_linux(desc, priv->region_start,
+			(priv->region_end - priv->region_start));
+
+	s = ramdump_segs;
+	for (i = 0; i < ss_mdump_seg_cnt; i++) {
+		memcpy(&offset, &region_info, sizeof(region_info));
+		memcpy(&s->name, &region_info, sizeof(region_info));
+		offset = offset + sizeof(region_info->region_name);
+		s->address = __raw_readl(offset);
+		offset = offset + sizeof(region_info->region_base_address);
+		s->size = __raw_readl(offset);
+		s++;
+		region_info++;
+	}
+	ret = do_minidump(ramdump_dev, ramdump_segs, ss_mdump_seg_cnt);
+	kfree(ramdump_segs);
+	if (ret)
+		pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n",
+			__func__, desc->name, ret);
+	writel_relaxed(0, &priv->minidump->md_ss_smem_regions_baseptr);
+	writeb_relaxed(1, &priv->minidump->md_ss_ssr_cause);
+
+	if (desc->subsys_vmid > 0)
+		ret = pil_assign_mem_to_subsys(desc, priv->region_start,
+			(priv->region_end - priv->region_start));
+	return ret;
+}
+
 /**
  * pil_do_ramdump() - Ramdump an image
  * @desc: descriptor from pil_desc_init()
@@ -151,6 +221,9 @@
 	int count = 0, ret;
 	struct ramdump_segment *ramdump_segs, *s;
 
+	if (priv->minidump && (__raw_readl(priv->minidump) > 0))
+		return pil_do_minidump(desc, ramdump_dev);
+
 	list_for_each_entry(seg, &priv->segs, list)
 		count++;
 
@@ -1011,9 +1084,10 @@
 int pil_desc_init(struct pil_desc *desc)
 {
 	struct pil_priv *priv;
-	int ret;
 	void __iomem *addr;
+	int ret, ss_imem_offset_mdump;
 	char buf[sizeof(priv->info->name)];
+	struct device_node *ofnode = desc->dev->of_node;
 
 	if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
 				"Invalid proxy voting. Ignoring\n"))
@@ -1036,6 +1110,22 @@
 		strlcpy(buf, desc->name, sizeof(buf));
 		__iowrite32_copy(priv->info->name, buf, sizeof(buf) / 4);
 	}
+	if (of_property_read_u32(ofnode, "qcom,minidump-id",
+		&priv->minidump_id))
+		pr_debug("minidump-id not found for %s\n", desc->name);
+	else {
+		ss_imem_offset_mdump =
+			sizeof(struct md_ssr_ss_info) * priv->minidump_id;
+		if (pil_minidump_base) {
+			/* Add 0x4 to get start of struct md_ssr_ss_info base
+			 * from struct md_ssr_toc for any subsystem,
+			 * struct md_ssr_ss_info is actually the pointer
+			 * of ToC in smem for any subsystem.
+			 */
+			addr = pil_minidump_base + ss_imem_offset_mdump + 0x4;
+			priv->minidump = (struct md_ssr_ss_info __iomem *)addr;
+		}
+	}
 
 	ret = pil_parse_devicetree(desc);
 	if (ret)
@@ -1144,6 +1234,20 @@
 	for (i = 0; i < resource_size(&res)/sizeof(u32); i++)
 		writel_relaxed(0, pil_info_base + (i * sizeof(u32)));
 
+	np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-minidump");
+	if (!np) {
+		pr_warn("pil: failed to find qcom,msm-imem-minidump node\n");
+		goto out;
+	} else {
+		pil_minidump_base = of_iomap(np, 0);
+		if (!pil_minidump_base) {
+			pr_err("unable to map pil minidump imem offset\n");
+			goto out;
+		}
+	}
+	for (i = 0; i < sizeof(struct md_ssr_toc)/sizeof(u32); i++)
+		writel_relaxed(0, pil_minidump_base + (i * sizeof(u32)));
+	writel_relaxed(1, pil_minidump_base);
 out:
 	return register_pm_notifier(&pil_pm_notifier);
 }
@@ -1154,6 +1258,8 @@
 	unregister_pm_notifier(&pil_pm_notifier);
 	if (pil_info_base)
 		iounmap(pil_info_base);
+	if (pil_minidump_base)
+		iounmap(pil_minidump_base);
 }
 module_exit(msm_pil_exit);
 
diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h
index af7249b..daa4533 100644
--- a/drivers/soc/qcom/peripheral-loader.h
+++ b/drivers/soc/qcom/peripheral-loader.h
@@ -71,6 +71,34 @@
 	__le32 size;
 } __attribute__((__packed__));
 
+#define MAX_NUM_OF_SS 3
+
+/**
+ * struct md_ssr_ss_info - Info in imem about smem ToC
+ * @md_ss_smem_regions_baseptr: Start physical address of SMEM TOC
+ * @md_ss_num_of_regions: number of segments that need to be dumped
+ * @md_ss_encryption_status: status of encryption of segments
+ * @md_ss_ssr_cause: ssr cause enum
+ */
+struct md_ssr_ss_info {
+	u32 md_ss_smem_regions_baseptr;
+	u8 md_ss_num_of_regions;
+	u8 md_ss_encryption_status;
+	u8 md_ss_ssr_cause;
+	u8 reserved;
+};
+
+/**
+ * struct md_ssr_toc - Wrapper of struct md_ssr_ss_info
+ * @md_ssr_toc_init: flag to indicate to MSS SW about imem init done
+ * @md_ssr_ss: Instance of struct md_ssr_ss_info for a subsystem
+ */
+struct md_ssr_toc /* Shared IMEM ToC struct */
+{
+	u32 md_ssr_toc_init;
+	struct md_ssr_ss_info	md_ssr_ss[MAX_NUM_OF_SS];
+};
+
 /**
  * struct pil_reset_ops - PIL operations
  * @init_image: prepare an image for authentication
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 20b9769..a3cf11d 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -80,6 +80,8 @@
 #define MSS_PDC_OFFSET			8
 #define MSS_PDC_MASK			BIT(MSS_PDC_OFFSET)
 
+/* Timeout value for MBA boot when minidump is enabled */
+#define MBA_ENCRYPTION_TIMEOUT	3000
 enum scm_cmd {
 	PAS_MEM_SETUP_CMD = 2,
 };
@@ -298,7 +300,12 @@
 	struct device *dev = drv->desc.dev;
 	int ret;
 	u32 status;
-	u64 val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000;
+	u64 val;
+
+	if (of_property_read_bool(dev->of_node, "qcom,minidump-id"))
+		pbl_mba_boot_timeout_ms = MBA_ENCRYPTION_TIMEOUT;
+
+	val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000;
 
 	/* Wait for PBL completion. */
 	ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
diff --git a/drivers/soc/qcom/ramdump.c b/drivers/soc/qcom/ramdump.c
index dd77062..e4c1bb8 100644
--- a/drivers/soc/qcom/ramdump.c
+++ b/drivers/soc/qcom/ramdump.c
@@ -38,6 +38,8 @@
 static DEFINE_IDA(rd_minor_id);
 static bool ramdump_devnode_inited;
 #define RAMDUMP_WAIT_MSECS	120000
+#define MAX_STRTBL_SIZE 512
+#define MAX_NAME_LENGTH 16
 
 struct ramdump_device {
 	char name[256];
@@ -452,12 +454,143 @@
 
 }
 
+static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr)
+{
+	return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff);
+}
+
+static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx)
+{
+	return &elf_sheader(hdr)[idx];
+}
+
+static inline char *elf_str_table(struct elfhdr *hdr)
+{
+	if (hdr->e_shstrndx == SHN_UNDEF)
+		return NULL;
+	return (char *)hdr + elf_section(hdr, hdr->e_shstrndx)->sh_offset;
+}
+
+static inline unsigned int set_section_name(const char *name,
+					    struct elfhdr *ehdr)
+{
+	char *strtab = elf_str_table(ehdr);
+	static int strtable_idx = 1;
+	int idx, ret = 0;
+
+	idx = strtable_idx;
+	if ((strtab == NULL) || (name == NULL))
+		return 0;
+
+	ret = idx;
+	idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH);
+	strtable_idx = idx + 1;
+
+	return ret;
+}
+
+static int _do_minidump(void *handle, struct ramdump_segment *segments,
+		int nsegments)
+{
+	int ret, i;
+	struct ramdump_device *rd_dev = (struct ramdump_device *)handle;
+	struct elfhdr *ehdr;
+	struct elf_shdr *shdr;
+	unsigned long offset, strtbl_off;
+
+	if (!rd_dev->consumer_present) {
+		pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name);
+		return -EPIPE;
+	}
+
+	rd_dev->segments = segments;
+	rd_dev->nsegments = nsegments;
+
+	rd_dev->elfcore_size = sizeof(*ehdr) +
+			(sizeof(*shdr) * (nsegments + 2)) + MAX_STRTBL_SIZE;
+	ehdr = kzalloc(rd_dev->elfcore_size, GFP_KERNEL);
+	rd_dev->elfcore_buf = (char *)ehdr;
+	if (!rd_dev->elfcore_buf)
+		return -ENOMEM;
+
+	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+	ehdr->e_ident[EI_CLASS] = ELF_CLASS;
+	ehdr->e_ident[EI_DATA] = ELF_DATA;
+	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+	ehdr->e_ident[EI_OSABI] = ELF_OSABI;
+	ehdr->e_type = ET_CORE;
+	ehdr->e_machine  = ELF_ARCH;
+	ehdr->e_version = EV_CURRENT;
+	ehdr->e_ehsize = sizeof(*ehdr);
+	ehdr->e_shoff = sizeof(*ehdr);
+	ehdr->e_shentsize = sizeof(*shdr);
+	ehdr->e_shstrndx = 1;
+
+
+	offset = rd_dev->elfcore_size;
+	shdr = (struct elf_shdr *)(ehdr + 1);
+	strtbl_off = sizeof(*ehdr) + sizeof(*shdr) * (nsegments + 2);
+	shdr++;
+	shdr->sh_type = SHT_STRTAB;
+	shdr->sh_offset = (elf_addr_t)strtbl_off;
+	shdr->sh_size = MAX_STRTBL_SIZE;
+	shdr->sh_entsize = 0;
+	shdr->sh_flags = 0;
+	shdr->sh_name = set_section_name("STR_TBL", ehdr);
+	shdr++;
+
+	for (i = 0; i < nsegments; i++, shdr++) {
+		/* Update elf header */
+		shdr->sh_type = SHT_PROGBITS;
+		shdr->sh_name = set_section_name(segments[i].name, ehdr);
+		shdr->sh_addr = (elf_addr_t)segments[i].address;
+		shdr->sh_size = segments[i].size;
+		shdr->sh_flags = SHF_WRITE;
+		shdr->sh_offset = offset;
+		shdr->sh_entsize = 0;
+		offset += shdr->sh_size;
+	}
+	ehdr->e_shnum = nsegments + 2;
+
+	rd_dev->data_ready = 1;
+	rd_dev->ramdump_status = -1;
+
+	reinit_completion(&rd_dev->ramdump_complete);
+
+	/* Tell userspace that the data is ready */
+	wake_up(&rd_dev->dump_wait_q);
+
+	/* Wait (with a timeout) to let the ramdump complete */
+	ret = wait_for_completion_timeout(&rd_dev->ramdump_complete,
+			msecs_to_jiffies(RAMDUMP_WAIT_MSECS));
+
+	if (!ret) {
+		pr_err("Ramdump(%s): Timed out waiting for userspace.\n",
+		       rd_dev->name);
+		ret = -EPIPE;
+	} else {
+		ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE;
+	}
+
+	rd_dev->data_ready = 0;
+	rd_dev->elfcore_size = 0;
+	kfree(rd_dev->elfcore_buf);
+	rd_dev->elfcore_buf = NULL;
+	return ret;
+}
+
 int do_ramdump(void *handle, struct ramdump_segment *segments, int nsegments)
 {
 	return _do_ramdump(handle, segments, nsegments, false);
 }
 EXPORT_SYMBOL(do_ramdump);
 
+int do_minidump(void *handle, struct ramdump_segment *segments, int nsegments)
+{
+	return _do_minidump(handle, segments, nsegments);
+}
+EXPORT_SYMBOL(do_minidump);
+
 int
 do_elf_ramdump(void *handle, struct ramdump_segment *segments, int nsegments)
 {
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index f4c35ab..f7902e1 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -563,7 +563,7 @@
 	spin_lock_irqsave(&rpm->lock, flags);
 	for (i = 0; rpm->passthru_cache[i]; i++) {
 		rpm_msg = rpm->passthru_cache[i];
-		ret = mbox_send_controller_data(rc->chan, &rpm_msg->msg);
+		ret = mbox_write_controller_data(rc->chan, &rpm_msg->msg);
 		if (ret)
 			goto fail;
 	}
@@ -762,7 +762,7 @@
 	rpm_msg.msg.is_control = true;
 	rpm_msg.msg.is_complete = false;
 
-	return mbox_send_controller_data(rc->chan, &rpm_msg.msg);
+	return mbox_write_controller_data(rc->chan, &rpm_msg.msg);
 }
 EXPORT_SYMBOL(rpmh_write_control);
 
@@ -797,7 +797,7 @@
 	rpm->dirty = true;
 	spin_unlock_irqrestore(&rpm->lock, flags);
 
-	return mbox_send_controller_data(rc->chan, &rpm_msg.msg);
+	return mbox_write_controller_data(rc->chan, &rpm_msg.msg);
 }
 EXPORT_SYMBOL(rpmh_invalidate);
 
@@ -886,7 +886,7 @@
 	rpm_msg.msg.num_payload = 1;
 	rpm_msg.msg.is_complete = false;
 
-	return mbox_send_controller_data(rc->chan, &rpm_msg.msg);
+	return mbox_write_controller_data(rc->chan, &rpm_msg.msg);
 }
 
 /**
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 27960e4..c4226c0 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -107,7 +107,10 @@
 
 static int dw_spi_debugfs_init(struct dw_spi *dws)
 {
-	dws->debugfs = debugfs_create_dir("dw_spi", NULL);
+	char name[128];
+
+	snprintf(name, 128, "dw_spi-%s", dev_name(&dws->master->dev));
+	dws->debugfs = debugfs_create_dir(name, NULL);
 	if (!dws->debugfs)
 		return -ENOMEM;
 
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index a34fd5a..ec99790 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2898,9 +2898,6 @@
 
 	comedi_class->dev_groups = comedi_dev_groups;
 
-	/* XXX requires /proc interface */
-	comedi_proc_init();
-
 	/* create devices files for legacy/manual use */
 	for (i = 0; i < comedi_num_legacy_minors; i++) {
 		struct comedi_device *dev;
@@ -2918,6 +2915,9 @@
 		mutex_unlock(&dev->mutex);
 	}
 
+	/* XXX requires /proc interface */
+	comedi_proc_init();
+
 	return 0;
 }
 module_init(comedi_init);
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 5dd1832..35b6351 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/dwc3-omap.h>
@@ -511,7 +512,7 @@
 
 	/* check the DMA Status */
 	reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
-
+	irq_set_status_flags(omap->irq, IRQ_NOAUTOEN);
 	ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt,
 					dwc3_omap_interrupt_thread, IRQF_SHARED,
 					"dwc3-omap", omap);
@@ -532,7 +533,7 @@
 	}
 
 	dwc3_omap_enable_irqs(omap);
-
+	enable_irq(omap->irq);
 	return 0;
 
 err2:
@@ -553,6 +554,7 @@
 	extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb);
 	extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb);
 	dwc3_omap_disable_irqs(omap);
+	disable_irq(omap->irq);
 	of_platform_depopulate(omap->dev);
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index b0f7195..b6d4b48 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -582,7 +582,7 @@
 		}
 		status = usb_ep_enable(hidg->out_ep);
 		if (status < 0) {
-			ERROR(cdev, "Enable IN endpoint FAILED!\n");
+			ERROR(cdev, "Enable OUT endpoint FAILED!\n");
 			goto fail;
 		}
 		hidg->out_ep->driver_data = hidg;
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 37d904f..6103172 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -572,11 +572,15 @@
 				qphy->base +
 				qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
 
-			/* enable phy auto-resume */
-			writel_relaxed(0x91, qphy->base + qphy->phy_reg[TEST1]);
-			/* flush the previous write before next write */
-			wmb();
-			writel_relaxed(0x90, qphy->base + qphy->phy_reg[TEST1]);
+			if (linestate & (LINESTATE_DP | LINESTATE_DM)) {
+				/* enable phy auto-resume */
+				writel_relaxed(0x91,
+					qphy->base + qphy->phy_reg[TEST1]);
+				/* flush the previous write before next write */
+				wmb();
+				writel_relaxed(0x90,
+					qphy->base + qphy->phy_reg[TEST1]);
+			}
 
 			dev_dbg(phy->dev, "%s: intr_mask = %x\n",
 			__func__, intr_mask);
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 031bc08..43559be 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -1173,6 +1173,10 @@
 			return ret;
 
 		vdev->barmap[index] = pci_iomap(pdev, index, 0);
+		if (!vdev->barmap[index]) {
+			pci_release_selected_regions(pdev, 1 << index);
+			return -ENOMEM;
+		}
 	}
 
 	vma->vm_private_data = vdev;
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
index 5ffd1d9..357243d 100644
--- a/drivers/vfio/pci/vfio_pci_rdwr.c
+++ b/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -193,7 +193,10 @@
 	if (!vdev->has_vga)
 		return -EINVAL;
 
-	switch (pos) {
+	if (pos > 0xbfffful)
+		return -EINVAL;
+
+	switch ((u32)pos) {
 	case 0xa0000 ... 0xbffff:
 		count = min(count, (size_t)(0xc0000 - pos));
 		iomem = ioremap_nocache(0xa0000, 0xbffff - 0xa0000 + 1);
diff --git a/drivers/video/fbdev/cobalt_lcdfb.c b/drivers/video/fbdev/cobalt_lcdfb.c
index 2d3b691..038ac69 100644
--- a/drivers/video/fbdev/cobalt_lcdfb.c
+++ b/drivers/video/fbdev/cobalt_lcdfb.c
@@ -308,6 +308,11 @@
 	info->screen_size = resource_size(res);
 	info->screen_base = devm_ioremap(&dev->dev, res->start,
 					 info->screen_size);
+	if (!info->screen_base) {
+		framebuffer_release(info);
+		return -ENOMEM;
+	}
+
 	info->fbops = &cobalt_lcd_fbops;
 	info->fix = cobalt_lcdfb_fix;
 	info->fix.smem_start = res->start;
diff --git a/drivers/xen/arm-device.c b/drivers/xen/arm-device.c
index 778acf8..85dd20e 100644
--- a/drivers/xen/arm-device.c
+++ b/drivers/xen/arm-device.c
@@ -58,9 +58,13 @@
 	xen_pfn_t *gpfns;
 	xen_ulong_t *idxs;
 	int *errs;
-	struct xen_add_to_physmap_range xatp;
 
 	for (i = 0; i < count; i++) {
+		struct xen_add_to_physmap_range xatp = {
+			.domid = DOMID_SELF,
+			.space = XENMAPSPACE_dev_mmio
+		};
+
 		r = &resources[i];
 		nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE);
 		if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0))
@@ -87,9 +91,7 @@
 			idxs[j] = XEN_PFN_DOWN(r->start) + j;
 		}
 
-		xatp.domid = DOMID_SELF;
 		xatp.size = nr;
-		xatp.space = XENMAPSPACE_dev_mmio;
 
 		set_xen_guest_handle(xatp.gpfns, gpfns);
 		set_xen_guest_handle(xatp.idxs, idxs);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index e46e7fb..14a37ff 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -7401,7 +7401,8 @@
 
 		spin_unlock(&cluster->refill_lock);
 
-		down_read(&used_bg->data_rwsem);
+		/* We should only have one-level nested. */
+		down_read_nested(&used_bg->data_rwsem, SINGLE_DEPTH_NESTING);
 
 		spin_lock(&cluster->refill_lock);
 		if (used_bg == cluster->block_group)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a2a014b..8a05fa7 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7648,11 +7648,18 @@
 	 * within our reservation, otherwise we need to adjust our inode
 	 * counter appropriately.
 	 */
-	if (dio_data->outstanding_extents) {
+	if (dio_data->outstanding_extents >= num_extents) {
 		dio_data->outstanding_extents -= num_extents;
 	} else {
+		/*
+		 * If dio write length has been split due to no large enough
+		 * contiguous space, we need to compensate our inode counter
+		 * appropriately.
+		 */
+		u64 num_needed = num_extents - dio_data->outstanding_extents;
+
 		spin_lock(&BTRFS_I(inode)->lock);
-		BTRFS_I(inode)->outstanding_extents += num_extents;
+		BTRFS_I(inode)->outstanding_extents += num_needed;
 		spin_unlock(&BTRFS_I(inode)->lock);
 	}
 }
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index b890045..309313b 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -37,6 +37,7 @@
  */
 #define LOG_INODE_ALL 0
 #define LOG_INODE_EXISTS 1
+#define LOG_OTHER_INODE 2
 
 /*
  * directory trouble cases
@@ -4623,7 +4624,7 @@
 	if (S_ISDIR(inode->i_mode) ||
 	    (!test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
 		       &BTRFS_I(inode)->runtime_flags) &&
-	     inode_only == LOG_INODE_EXISTS))
+	     inode_only >= LOG_INODE_EXISTS))
 		max_key.type = BTRFS_XATTR_ITEM_KEY;
 	else
 		max_key.type = (u8)-1;
@@ -4647,7 +4648,13 @@
 		return ret;
 	}
 
-	mutex_lock(&BTRFS_I(inode)->log_mutex);
+	if (inode_only == LOG_OTHER_INODE) {
+		inode_only = LOG_INODE_EXISTS;
+		mutex_lock_nested(&BTRFS_I(inode)->log_mutex,
+				  SINGLE_DEPTH_NESTING);
+	} else {
+		mutex_lock(&BTRFS_I(inode)->log_mutex);
+	}
 
 	/*
 	 * a brute force approach to making sure we get the most uptodate
@@ -4799,7 +4806,7 @@
 				 * unpin it.
 				 */
 				err = btrfs_log_inode(trans, root, other_inode,
-						      LOG_INODE_EXISTS,
+						      LOG_OTHER_INODE,
 						      0, LLONG_MAX, ctx);
 				iput(other_inode);
 				if (err)
diff --git a/fs/dcache.c b/fs/dcache.c
index 7171f0d..227a4f9 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -277,6 +277,33 @@
 	return dentry->d_name.name != dentry->d_iname;
 }
 
+void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry)
+{
+	spin_lock(&dentry->d_lock);
+	if (unlikely(dname_external(dentry))) {
+		struct external_name *p = external_name(dentry);
+		atomic_inc(&p->u.count);
+		spin_unlock(&dentry->d_lock);
+		name->name = p->name;
+	} else {
+		memcpy(name->inline_name, dentry->d_iname, DNAME_INLINE_LEN);
+		spin_unlock(&dentry->d_lock);
+		name->name = name->inline_name;
+	}
+}
+EXPORT_SYMBOL(take_dentry_name_snapshot);
+
+void release_dentry_name_snapshot(struct name_snapshot *name)
+{
+	if (unlikely(name->name != name->inline_name)) {
+		struct external_name *p;
+		p = container_of(name->name, struct external_name, name[0]);
+		if (unlikely(atomic_dec_and_test(&p->u.count)))
+			kfree_rcu(p, u.head);
+	}
+}
+EXPORT_SYMBOL(release_dentry_name_snapshot);
+
 static inline void __d_set_inode_and_type(struct dentry *dentry,
 					  struct inode *inode,
 					  unsigned type_flags)
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 1e30f74..3d7de9f 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -730,7 +730,7 @@
 {
 	int error;
 	struct dentry *dentry = NULL, *trap;
-	const char *old_name;
+	struct name_snapshot old_name;
 
 	trap = lock_rename(new_dir, old_dir);
 	/* Source or destination directories don't exist? */
@@ -745,19 +745,19 @@
 	if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry))
 		goto exit;
 
-	old_name = fsnotify_oldname_init(old_dentry->d_name.name);
+	take_dentry_name_snapshot(&old_name, old_dentry);
 
 	error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir),
 			      dentry, 0);
 	if (error) {
-		fsnotify_oldname_free(old_name);
+		release_dentry_name_snapshot(&old_name);
 		goto exit;
 	}
 	d_move(old_dentry, dentry);
-	fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name,
+	fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name.name,
 		d_is_dir(old_dentry),
 		NULL, old_dentry);
-	fsnotify_oldname_free(old_name);
+	release_dentry_name_snapshot(&old_name);
 	unlock_rename(new_dir, old_dir);
 	dput(dentry);
 	return old_dentry;
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 7bc186f..1be45c8 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -77,13 +77,6 @@
 	switch (type) {
 	case ACL_TYPE_ACCESS:
 		ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
-		if (acl) {
-			rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-			if (rc)
-				return rc;
-			inode->i_ctime = current_time(inode);
-			mark_inode_dirty(inode);
-		}
 		break;
 	case ACL_TYPE_DEFAULT:
 		ea_name = XATTR_NAME_POSIX_ACL_DEFAULT;
@@ -118,9 +111,17 @@
 
 	tid = txBegin(inode->i_sb, 0);
 	mutex_lock(&JFS_IP(inode)->commit_mutex);
+	if (type == ACL_TYPE_ACCESS && acl) {
+		rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+		if (rc)
+			goto end_tx;
+		inode->i_ctime = current_time(inode);
+		mark_inode_dirty(inode);
+	}
 	rc = __jfs_set_acl(tid, inode, type, acl);
 	if (!rc)
 		rc = txCommit(tid, 1, &inode, 0);
+end_tx:
 	txEnd(tid);
 	mutex_unlock(&JFS_IP(inode)->commit_mutex);
 	return rc;
diff --git a/fs/namei.c b/fs/namei.c
index 79177c9..e10895c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4404,11 +4404,11 @@
 {
 	int error;
 	bool is_dir = d_is_dir(old_dentry);
-	const unsigned char *old_name;
 	struct inode *source = old_dentry->d_inode;
 	struct inode *target = new_dentry->d_inode;
 	bool new_is_dir = false;
 	unsigned max_links = new_dir->i_sb->s_max_links;
+	struct name_snapshot old_name;
 
 	/*
 	 * Check source == target.
@@ -4459,7 +4459,7 @@
 	if (error)
 		return error;
 
-	old_name = fsnotify_oldname_init(old_dentry->d_name.name);
+	take_dentry_name_snapshot(&old_name, old_dentry);
 	dget(new_dentry);
 	if (!is_dir || (flags & RENAME_EXCHANGE))
 		lock_two_nondirectories(source, target);
@@ -4514,14 +4514,14 @@
 		inode_unlock(target);
 	dput(new_dentry);
 	if (!error) {
-		fsnotify_move(old_dir, new_dir, old_name, is_dir,
+		fsnotify_move(old_dir, new_dir, old_name.name, is_dir,
 			      !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry);
 		if (flags & RENAME_EXCHANGE) {
 			fsnotify_move(new_dir, old_dir, old_dentry->d_name.name,
 				      new_is_dir, NULL, new_dentry);
 		}
 	}
-	fsnotify_oldname_free(old_name);
+	release_dentry_name_snapshot(&old_name);
 
 	return error;
 }
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index a1de8ef..84c1cb9 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -757,7 +757,7 @@
 	 */
 	nfs_sync_mapping(filp->f_mapping);
 	if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
-		nfs_zap_mapping(inode, filp->f_mapping);
+		nfs_zap_caches(inode);
 out:
 	return status;
 }
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 401ea6e..46ca788 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6419,7 +6419,7 @@
 		set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(&q->lock, flags);
 
-		freezable_schedule_timeout_interruptible(NFS4_LOCK_MAXTIMEOUT);
+		freezable_schedule_timeout(NFS4_LOCK_MAXTIMEOUT);
 	}
 
 	finish_wait(q, &wait);
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index db39de2..a64adc2 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -104,16 +104,20 @@
 	if (unlikely(!fsnotify_inode_watches_children(p_inode)))
 		__fsnotify_update_child_dentry_flags(p_inode);
 	else if (p_inode->i_fsnotify_mask & mask) {
+		struct name_snapshot name;
+
 		/* we are notifying a parent so come up with the new mask which
 		 * specifies these are events which came from a child. */
 		mask |= FS_EVENT_ON_CHILD;
 
+		take_dentry_name_snapshot(&name, dentry);
 		if (path)
 			ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
-				       dentry->d_name.name, 0);
+				       name.name, 0);
 		else
 			ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
-				       dentry->d_name.name, 0);
+				       name.name, 0);
+		release_dentry_name_snapshot(&name);
 	}
 
 	dput(parent);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index bd2dc34..8e151fb 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -434,7 +434,7 @@
 	for (i = 0; i < cxt->max_dump_cnt; i++) {
 		cxt->przs[i] = persistent_ram_new(*paddr, cxt->record_size, 0,
 						  &cxt->ecc_info,
-						  cxt->memtype);
+						  cxt->memtype, 0);
 		if (IS_ERR(cxt->przs[i])) {
 			err = PTR_ERR(cxt->przs[i]);
 			dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
@@ -471,7 +471,8 @@
 		return -ENOMEM;
 	}
 
-	*prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info, cxt->memtype);
+	*prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info,
+				  cxt->memtype, 0);
 	if (IS_ERR(*prz)) {
 		int err = PTR_ERR(*prz);
 
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
index 3975dee..e11672a 100644
--- a/fs/pstore/ram_core.c
+++ b/fs/pstore/ram_core.c
@@ -48,16 +48,15 @@
 	return atomic_read(&prz->buffer->start);
 }
 
-static DEFINE_RAW_SPINLOCK(buffer_lock);
-
 /* increase and wrap the start pointer, returning the old value */
 static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
 {
 	int old;
 	int new;
-	unsigned long flags;
+	unsigned long flags = 0;
 
-	raw_spin_lock_irqsave(&buffer_lock, flags);
+	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
+		raw_spin_lock_irqsave(&prz->buffer_lock, flags);
 
 	old = atomic_read(&prz->buffer->start);
 	new = old + a;
@@ -65,7 +64,8 @@
 		new -= prz->buffer_size;
 	atomic_set(&prz->buffer->start, new);
 
-	raw_spin_unlock_irqrestore(&buffer_lock, flags);
+	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
+		raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
 
 	return old;
 }
@@ -75,9 +75,10 @@
 {
 	size_t old;
 	size_t new;
-	unsigned long flags;
+	unsigned long flags = 0;
 
-	raw_spin_lock_irqsave(&buffer_lock, flags);
+	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
+		raw_spin_lock_irqsave(&prz->buffer_lock, flags);
 
 	old = atomic_read(&prz->buffer->size);
 	if (old == prz->buffer_size)
@@ -89,7 +90,8 @@
 	atomic_set(&prz->buffer->size, new);
 
 exit:
-	raw_spin_unlock_irqrestore(&buffer_lock, flags);
+	if (!(prz->flags & PRZ_FLAG_NO_LOCK))
+		raw_spin_unlock_irqrestore(&prz->buffer_lock, flags);
 }
 
 static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
@@ -491,6 +493,7 @@
 			 prz->buffer->sig);
 	}
 
+	/* Rewind missing or invalid memory area. */
 	prz->buffer->sig = sig;
 	persistent_ram_zap(prz);
 
@@ -517,7 +520,7 @@
 
 struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
 			u32 sig, struct persistent_ram_ecc_info *ecc_info,
-			unsigned int memtype)
+			unsigned int memtype, u32 flags)
 {
 	struct persistent_ram_zone *prz;
 	int ret = -ENOMEM;
@@ -528,6 +531,10 @@
 		goto err;
 	}
 
+	/* Initialize general buffer state. */
+	raw_spin_lock_init(&prz->buffer_lock);
+	prz->flags = flags;
+
 	ret = persistent_ram_buffer_map(start, size, prz, memtype);
 	if (ret)
 		goto err;
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index 339d470..c8696df 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -212,6 +212,7 @@
 #define GCC_VS_CTRL_CLK_SRC					194
 #define GCC_VSENSOR_CLK_SRC					195
 #define GPLL4							196
+#define GPLL6							197
 
 /* GCC reset clocks */
 #define GCC_MMSS_BCR						0
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index edf88bd..9ddaf05 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -102,6 +102,8 @@
 	CPUHP_AP_DUMMY_TIMER_STARTING,
 	CPUHP_AP_ARM_XEN_STARTING,
 	CPUHP_AP_ARM_CORESIGHT_STARTING,
+	CPUHP_AP_ARM_SAVE_RESTORE_CORESIGHT4_STARTING,
+	CPUHP_AP_ARM_MM_CORESIGHT4_STARTING,
 	CPUHP_AP_ARM_CORESIGHT4_STARTING,
 	CPUHP_AP_ARM64_ISNDEP_STARTING,
 	CPUHP_AP_SMPCFD_DYING,
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 9b0477e..3d4a198 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -591,5 +591,11 @@
 	return d_backing_inode(d_real((struct dentry *) dentry, NULL, 0));
 }
 
+struct name_snapshot {
+	const char *name;
+	char inline_name[DNAME_INLINE_LEN];
+};
+void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
+void release_dentry_name_snapshot(struct name_snapshot *);
 
 #endif	/* __LINUX_DCACHE_H */
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index b8bcc05..e5f03a4d 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -293,35 +293,4 @@
 	}
 }
 
-#if defined(CONFIG_FSNOTIFY)	/* notify helpers */
-
-/*
- * fsnotify_oldname_init - save off the old filename before we change it
- */
-static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name)
-{
-	return kstrdup(name, GFP_KERNEL);
-}
-
-/*
- * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
- */
-static inline void fsnotify_oldname_free(const unsigned char *old_name)
-{
-	kfree(old_name);
-}
-
-#else	/* CONFIG_FSNOTIFY */
-
-static inline const char *fsnotify_oldname_init(const unsigned char *name)
-{
-	return NULL;
-}
-
-static inline void fsnotify_oldname_free(const unsigned char *old_name)
-{
-}
-
-#endif	/*  CONFIG_FSNOTIFY */
-
 #endif	/* _LINUX_FS_NOTIFY_H */
diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h
index 86a2dc6..073391b 100644
--- a/include/linux/mailbox_client.h
+++ b/include/linux/mailbox_client.h
@@ -44,7 +44,7 @@
 					      const char *name);
 struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);
 int mbox_send_message(struct mbox_chan *chan, void *mssg);
-int mbox_send_controller_data(struct mbox_chan *chan, void *mssg);
+int mbox_write_controller_data(struct mbox_chan *chan, void *mssg);
 void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */
 bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */
 void mbox_free_channel(struct mbox_chan *chan); /* may sleep */
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
index 7827c68..751b354 100644
--- a/include/linux/mailbox_controller.h
+++ b/include/linux/mailbox_controller.h
@@ -24,8 +24,8 @@
  *		transmission of data is reported by the controller via
  *		mbox_chan_txdone (if it has some TX ACK irq). It must not
  *		sleep.
- * @send_controller_data:
- *		Send data for the controller driver. This could be data to
+ * @write_controller_data:
+ *		Write data for the controller driver. This could be data to
  *		configure the controller or data that may be cached in the
  *		controller and not transmitted immediately. There is no ACK
  *		for this request and the request is not buffered in the
@@ -54,7 +54,7 @@
  */
 struct mbox_chan_ops {
 	int (*send_data)(struct mbox_chan *chan, void *data);
-	int (*send_controller_data)(struct mbox_chan *chan, void *data);
+	int (*write_controller_data)(struct mbox_chan *chan, void *data);
 	int (*startup)(struct mbox_chan *chan);
 	void (*shutdown)(struct mbox_chan *chan);
 	bool (*last_tx_done)(struct mbox_chan *chan);
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index c9f3796..80faf44 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -1384,6 +1384,8 @@
 int get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv);
 int mlx4_get_is_vlan_offload_disabled(struct mlx4_dev *dev, u8 port,
 				      bool *vlan_offload_disabled);
+void mlx4_handle_eth_header_mcast_prio(struct mlx4_net_trans_rule_hw_ctrl *ctrl,
+				       struct _rule_hw *eth_header);
 int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx);
 int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx);
 int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ed0099c9..07e1acb 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -158,7 +158,6 @@
 	NR_UNEVICTABLE,		/*  "     "     "   "       "         */
 	NR_ISOLATED_ANON,	/* Temporary isolated pages from anon lru */
 	NR_ISOLATED_FILE,	/* Temporary isolated pages from file lru */
-	NR_PAGES_SCANNED,	/* pages scanned since last reclaim */
 	WORKINGSET_REFAULT,
 	WORKINGSET_ACTIVATE,
 	WORKINGSET_NODERECLAIM,
@@ -645,6 +644,8 @@
 	int kswapd_order;
 	enum zone_type kswapd_classzone_idx;
 
+	int kswapd_failures;		/* Number of 'reclaimed == 0' runs */
+
 #ifdef CONFIG_COMPACTION
 	int kcompactd_max_order;
 	enum zone_type kcompactd_classzone_idx;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 6c9b1e0..8431c8c 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -799,6 +799,10 @@
 int genphy_suspend(struct phy_device *phydev);
 int genphy_resume(struct phy_device *phydev);
 int genphy_soft_reset(struct phy_device *phydev);
+static inline int genphy_no_soft_reset(struct phy_device *phydev)
+{
+	return 0;
+}
 void phy_driver_unregister(struct phy_driver *drv);
 void phy_drivers_unregister(struct phy_driver *drv, int n);
 int phy_driver_register(struct phy_driver *new_driver, struct module *owner);
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h
index 485cc8e..cb5edd6 100644
--- a/include/linux/pstore_ram.h
+++ b/include/linux/pstore_ram.h
@@ -24,6 +24,13 @@
 #include <linux/list.h>
 #include <linux/types.h>
 
+/*
+ * Choose whether access to the RAM zone requires locking or not.  If a zone
+ * can be written to from different CPUs like with ftrace for example, then
+ * PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
+ */
+#define PRZ_FLAG_NO_LOCK	BIT(0)
+
 struct persistent_ram_buffer;
 struct rs_control;
 
@@ -40,6 +47,8 @@
 	void *vaddr;
 	struct persistent_ram_buffer *buffer;
 	size_t buffer_size;
+	u32 flags;
+	raw_spinlock_t buffer_lock;
 
 	/* ECC correction */
 	char *par_buffer;
@@ -55,7 +64,7 @@
 
 struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
 			u32 sig, struct persistent_ram_ecc_info *ecc_info,
-			unsigned int memtype);
+			unsigned int memtype, u32 flags);
 void persistent_ram_free(struct persistent_ram_zone *prz);
 void persistent_ram_zap(struct persistent_ram_zone *prz);
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0737cb6..e1345ec 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1197,6 +1197,37 @@
 
 struct sched_group;
 
+struct eas_stats {
+	/* select_idle_sibling() stats */
+	u64 sis_attempts;
+	u64 sis_idle;
+	u64 sis_cache_affine;
+	u64 sis_suff_cap;
+	u64 sis_idle_cpu;
+	u64 sis_count;
+
+	/* select_energy_cpu_brute() stats */
+	u64 secb_attempts;
+	u64 secb_sync;
+	u64 secb_idle_bt;
+	u64 secb_insuff_cap;
+	u64 secb_no_nrg_sav;
+	u64 secb_nrg_sav;
+	u64 secb_count;
+
+	/* find_best_target() stats */
+	u64 fbt_attempts;
+	u64 fbt_no_cpu;
+	u64 fbt_no_sd;
+	u64 fbt_pref_idle;
+	u64 fbt_count;
+
+	/* cas */
+	/* select_task_rq_fair() stats */
+	u64 cas_attempts;
+	u64 cas_count;
+};
+
 struct sched_domain_shared {
 	atomic_t	ref;
 	atomic_t	nr_busy_cpus;
@@ -1265,6 +1296,8 @@
 	unsigned int ttwu_wake_remote;
 	unsigned int ttwu_move_affine;
 	unsigned int ttwu_move_balance;
+
+	struct eas_stats eas_stats;
 #endif
 #ifdef CONFIG_SCHED_DEBUG
 	char *name;
@@ -1463,6 +1496,35 @@
 	u64			nr_wakeups_affine_attempts;
 	u64			nr_wakeups_passive;
 	u64			nr_wakeups_idle;
+
+	/* select_idle_sibling() */
+	u64			nr_wakeups_sis_attempts;
+	u64			nr_wakeups_sis_idle;
+	u64			nr_wakeups_sis_cache_affine;
+	u64			nr_wakeups_sis_suff_cap;
+	u64			nr_wakeups_sis_idle_cpu;
+	u64			nr_wakeups_sis_count;
+
+	/* energy_aware_wake_cpu() */
+	u64			nr_wakeups_secb_attempts;
+	u64			nr_wakeups_secb_sync;
+	u64			nr_wakeups_secb_idle_bt;
+	u64			nr_wakeups_secb_insuff_cap;
+	u64			nr_wakeups_secb_no_nrg_sav;
+	u64			nr_wakeups_secb_nrg_sav;
+	u64			nr_wakeups_secb_count;
+
+	/* find_best_target() */
+	u64			nr_wakeups_fbt_attempts;
+	u64			nr_wakeups_fbt_no_cpu;
+	u64			nr_wakeups_fbt_no_sd;
+	u64			nr_wakeups_fbt_pref_idle;
+	u64			nr_wakeups_fbt_count;
+
+	/* cas */
+	/* select_task_rq_fair() */
+	u64			nr_wakeups_cas_attempts;
+	u64			nr_wakeups_cas_count;
 };
 #endif
 
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 513cd4fd..fc72465 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -119,6 +119,7 @@
 extern void tick_nohz_idle_exit(void);
 extern void tick_nohz_irq_exit(void);
 extern ktime_t tick_nohz_get_sleep_length(void);
+extern unsigned long tick_nohz_get_idle_calls(void);
 extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time);
 extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time);
 #else /* !CONFIG_NO_HZ_COMMON */
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index 261202f..8dbfdf7 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -95,8 +95,6 @@
 	[FRA_FWMARK]	= { .type = NLA_U32 }, \
 	[FRA_FWMASK]	= { .type = NLA_U32 }, \
 	[FRA_TABLE]     = { .type = NLA_U32 }, \
-	[FRA_UID_START]	= { .type = NLA_U32 }, \
-	[FRA_UID_END]	= { .type = NLA_U32 }, \
 	[FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
 	[FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \
 	[FRA_GOTO]	= { .type = NLA_U32 }, \
diff --git a/include/soc/qcom/jtag.h b/include/soc/qcom/jtag.h
index 5719e05..dff601d 100644
--- a/include/soc/qcom/jtag.h
+++ b/include/soc/qcom/jtag.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, 2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
diff --git a/include/soc/qcom/ramdump.h b/include/soc/qcom/ramdump.h
index 50a17c8..4e23ccf 100644
--- a/include/soc/qcom/ramdump.h
+++ b/include/soc/qcom/ramdump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 2017 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
 struct device;
 
 struct ramdump_segment {
+	char *name;
 	unsigned long address;
 	void *v_address;
 	unsigned long size;
@@ -28,6 +29,8 @@
 		int nsegments);
 extern int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
 		int nsegments);
+extern int do_minidump(void *handle, struct ramdump_segment *segments,
+		       int nsegments);
 
 #else
 static inline void *create_ramdump_device(const char *dev_name,
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index c88fd09..2f8536b 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -269,23 +269,24 @@
 		__entry->retval)
 );
 
-DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template,
-
+TRACE_EVENT(mm_vmscan_lru_isolate,
 	TP_PROTO(int classzone_idx,
 		int order,
 		unsigned long nr_requested,
 		unsigned long nr_scanned,
+		unsigned long nr_skipped,
 		unsigned long nr_taken,
 		isolate_mode_t isolate_mode,
 		int file),
 
-	TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file),
+	TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_skipped, nr_taken, isolate_mode, file),
 
 	TP_STRUCT__entry(
 		__field(int, classzone_idx)
 		__field(int, order)
 		__field(unsigned long, nr_requested)
 		__field(unsigned long, nr_scanned)
+		__field(unsigned long, nr_skipped)
 		__field(unsigned long, nr_taken)
 		__field(isolate_mode_t, isolate_mode)
 		__field(int, file)
@@ -296,49 +297,23 @@
 		__entry->order = order;
 		__entry->nr_requested = nr_requested;
 		__entry->nr_scanned = nr_scanned;
+		__entry->nr_skipped = nr_skipped;
 		__entry->nr_taken = nr_taken;
 		__entry->isolate_mode = isolate_mode;
 		__entry->file = file;
 	),
 
-	TP_printk("isolate_mode=%d classzone=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d",
+	TP_printk("isolate_mode=%d classzone=%d order=%d nr_requested=%lu nr_scanned=%lu nr_skipped=%lu nr_taken=%lu file=%d",
 		__entry->isolate_mode,
 		__entry->classzone_idx,
 		__entry->order,
 		__entry->nr_requested,
 		__entry->nr_scanned,
+		__entry->nr_skipped,
 		__entry->nr_taken,
 		__entry->file)
 );
 
-DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate,
-
-	TP_PROTO(int classzone_idx,
-		int order,
-		unsigned long nr_requested,
-		unsigned long nr_scanned,
-		unsigned long nr_taken,
-		isolate_mode_t isolate_mode,
-		int file),
-
-	TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
-
-);
-
-DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate,
-
-	TP_PROTO(int classzone_idx,
-		int order,
-		unsigned long nr_requested,
-		unsigned long nr_scanned,
-		unsigned long nr_taken,
-		isolate_mode_t isolate_mode,
-		int file),
-
-	TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file)
-
-);
-
 TRACE_EVENT(mm_vmscan_writepage,
 
 	TP_PROTO(struct page *page),
diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
index a66c4ba..bbf02a6 100644
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -54,8 +54,6 @@
 	FRA_TABLE,	/* Extended table id */
 	FRA_FWMASK,	/* mask for netfilter mark */
 	FRA_OIFNAME,
-	FRA_UID_START,	/* UID range */
-	FRA_UID_END,
 	FRA_PAD,
 	FRA_L3MDEV,	/* iif or oif is l3mdev goto its table */
 	FRA_UID_RANGE,	/* UID range */
diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h
index fdc56ee..9a767dd 100644
--- a/include/uapi/media/cam_defs.h
+++ b/include/uapi/media/cam_defs.h
@@ -27,6 +27,18 @@
 #define CAM_GENERIC_BLOB_CMDBUFFER_TYPE_MASK    0xFF
 #define CAM_GENERIC_BLOB_CMDBUFFER_TYPE_SHIFT   0
 
+/* Command Buffer Types */
+#define CAM_CMD_BUF_DMI                     0x1
+#define CAM_CMD_BUF_DMI16                   0x2
+#define CAM_CMD_BUF_DMI32                   0x3
+#define CAM_CMD_BUF_DMI64                   0x4
+#define CAM_CMD_BUF_DIRECT                  0x5
+#define CAM_CMD_BUF_INDIRECT                0x6
+#define CAM_CMD_BUF_I2C                     0x7
+#define CAM_CMD_BUF_FW                      0x8
+#define CAM_CMD_BUF_GENERIC                 0x9
+#define CAM_CMD_BUF_LEGACY                  0xA
+
 /**
  * struct cam_control - Structure used by ioctl control for camera
  *
diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h
index 9351d2d..cd2d2d2 100644
--- a/include/uapi/media/cam_icp.h
+++ b/include/uapi/media/cam_icp.h
@@ -56,6 +56,29 @@
 
 #define CAM_ICP_BPS_IO_IMAGES_MAX               0x9
 
+/* Command meta types */
+#define CAM_ICP_CMD_META_GENERIC_BLOB           0x1
+
+/* Generic blon types */
+#define CAM_ICP_CMD_GENERIC_BLOB_CLK            0x1
+
+/**
+ * struct cam_icp_clk_bw_request
+ *
+ * @budget_ns: Time required to process frame
+ * @frame_cycles: Frame cycles needed to process the frame
+ * @rt_flag: Flag to indicate real time stream
+ * @uncompressed_bw: Bandwidth required to process frame
+ * @compressed_bw: Compressed bandwidth to process frame
+ */
+struct cam_icp_clk_bw_request {
+	uint64_t budget_ns;
+	uint32_t frame_cycles;
+	uint32_t rt_flag;
+	uint64_t uncompressed_bw;
+	uint64_t compressed_bw;
+};
+
 /**
  * struct cam_icp_dev_ver - Device information for particular hw type
  *
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 7e3dfa6..69dc428 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -411,13 +411,16 @@
 }
 static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st);
 
+static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st);
+
 static int bringup_wait_for_ap(unsigned int cpu)
 {
 	struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
 
 	/* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */
 	wait_for_completion(&st->done);
-	BUG_ON(!cpu_online(cpu));
+	if (WARN_ON_ONCE((!cpu_online(cpu))))
+		return -ECANCELED;
 
 	/* Unpark the stopper thread and the hotplug thread of the target cpu */
 	stop_machine_unpark(cpu);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index a836ad6..4573d45 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3238,9 +3238,10 @@
 	return total += scr->dl;
 }
 
+unsigned long boosted_cpu_util(int cpu);
 static void sched_freq_tick_pelt(int cpu)
 {
-	unsigned long cpu_utilization = capacity_max;
+	unsigned long cpu_utilization = boosted_cpu_util(cpu);
 	unsigned long capacity_curr = capacity_curr_of(cpu);
 	struct sched_capacity_reqs *scr;
 
@@ -6222,9 +6223,6 @@
 
 	if (!(sd->flags & SD_LOAD_BALANCE)) {
 		printk("does not load-balance\n");
-		if (sd->parent)
-			printk(KERN_ERR "ERROR: !SD_LOAD_BALANCE domain"
-					" has parent");
 		return -1;
 	}
 
@@ -6319,8 +6317,12 @@
 
 static int sd_degenerate(struct sched_domain *sd)
 {
-	if (cpumask_weight(sched_domain_span(sd)) == 1)
-		return 1;
+	if (cpumask_weight(sched_domain_span(sd)) == 1) {
+		if (sd->groups->sge)
+			sd->flags &= ~SD_LOAD_BALANCE;
+		else
+			return 1;
+	}
 
 	/* Following flags need at least 2 groups */
 	if (sd->flags & (SD_LOAD_BALANCE |
@@ -6366,6 +6368,10 @@
 				SD_PREFER_SIBLING |
 				SD_SHARE_POWERDOMAIN |
 				SD_SHARE_CAP_STATES);
+		if (parent->groups->sge) {
+			parent->flags &= ~SD_LOAD_BALANCE;
+			return 0;
+		}
 		if (nr_node_ids == 1)
 			pflags &= ~SD_SERIALIZE;
 	}
@@ -6446,6 +6452,9 @@
 		goto free_rto_mask;
 
 	init_max_cpu_capacity(&rd->max_cpu_capacity);
+
+	rd->max_cap_orig_cpu = rd->min_cap_orig_cpu = -1;
+
 	return 0;
 
 free_rto_mask:
@@ -6790,6 +6799,7 @@
 		 */
 		sg->sgc->capacity = SCHED_CAPACITY_SCALE * cpumask_weight(sg_span);
 		sg->sgc->max_capacity = SCHED_CAPACITY_SCALE;
+		sg->sgc->min_capacity = SCHED_CAPACITY_SCALE;
 
 		/*
 		 * Make sure the first group of this domain contains the
@@ -7668,7 +7678,6 @@
 	enum s_alloc alloc_state;
 	struct sched_domain *sd;
 	struct s_data d;
-	struct rq *rq = NULL;
 	int i, ret = -ENOMEM;
 
 	alloc_state = __visit_domain_allocation_hell(&d, cpu_map);
@@ -7686,8 +7695,6 @@
 				*per_cpu_ptr(d.sd, i) = sd;
 			if (tl->flags & SDTL_OVERLAP || sched_feat(FORCE_SD_OVERLAP))
 				sd->flags |= SD_OVERLAP;
-			if (cpumask_equal(cpu_map, sched_domain_span(sd)))
-				break;
 		}
 	}
 
@@ -7722,8 +7729,19 @@
 	/* Attach the domains */
 	rcu_read_lock();
 	for_each_cpu(i, cpu_map) {
-		rq = cpu_rq(i);
+		int max_cpu = READ_ONCE(d.rd->max_cap_orig_cpu);
+		int min_cpu = READ_ONCE(d.rd->min_cap_orig_cpu);
+
+		if ((max_cpu < 0) || (cpu_rq(i)->cpu_capacity_orig >
+		    cpu_rq(max_cpu)->cpu_capacity_orig))
+			WRITE_ONCE(d.rd->max_cap_orig_cpu, i);
+
+		if ((min_cpu < 0) || (cpu_rq(i)->cpu_capacity_orig <
+		    cpu_rq(min_cpu)->cpu_capacity_orig))
+			WRITE_ONCE(d.rd->min_cap_orig_cpu, i);
+
 		sd = *per_cpu_ptr(d.sd, i);
+
 		cpu_attach_domain(sd, d.rd, i);
 	}
 	rcu_read_unlock();
@@ -8260,6 +8278,7 @@
 #ifdef CONFIG_FAIR_GROUP_SCHED
 		root_task_group.shares = ROOT_TASK_GROUP_LOAD;
 		INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
+		rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
 		/*
 		 * How much cpu bandwidth does root_task_group get?
 		 *
@@ -9081,11 +9100,20 @@
 	if (IS_ERR(tg))
 		return ERR_PTR(-ENOMEM);
 
-	sched_online_group(tg, parent);
-
 	return &tg->css;
 }
 
+/* Expose task group only after completing cgroup initialization */
+static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
+{
+	struct task_group *tg = css_tg(css);
+	struct task_group *parent = css_tg(css->parent);
+
+	if (parent)
+		sched_online_group(tg, parent);
+	return 0;
+}
+
 static void cpu_cgroup_css_released(struct cgroup_subsys_state *css)
 {
 	struct task_group *tg = css_tg(css);
@@ -9488,6 +9516,7 @@
 
 struct cgroup_subsys cpu_cgrp_subsys = {
 	.css_alloc	= cpu_cgroup_css_alloc,
+	.css_online	= cpu_cgroup_css_online,
 	.css_released	= cpu_cgroup_css_released,
 	.css_free	= cpu_cgroup_css_free,
 	.fork		= cpu_cgroup_fork,
diff --git a/kernel/sched/cpufreq_sched.c b/kernel/sched/cpufreq_sched.c
index 11b75e3..843eaa7 100644
--- a/kernel/sched/cpufreq_sched.c
+++ b/kernel/sched/cpufreq_sched.c
@@ -32,6 +32,12 @@
 static DEFINE_PER_CPU(unsigned long, enabled);
 DEFINE_PER_CPU(struct sched_capacity_reqs, cpu_sched_capacity_reqs);
 
+struct gov_tunables {
+	struct gov_attr_set attr_set;
+	unsigned int up_throttle_nsec;
+	unsigned int down_throttle_nsec;
+};
+
 /**
  * gov_data - per-policy data internal to the governor
  * @up_throttle: next throttling period expiry if increasing OPP
@@ -53,8 +59,8 @@
 struct gov_data {
 	ktime_t up_throttle;
 	ktime_t down_throttle;
-	unsigned int up_throttle_nsec;
-	unsigned int down_throttle_nsec;
+	struct gov_tunables *tunables;
+	struct list_head tunables_hook;
 	struct task_struct *task;
 	struct irq_work irq_work;
 	unsigned int requested_freq;
@@ -71,8 +77,10 @@
 
 	__cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
 
-	gd->up_throttle = ktime_add_ns(ktime_get(), gd->up_throttle_nsec);
-	gd->down_throttle = ktime_add_ns(ktime_get(), gd->down_throttle_nsec);
+	gd->up_throttle = ktime_add_ns(ktime_get(),
+				       gd->tunables->up_throttle_nsec);
+	gd->down_throttle = ktime_add_ns(ktime_get(),
+					 gd->tunables->down_throttle_nsec);
 	up_write(&policy->rwsem);
 }
 
@@ -263,12 +271,70 @@
 	static_key_slow_dec(&__sched_freq);
 }
 
-static struct attribute_group sched_attr_group_gov_pol;
-static struct attribute_group *get_sysfs_attr(void)
+/* Tunables */
+static struct gov_tunables *global_tunables;
+
+static inline struct gov_tunables *to_tunables(struct gov_attr_set *attr_set)
 {
-	return &sched_attr_group_gov_pol;
+	return container_of(attr_set, struct gov_tunables, attr_set);
 }
 
+static ssize_t up_throttle_nsec_show(struct gov_attr_set *attr_set, char *buf)
+{
+	struct gov_tunables *tunables = to_tunables(attr_set);
+
+	return sprintf(buf, "%u\n", tunables->up_throttle_nsec);
+}
+
+static ssize_t up_throttle_nsec_store(struct gov_attr_set *attr_set,
+				      const char *buf, size_t count)
+{
+	struct gov_tunables *tunables = to_tunables(attr_set);
+	int ret;
+	long unsigned int val;
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret < 0)
+		return ret;
+	tunables->up_throttle_nsec = val;
+	return count;
+}
+
+static ssize_t down_throttle_nsec_show(struct gov_attr_set *attr_set, char *buf)
+{
+	struct gov_tunables *tunables = to_tunables(attr_set);
+
+	return sprintf(buf, "%u\n", tunables->down_throttle_nsec);
+}
+
+static ssize_t down_throttle_nsec_store(struct gov_attr_set *attr_set,
+					const char *buf, size_t count)
+{
+	struct gov_tunables *tunables = to_tunables(attr_set);
+	int ret;
+	long unsigned int val;
+
+	ret = kstrtoul(buf, 0, &val);
+	if (ret < 0)
+		return ret;
+	tunables->down_throttle_nsec = val;
+	return count;
+}
+
+static struct governor_attr up_throttle_nsec = __ATTR_RW(up_throttle_nsec);
+static struct governor_attr down_throttle_nsec = __ATTR_RW(down_throttle_nsec);
+
+static struct attribute *schedfreq_attributes[] = {
+	&up_throttle_nsec.attr,
+	&down_throttle_nsec.attr,
+	NULL
+};
+
+static struct kobj_type tunables_ktype = {
+	.default_attrs = schedfreq_attributes,
+	.sysfs_ops = &governor_sysfs_ops,
+};
+
 static int cpufreq_sched_policy_init(struct cpufreq_policy *policy)
 {
 	struct gov_data *gd;
@@ -283,17 +349,39 @@
 	if (!gd)
 		return -ENOMEM;
 
-	gd->up_throttle_nsec = policy->cpuinfo.transition_latency ?
-			    policy->cpuinfo.transition_latency :
-			    THROTTLE_UP_NSEC;
-	gd->down_throttle_nsec = THROTTLE_DOWN_NSEC;
-	pr_debug("%s: throttle threshold = %u [ns]\n",
-		  __func__, gd->up_throttle_nsec);
+	policy->governor_data = gd;
 
-	rc = sysfs_create_group(&policy->kobj, get_sysfs_attr());
-	if (rc) {
-		pr_err("%s: couldn't create sysfs attributes: %d\n", __func__, rc);
-		goto err;
+	if (!global_tunables) {
+		gd->tunables = kzalloc(sizeof(*gd->tunables), GFP_KERNEL);
+		if (!gd->tunables)
+			goto free_gd;
+
+		gd->tunables->up_throttle_nsec =
+			policy->cpuinfo.transition_latency ?
+			policy->cpuinfo.transition_latency :
+			THROTTLE_UP_NSEC;
+		gd->tunables->down_throttle_nsec =
+			THROTTLE_DOWN_NSEC;
+
+		rc = kobject_init_and_add(&gd->tunables->attr_set.kobj,
+					  &tunables_ktype,
+					  get_governor_parent_kobj(policy),
+					  "%s", cpufreq_gov_sched.name);
+		if (rc)
+			goto free_tunables;
+
+		gov_attr_set_init(&gd->tunables->attr_set,
+				  &gd->tunables_hook);
+
+		pr_debug("%s: throttle_threshold = %u [ns]\n",
+			 __func__, gd->tunables->up_throttle_nsec);
+
+		if (!have_governor_per_policy())
+			global_tunables = gd->tunables;
+	} else {
+		gd->tunables = global_tunables;
+		gov_attr_set_get(&global_tunables->attr_set,
+				 &gd->tunables_hook);
 	}
 
 	policy->governor_data = gd;
@@ -305,7 +393,7 @@
 		if (IS_ERR_OR_NULL(gd->task)) {
 			pr_err("%s: failed to create kschedfreq thread\n",
 			       __func__);
-			goto err;
+			goto free_tunables;
 		}
 		get_task_struct(gd->task);
 		kthread_bind_mask(gd->task, policy->related_cpus);
@@ -317,7 +405,9 @@
 
 	return 0;
 
-err:
+free_tunables:
+	kfree(gd->tunables);
+free_gd:
 	policy->governor_data = NULL;
 	kfree(gd);
 	return -ENOMEM;
@@ -325,6 +415,7 @@
 
 static void cpufreq_sched_policy_exit(struct cpufreq_policy *policy)
 {
+	unsigned int count;
 	struct gov_data *gd = policy->governor_data;
 
 	clear_sched_freq();
@@ -333,7 +424,12 @@
 		put_task_struct(gd->task);
 	}
 
-	sysfs_remove_group(&policy->kobj, get_sysfs_attr());
+	count = gov_attr_set_put(&gd->tunables->attr_set, &gd->tunables_hook);
+	if (!count) {
+		if (!have_governor_per_policy())
+			global_tunables = NULL;
+		kfree(gd->tunables);
+	}
 
 	policy->governor_data = NULL;
 
@@ -373,88 +469,6 @@
 		per_cpu(enabled, cpu) = 0;
 }
 
-/* Tunables */
-static ssize_t show_up_throttle_nsec(struct gov_data *gd, char *buf)
-{
-	return sprintf(buf, "%u\n", gd->up_throttle_nsec);
-}
-
-static ssize_t store_up_throttle_nsec(struct gov_data *gd,
-		const char *buf, size_t count)
-{
-	int ret;
-	long unsigned int val;
-
-	ret = kstrtoul(buf, 0, &val);
-	if (ret < 0)
-		return ret;
-	gd->up_throttle_nsec = val;
-	return count;
-}
-
-static ssize_t show_down_throttle_nsec(struct gov_data *gd, char *buf)
-{
-	return sprintf(buf, "%u\n", gd->down_throttle_nsec);
-}
-
-static ssize_t store_down_throttle_nsec(struct gov_data *gd,
-		const char *buf, size_t count)
-{
-	int ret;
-	long unsigned int val;
-
-	ret = kstrtoul(buf, 0, &val);
-	if (ret < 0)
-		return ret;
-	gd->down_throttle_nsec = val;
-	return count;
-}
-
-/*
- * Create show/store routines
- * - sys: One governor instance for complete SYSTEM
- * - pol: One governor instance per struct cpufreq_policy
- */
-#define show_gov_pol_sys(file_name)					\
-static ssize_t show_##file_name##_gov_pol				\
-(struct cpufreq_policy *policy, char *buf)				\
-{									\
-	return show_##file_name(policy->governor_data, buf);		\
-}
-
-#define store_gov_pol_sys(file_name)					\
-static ssize_t store_##file_name##_gov_pol				\
-(struct cpufreq_policy *policy, const char *buf, size_t count)		\
-{									\
-	return store_##file_name(policy->governor_data, buf, count);	\
-}
-
-#define gov_pol_attr_rw(_name)						\
-	static struct freq_attr _name##_gov_pol =				\
-	__ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
-
-#define show_store_gov_pol_sys(file_name)				\
-	show_gov_pol_sys(file_name);						\
-	store_gov_pol_sys(file_name)
-#define tunable_handlers(file_name) \
-	show_gov_pol_sys(file_name); \
-	store_gov_pol_sys(file_name); \
-	gov_pol_attr_rw(file_name)
-
-tunable_handlers(down_throttle_nsec);
-tunable_handlers(up_throttle_nsec);
-
-/* Per policy governor instance */
-static struct attribute *sched_attributes_gov_pol[] = {
-	&up_throttle_nsec_gov_pol.attr,
-	&down_throttle_nsec_gov_pol.attr,
-	NULL,
-};
-
-static struct attribute_group sched_attr_group_gov_pol = {
-	.attrs = sched_attributes_gov_pol,
-	.name = "sched",
-};
 
 #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED
 static
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 8d327c3..116ffe4 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -17,6 +17,11 @@
 #include <trace/events/power.h>
 #include <linux/sched/sysctl.h>
 #include "sched.h"
+#include "tune.h"
+
+#ifdef CONFIG_SCHED_WALT
+unsigned long boosted_cpu_util(int cpu);
+#endif
 
 #define SUGOV_KTHREAD_PRIORITY	50
 
@@ -71,6 +76,11 @@
 	unsigned long max;
 	unsigned int flags;
 	unsigned int cpu;
+
+	/* The field below is for single-CPU policies only. */
+#ifdef CONFIG_NO_HZ_COMMON
+	unsigned long saved_idle_calls;
+#endif
 };
 
 static DEFINE_PER_CPU(struct sugov_cpu, sugov_cpu);
@@ -100,22 +110,20 @@
 {
 	struct cpufreq_policy *policy = sg_policy->policy;
 
+	if (sg_policy->next_freq == next_freq)
+		return;
+
+	sg_policy->next_freq = next_freq;
 	sg_policy->last_freq_update_time = time;
 
 	if (policy->fast_switch_enabled) {
-		if (sg_policy->next_freq == next_freq) {
-			trace_cpu_frequency(policy->cur, smp_processor_id());
-			return;
-		}
-		sg_policy->next_freq = next_freq;
 		next_freq = cpufreq_driver_fast_switch(policy, next_freq);
 		if (next_freq == CPUFREQ_ENTRY_INVALID)
 			return;
 
 		policy->cur = next_freq;
 		trace_cpu_frequency(next_freq, smp_processor_id());
-	} else if (sg_policy->next_freq != next_freq) {
-		sg_policy->next_freq = next_freq;
+	} else {
 		sg_policy->work_in_progress = true;
 		irq_work_queue(&sg_policy->irq_work);
 	}
@@ -171,6 +179,7 @@
 	*max = cfs_max;
 
 	*util = cpu_util_freq(cpu, &loadcpu->walt_load);
+	*util = boosted_cpu_util(cpu);
 }
 
 static void sugov_set_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,
@@ -283,6 +292,19 @@
 		*util = max(*util, sg_cpu->walt_load.pl);
 }
 
+#ifdef CONFIG_NO_HZ_COMMON
+static bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu)
+{
+	unsigned long idle_calls = tick_nohz_get_idle_calls();
+	bool ret = idle_calls == sg_cpu->saved_idle_calls;
+
+	sg_cpu->saved_idle_calls = idle_calls;
+	return ret;
+}
+#else
+static inline bool sugov_cpu_is_busy(struct sugov_cpu *sg_cpu) { return false; }
+#endif /* CONFIG_NO_HZ_COMMON */
+
 static void sugov_update_single(struct update_util_data *hook, u64 time,
 				unsigned int flags)
 {
@@ -291,6 +313,7 @@
 	struct cpufreq_policy *policy = sg_policy->policy;
 	unsigned long util, max;
 	unsigned int next_f;
+	bool busy;
 
 	sugov_set_iowait_boost(sg_cpu, time, flags);
 	sg_cpu->last_update = time;
@@ -298,6 +321,7 @@
 	if (!sugov_should_update_freq(sg_policy, time))
 		return;
 
+	busy = sugov_cpu_is_busy(sg_cpu);
 	flags &= ~SCHED_CPUFREQ_RT_DL;
 
 	if (flags & SCHED_CPUFREQ_RT_DL) {
@@ -309,35 +333,29 @@
 				   sg_policy->policy->cur);
 		sugov_walt_adjust(sg_cpu, &util, &max);
 		next_f = get_next_freq(sg_policy, util, max);
+		/*
+		 * Do not reduce the frequency if the CPU has not been idle
+		 * recently, as the reduction is likely to be premature then.
+		 */
+		if (busy && next_f < sg_policy->next_freq)
+			next_f = sg_policy->next_freq;
 	}
 	sugov_update_commit(sg_policy, time, next_f);
 }
 
-static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu,
-					   unsigned long util, unsigned long max,
-					   unsigned int flags)
+static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu)
 {
 	struct sugov_policy *sg_policy = sg_cpu->sg_policy;
 	struct cpufreq_policy *policy = sg_policy->policy;
-	unsigned int max_f = policy->cpuinfo.max_freq;
 	u64 last_freq_update_time = sg_policy->last_freq_update_time;
+	unsigned long util = 0, max = 1;
 	unsigned int j;
 
-	if (flags & SCHED_CPUFREQ_RT_DL)
-		return max_f;
-
-	sugov_iowait_boost(sg_cpu, &util, &max);
-	sugov_walt_adjust(sg_cpu, &util, &max);
-
 	for_each_cpu(j, policy->cpus) {
-		struct sugov_cpu *j_sg_cpu;
+		struct sugov_cpu *j_sg_cpu = &per_cpu(sugov_cpu, j);
 		unsigned long j_util, j_max;
 		s64 delta_ns;
 
-		if (j == sg_cpu->cpu)
-			continue;
-
-		j_sg_cpu = &per_cpu(sugov_cpu, j);
 		/*
 		 * If the CPU utilization was last updated before the previous
 		 * frequency update and the time elapsed between the last update
@@ -351,7 +369,7 @@
 			continue;
 		}
 		if (j_sg_cpu->flags & SCHED_CPUFREQ_RT_DL)
-			return max_f;
+			return policy->cpuinfo.max_freq;
 
 		j_util = j_sg_cpu->util;
 		j_max = j_sg_cpu->max;
@@ -404,7 +422,11 @@
 				sg_cpu->walt_load.pl, flags);
 
 	if (sugov_should_update_freq(sg_policy, time)) {
-		next_f = sugov_next_freq_shared(sg_cpu, util, max, flags);
+		if (flags & SCHED_CPUFREQ_RT_DL)
+			next_f = sg_policy->policy->cpuinfo.max_freq;
+		else
+			next_f = sugov_next_freq_shared(sg_cpu);
+
 		sugov_update_commit(sg_policy, time, next_f);
 	}
 
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 0f8c0b2..c091ca4 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -1008,6 +1008,33 @@
 		P_SCHEDSTAT(se.statistics.nr_wakeups_affine_attempts);
 		P_SCHEDSTAT(se.statistics.nr_wakeups_passive);
 		P_SCHEDSTAT(se.statistics.nr_wakeups_idle);
+		/* eas */
+		/* select_idle_sibling() */
+		P_SCHEDSTAT(se.statistics.nr_wakeups_sis_attempts);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_sis_idle);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_sis_cache_affine);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_sis_suff_cap);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_sis_idle_cpu);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_sis_count);
+		/* select_energy_cpu_brute() */
+		P_SCHEDSTAT(se.statistics.nr_wakeups_secb_attempts);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_secb_sync);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_secb_idle_bt);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_secb_insuff_cap);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_secb_no_nrg_sav);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_secb_nrg_sav);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_secb_count);
+		/* find_best_target() */
+		P_SCHEDSTAT(se.statistics.nr_wakeups_fbt_attempts);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_fbt_no_cpu);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_fbt_no_sd);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_fbt_pref_idle);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_fbt_count);
+		/* cas */
+		/* select_task_rq_fair() */
+		P_SCHEDSTAT(se.statistics.nr_wakeups_cas_attempts);
+		P_SCHEDSTAT(se.statistics.nr_wakeups_cas_count);
+ 
 #ifdef CONFIG_SCHED_WALT
 		P(ravg.demand);
 #endif
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 62a29ed..fde0639 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -160,7 +160,7 @@
 
 /*
  * The margin used when comparing utilization with CPU capacity:
- * util * 1024 < capacity * margin
+ * util * margin < capacity * 1024
  */
 unsigned int sysctl_sched_capacity_margin = 1078; /* ~5% margin */
 unsigned int sysctl_sched_capacity_margin_down = 1205; /* ~15% margin */
@@ -338,19 +338,59 @@
 static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
 {
 	if (!cfs_rq->on_list) {
+		struct rq *rq = rq_of(cfs_rq);
+		int cpu = cpu_of(rq);
 		/*
 		 * Ensure we either appear before our parent (if already
 		 * enqueued) or force our parent to appear after us when it is
-		 * enqueued.  The fact that we always enqueue bottom-up
-		 * reduces this to two cases.
+		 * enqueued. The fact that we always enqueue bottom-up
+		 * reduces this to two cases and a special case for the root
+		 * cfs_rq. Furthermore, it also means that we will always reset
+		 * tmp_alone_branch either when the branch is connected
+		 * to a tree or when we reach the beg of the tree
 		 */
 		if (cfs_rq->tg->parent &&
-		    cfs_rq->tg->parent->cfs_rq[cpu_of(rq_of(cfs_rq))]->on_list) {
-			list_add_rcu(&cfs_rq->leaf_cfs_rq_list,
-				&rq_of(cfs_rq)->leaf_cfs_rq_list);
-		} else {
+		    cfs_rq->tg->parent->cfs_rq[cpu]->on_list) {
+			/*
+			 * If parent is already on the list, we add the child
+			 * just before. Thanks to circular linked property of
+			 * the list, this means to put the child at the tail
+			 * of the list that starts by parent.
+			 */
 			list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
-				&rq_of(cfs_rq)->leaf_cfs_rq_list);
+				&(cfs_rq->tg->parent->cfs_rq[cpu]->leaf_cfs_rq_list));
+			/*
+			 * The branch is now connected to its tree so we can
+			 * reset tmp_alone_branch to the beginning of the
+			 * list.
+			 */
+			rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
+		} else if (!cfs_rq->tg->parent) {
+			/*
+			 * cfs rq without parent should be put
+			 * at the tail of the list.
+			 */
+			list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
+				&rq->leaf_cfs_rq_list);
+			/*
+			 * We have reach the beg of a tree so we can reset
+			 * tmp_alone_branch to the beginning of the list.
+			 */
+			rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
+		} else {
+			/*
+			 * The parent has not already been added so we want to
+			 * make sure that it will be put after us.
+			 * tmp_alone_branch points to the beg of the branch
+			 * where we will add parent.
+			 */
+			list_add_rcu(&cfs_rq->leaf_cfs_rq_list,
+				rq->tmp_alone_branch);
+			/*
+			 * update tmp_alone_branch to points to the new beg
+			 * of the branch
+			 */
+			rq->tmp_alone_branch = &cfs_rq->leaf_cfs_rq_list;
 		}
 
 		cfs_rq->on_list = 1;
@@ -759,9 +799,7 @@
 }
 
 static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq);
-static int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq);
-static void update_tg_load_avg(struct cfs_rq *cfs_rq, int force);
-static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se);
+static void attach_entity_cfs_rq(struct sched_entity *se);
 
 /*
  * With new tasks being created, their initial util_avgs are extrapolated
@@ -793,7 +831,6 @@
 	struct cfs_rq *cfs_rq = cfs_rq_of(se);
 	struct sched_avg *sa = &se->avg;
 	long cap = (long)(SCHED_CAPACITY_SCALE - cfs_rq->avg.util_avg) / 2;
-	u64 now = cfs_rq_clock_task(cfs_rq);
 
 	if (cap > 0) {
 		if (cfs_rq->avg.util_avg != 0) {
@@ -821,14 +858,12 @@
 			 * such that the next switched_to_fair() has the
 			 * expected state.
 			 */
-			se->avg.last_update_time = now;
+			se->avg.last_update_time = cfs_rq_clock_task(cfs_rq);
 			return;
 		}
 	}
 
-	update_cfs_rq_load_avg(now, cfs_rq, false);
-	attach_entity_load_avg(cfs_rq, se);
-	update_tg_load_avg(cfs_rq, false);
+	attach_entity_cfs_rq(se);
 }
 
 #else /* !CONFIG_SMP */
@@ -2697,16 +2732,20 @@
 
 static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
 
-static void update_cfs_shares(struct cfs_rq *cfs_rq)
+static void update_cfs_shares(struct sched_entity *se)
 {
+	struct cfs_rq *cfs_rq = group_cfs_rq(se);
 	struct task_group *tg;
-	struct sched_entity *se;
 	long shares;
 
-	tg = cfs_rq->tg;
-	se = tg->se[cpu_of(rq_of(cfs_rq))];
-	if (!se || throttled_hierarchy(cfs_rq))
+	if (!cfs_rq)
 		return;
+
+	if (throttled_hierarchy(cfs_rq))
+		return;
+
+	tg = cfs_rq->tg;
+
 #ifndef CONFIG_SMP
 	if (likely(se->load.weight == tg->shares))
 		return;
@@ -2715,8 +2754,9 @@
 
 	reweight_entity(cfs_rq_of(se), se, shares);
 }
+
 #else /* CONFIG_FAIR_GROUP_SCHED */
-static inline void update_cfs_shares(struct cfs_rq *cfs_rq)
+static inline void update_cfs_shares(struct sched_entity *se)
 {
 }
 #endif /* CONFIG_FAIR_GROUP_SCHED */
@@ -2962,6 +3002,26 @@
 	return decayed;
 }
 
+/*
+ * Signed add and clamp on underflow.
+ *
+ * Explicitly do a load-store to ensure the intermediate value never hits
+ * memory. This allows lockless observations without ever seeing the negative
+ * values.
+ */
+#define add_positive(_ptr, _val) do {                           \
+	typeof(_ptr) ptr = (_ptr);                              \
+	typeof(_val) val = (_val);                              \
+	typeof(*ptr) res, var = READ_ONCE(*ptr);                \
+								\
+	res = var + val;                                        \
+								\
+	if (val < 0 && res > var)                               \
+		res = 0;                                        \
+								\
+	WRITE_ONCE(*ptr, res);                                  \
+} while (0)
+
 #ifdef CONFIG_FAIR_GROUP_SCHED
 /**
  * update_tg_load_avg - update the tg's load avg
@@ -3041,8 +3101,138 @@
 		se->avg.last_update_time = n_last_update_time;
 	}
 }
+
+/* Take into account change of utilization of a child task group */
+static inline void
+update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	struct cfs_rq *gcfs_rq = group_cfs_rq(se);
+	long delta = gcfs_rq->avg.util_avg - se->avg.util_avg;
+
+	/* Nothing to update */
+	if (!delta)
+		return;
+
+	/* Set new sched_entity's utilization */
+	se->avg.util_avg = gcfs_rq->avg.util_avg;
+	se->avg.util_sum = se->avg.util_avg * LOAD_AVG_MAX;
+
+	/* Update parent cfs_rq utilization */
+	add_positive(&cfs_rq->avg.util_avg, delta);
+	cfs_rq->avg.util_sum = cfs_rq->avg.util_avg * LOAD_AVG_MAX;
+}
+
+/* Take into account change of load of a child task group */
+static inline void
+update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	struct cfs_rq *gcfs_rq = group_cfs_rq(se);
+	long delta, load = gcfs_rq->avg.load_avg;
+
+	/*
+	 * If the load of group cfs_rq is null, the load of the
+	 * sched_entity will also be null so we can skip the formula
+	 */
+	if (load) {
+		long tg_load;
+
+		/* Get tg's load and ensure tg_load > 0 */
+		tg_load = atomic_long_read(&gcfs_rq->tg->load_avg) + 1;
+
+		/* Ensure tg_load >= load and updated with current load*/
+		tg_load -= gcfs_rq->tg_load_avg_contrib;
+		tg_load += load;
+
+		/*
+		 * We need to compute a correction term in the case that the
+		 * task group is consuming more CPU than a task of equal
+		 * weight. A task with a weight equals to tg->shares will have
+		 * a load less or equal to scale_load_down(tg->shares).
+		 * Similarly, the sched_entities that represent the task group
+		 * at parent level, can't have a load higher than
+		 * scale_load_down(tg->shares). And the Sum of sched_entities'
+		 * load must be <= scale_load_down(tg->shares).
+		 */
+		if (tg_load > scale_load_down(gcfs_rq->tg->shares)) {
+			/* scale gcfs_rq's load into tg's shares*/
+			load *= scale_load_down(gcfs_rq->tg->shares);
+			load /= tg_load;
+		}
+	}
+
+	delta = load - se->avg.load_avg;
+
+	/* Nothing to update */
+	if (!delta)
+		return;
+
+	/* Set new sched_entity's load */
+	se->avg.load_avg = load;
+	se->avg.load_sum = se->avg.load_avg * LOAD_AVG_MAX;
+
+	/* Update parent cfs_rq load */
+	add_positive(&cfs_rq->avg.load_avg, delta);
+	cfs_rq->avg.load_sum = cfs_rq->avg.load_avg * LOAD_AVG_MAX;
+
+	/*
+	 * If the sched_entity is already enqueued, we also have to update the
+	 * runnable load avg.
+	 */
+	if (se->on_rq) {
+		/* Update parent cfs_rq runnable_load_avg */
+		add_positive(&cfs_rq->runnable_load_avg, delta);
+		cfs_rq->runnable_load_sum = cfs_rq->runnable_load_avg * LOAD_AVG_MAX;
+	}
+}
+
+static inline void set_tg_cfs_propagate(struct cfs_rq *cfs_rq)
+{
+	cfs_rq->propagate_avg = 1;
+}
+
+static inline int test_and_clear_tg_cfs_propagate(struct sched_entity *se)
+{
+	struct cfs_rq *cfs_rq = group_cfs_rq(se);
+
+	if (!cfs_rq->propagate_avg)
+		return 0;
+
+	cfs_rq->propagate_avg = 0;
+	return 1;
+}
+
+/* Update task and its cfs_rq load average */
+static inline int propagate_entity_load_avg(struct sched_entity *se)
+{
+	struct cfs_rq *cfs_rq;
+
+	if (entity_is_task(se))
+		return 0;
+
+	if (!test_and_clear_tg_cfs_propagate(se))
+		return 0;
+
+	cfs_rq = cfs_rq_of(se);
+
+	set_tg_cfs_propagate(cfs_rq);
+
+	update_tg_cfs_util(cfs_rq, se);
+	update_tg_cfs_load(cfs_rq, se);
+
+	return 1;
+}
+
 #else /* CONFIG_FAIR_GROUP_SCHED */
+
 static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) {}
+
+static inline int propagate_entity_load_avg(struct sched_entity *se)
+{
+	return 0;
+}
+
+static inline void set_tg_cfs_propagate(struct cfs_rq *cfs_rq) {}
+
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq)
@@ -3113,6 +3303,7 @@
 		sub_positive(&sa->load_avg, r);
 		sub_positive(&sa->load_sum, r * LOAD_AVG_MAX);
 		removed_load = 1;
+		set_tg_cfs_propagate(cfs_rq);
 	}
 
 	if (atomic_long_read(&cfs_rq->removed_util_avg)) {
@@ -3120,6 +3311,7 @@
 		sub_positive(&sa->util_avg, r);
 		sub_positive(&sa->util_sum, r * LOAD_AVG_MAX);
 		removed_util = 1;
+		set_tg_cfs_propagate(cfs_rq);
 	}
 
 	decayed = __update_load_avg(now, cpu_of(rq_of(cfs_rq)), sa,
@@ -3133,31 +3325,46 @@
 	if (update_freq && (decayed || removed_util))
 		cfs_rq_util_change(cfs_rq);
 
+	/* Trace CPU load, unless cfs_rq belongs to a non-root task_group */
+	if (cfs_rq == &rq_of(cfs_rq)->cfs)
+		trace_sched_load_avg_cpu(cpu_of(rq_of(cfs_rq)), cfs_rq);
+
 	return decayed || removed_load;
 }
 
+/*
+ * Optional action to be done while updating the load average
+ */
+#define UPDATE_TG	0x1
+#define SKIP_AGE_LOAD	0x2
+
 /* Update task and its cfs_rq load average */
-static inline void update_load_avg(struct sched_entity *se, int update_tg)
+static inline void update_load_avg(struct sched_entity *se, int flags)
 {
 	struct cfs_rq *cfs_rq = cfs_rq_of(se);
 	u64 now = cfs_rq_clock_task(cfs_rq);
 	struct rq *rq = rq_of(cfs_rq);
 	int cpu = cpu_of(rq);
+	int decayed;
 
 	/*
 	 * Track task load average for carrying it to new CPU after migrated, and
 	 * track group sched_entity load average for task_h_load calc in migration
 	 */
-	__update_load_avg(now, cpu, &se->avg,
+	if (se->avg.last_update_time && !(flags & SKIP_AGE_LOAD)) {
+		__update_load_avg(now, cpu, &se->avg,
 			  se->on_rq * scale_load_down(se->load.weight),
 			  cfs_rq->curr == se, NULL);
+	}
 
-	if (update_cfs_rq_load_avg(now, cfs_rq, true) && update_tg)
+	decayed  = update_cfs_rq_load_avg(now, cfs_rq, true);
+	decayed |= propagate_entity_load_avg(se);
+
+	if (decayed && (flags & UPDATE_TG))
 		update_tg_load_avg(cfs_rq, 0);
 
 	if (entity_is_task(se))
 		trace_sched_load_avg_task(task_of(se), &se->avg);
-	trace_sched_load_avg_cpu(cpu, cfs_rq);
 }
 
 /**
@@ -3170,31 +3377,12 @@
  */
 static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-	if (!sched_feat(ATTACH_AGE_LOAD))
-		goto skip_aging;
-
-	/*
-	 * If we got migrated (either between CPUs or between cgroups) we'll
-	 * have aged the average right before clearing @last_update_time.
-	 *
-	 * Or we're fresh through post_init_entity_util_avg().
-	 */
-	if (se->avg.last_update_time) {
-		__update_load_avg(cfs_rq->avg.last_update_time, cpu_of(rq_of(cfs_rq)),
-				  &se->avg, 0, 0, NULL);
-
-		/*
-		 * XXX: we could have just aged the entire load away if we've been
-		 * absent from the fair class for too long.
-		 */
-	}
-
-skip_aging:
 	se->avg.last_update_time = cfs_rq->avg.last_update_time;
 	cfs_rq->avg.load_avg += se->avg.load_avg;
 	cfs_rq->avg.load_sum += se->avg.load_sum;
 	cfs_rq->avg.util_avg += se->avg.util_avg;
 	cfs_rq->avg.util_sum += se->avg.util_sum;
+	set_tg_cfs_propagate(cfs_rq);
 
 	cfs_rq_util_change(cfs_rq);
 }
@@ -3209,14 +3397,12 @@
  */
 static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-	__update_load_avg(cfs_rq->avg.last_update_time, cpu_of(rq_of(cfs_rq)),
-			  &se->avg, se->on_rq * scale_load_down(se->load.weight),
-			  cfs_rq->curr == se, NULL);
 
 	sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg);
 	sub_positive(&cfs_rq->avg.load_sum, se->avg.load_sum);
 	sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg);
 	sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum);
+	set_tg_cfs_propagate(cfs_rq);
 
 	cfs_rq_util_change(cfs_rq);
 }
@@ -3226,34 +3412,20 @@
 enqueue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
 	struct sched_avg *sa = &se->avg;
-	u64 now = cfs_rq_clock_task(cfs_rq);
-	int migrated, decayed;
-
-	migrated = !sa->last_update_time;
-	if (!migrated) {
-		__update_load_avg(now, cpu_of(rq_of(cfs_rq)), sa,
-			se->on_rq * scale_load_down(se->load.weight),
-			cfs_rq->curr == se, NULL);
-	}
-
-	decayed = update_cfs_rq_load_avg(now, cfs_rq, !migrated);
 
 	cfs_rq->runnable_load_avg += sa->load_avg;
 	cfs_rq->runnable_load_sum += sa->load_sum;
 
-	if (migrated)
+	if (!sa->last_update_time) {
 		attach_entity_load_avg(cfs_rq, se);
-
-	if (decayed || migrated)
 		update_tg_load_avg(cfs_rq, 0);
+	}
 }
 
 /* Remove the runnable load generated by se from cfs_rq's runnable load average */
 static inline void
 dequeue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-	update_load_avg(se, 1);
-
 	cfs_rq->runnable_load_avg =
 		max_t(long, cfs_rq->runnable_load_avg - se->avg.load_avg, 0);
 	cfs_rq->runnable_load_sum =
@@ -3282,13 +3454,25 @@
 #endif
 
 /*
+ * Synchronize entity load avg of dequeued entity without locking
+ * the previous rq.
+ */
+void sync_entity_load_avg(struct sched_entity *se)
+{
+	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+	u64 last_update_time;
+
+	last_update_time = cfs_rq_last_update_time(cfs_rq);
+	__update_load_avg(last_update_time, cpu_of(rq_of(cfs_rq)), &se->avg, 0, 0, NULL);
+}
+
+/*
  * Task first catches up with cfs_rq, and then subtract
  * itself from the cfs_rq (task must be off the queue now).
  */
 void remove_entity_load_avg(struct sched_entity *se)
 {
 	struct cfs_rq *cfs_rq = cfs_rq_of(se);
-	u64 last_update_time;
 
 	/*
 	 * tasks cannot exit without having gone through wake_up_new_task() ->
@@ -3300,9 +3484,7 @@
 	 * calls this.
 	 */
 
-	last_update_time = cfs_rq_last_update_time(cfs_rq);
-
-	__update_load_avg(last_update_time, cpu_of(rq_of(cfs_rq)), &se->avg, 0, 0, NULL);
+	sync_entity_load_avg(se);
 	atomic_long_add(se->avg.load_avg, &cfs_rq->removed_load_avg);
 	atomic_long_add(se->avg.util_avg, &cfs_rq->removed_util_avg);
 }
@@ -3327,7 +3509,10 @@
 	return 0;
 }
 
-static inline void update_load_avg(struct sched_entity *se, int not_used)
+#define UPDATE_TG	0x0
+#define SKIP_AGE_LOAD	0x0
+
+static inline void update_load_avg(struct sched_entity *se, int not_used1)
 {
 	cpufreq_update_util(rq_of(cfs_rq_of(se)), 0);
 }
@@ -3472,9 +3657,18 @@
 	if (renorm && !curr)
 		se->vruntime += cfs_rq->min_vruntime;
 
+	/*
+	 * When enqueuing a sched_entity, we must:
+	 *   - Update loads to have both entity and cfs_rq synced with now.
+	 *   - Add its load to cfs_rq->runnable_avg
+	 *   - For group_entity, update its weight to reflect the new share of
+	 *     its group cfs_rq
+	 *   - Add its new weight to cfs_rq->load.weight
+	 */
+	update_load_avg(se, UPDATE_TG);
 	enqueue_entity_load_avg(cfs_rq, se);
+	update_cfs_shares(se);
 	account_entity_enqueue(cfs_rq, se);
-	update_cfs_shares(cfs_rq);
 
 	if (flags & ENQUEUE_WAKEUP)
 		place_entity(cfs_rq, se, 0);
@@ -3546,6 +3740,16 @@
 	 * Update run-time statistics of the 'current'.
 	 */
 	update_curr(cfs_rq);
+
+	/*
+	 * When dequeuing a sched_entity, we must:
+	 *   - Update loads to have both entity and cfs_rq synced with now.
+	 *   - Substract its load from the cfs_rq->runnable_avg.
+	 *   - Substract its previous weight from cfs_rq->load.weight.
+	 *   - For group entity, update its weight to reflect the new share
+	 *     of its group cfs_rq.
+	 */
+	update_load_avg(se, UPDATE_TG);
 	dequeue_entity_load_avg(cfs_rq, se);
 
 	update_stats_dequeue(cfs_rq, se, flags);
@@ -3569,7 +3773,7 @@
 	/* return excess runtime on last dequeue */
 	return_cfs_rq_runtime(cfs_rq);
 
-	update_cfs_shares(cfs_rq);
+	update_cfs_shares(se);
 
 	/*
 	 * Now advance min_vruntime if @se was the entity holding it back,
@@ -3633,7 +3837,7 @@
 		 */
 		update_stats_wait_end(cfs_rq, se);
 		__dequeue_entity(cfs_rq, se);
-		update_load_avg(se, 1);
+		update_load_avg(se, UPDATE_TG);
 	}
 
 	update_stats_curr_start(cfs_rq, se);
@@ -3751,8 +3955,8 @@
 	/*
 	 * Ensure that runnable average is periodically updated.
 	 */
-	update_load_avg(curr, 1);
-	update_cfs_shares(cfs_rq);
+	update_load_avg(curr, UPDATE_TG);
+	update_cfs_shares(curr);
 
 #ifdef CONFIG_SCHED_HRTICK
 	/*
@@ -4614,9 +4818,9 @@
 #ifdef CONFIG_SMP
 static unsigned long capacity_orig_of(int cpu);
 static unsigned long cpu_util(int cpu);
-static inline unsigned long boosted_cpu_util(int cpu);
+unsigned long boosted_cpu_util(int cpu);
 #else
-#define boosted_cpu_util(cpu) cpu_util(cpu)
+#define boosted_cpu_util(cpu) cpu_util_freq(cpu)
 #endif
 
 #ifdef CONFIG_SMP
@@ -4688,8 +4892,8 @@
 		if (cfs_rq_throttled(cfs_rq))
 			break;
 
-		update_load_avg(se, 1);
-		update_cfs_shares(cfs_rq);
+		update_load_avg(se, UPDATE_TG);
+		update_cfs_shares(se);
 	}
 
 	if (!se) {
@@ -4699,6 +4903,25 @@
 
 #ifdef CONFIG_SMP
 
+	/*
+	 * Update SchedTune accounting.
+	 *
+	 * We do it before updating the CPU capacity to ensure the
+	 * boost value of the current task is accounted for in the
+	 * selection of the OPP.
+	 *
+	 * We do it also in the case where we enqueue a throttled task;
+	 * we could argue that a throttled task should not boost a CPU,
+	 * however:
+	 * a) properly implementing CPU boosting considering throttled
+	 *    tasks will increase a lot the complexity of the solution
+	 * b) it's not easy to quantify the benefits introduced by
+	 *    such a more complex solution.
+	 * Thus, for the time being we go for the simple solution and boost
+	 * also for throttled RQs.
+	 */
+	schedtune_enqueue_task(p, cpu_of(rq));
+
 	if (!se) {
 		if (!task_new && !rq->rd->overutilized &&
 		    cpu_overutilized(rq->cpu)) {
@@ -4717,9 +4940,6 @@
 			update_capacity_of(cpu_of(rq));
 	}
 
-	/* Update SchedTune accouting */
-	schedtune_enqueue_task(p, cpu_of(rq));
-
 #endif /* CONFIG_SMP */
 	hrtick_update(rq);
 }
@@ -4775,8 +4995,8 @@
 		if (cfs_rq_throttled(cfs_rq))
 			break;
 
-		update_load_avg(se, 1);
-		update_cfs_shares(cfs_rq);
+		update_load_avg(se, UPDATE_TG);
+		update_cfs_shares(se);
 	}
 
 	if (!se) {
@@ -4786,6 +5006,15 @@
 
 #ifdef CONFIG_SMP
 
+	/*
+	 * Update SchedTune accounting
+	 *
+	 * We do it before updating the CPU capacity to ensure the
+	 * boost value of the current task is accounted for in the
+	 * selection of the OPP.
+	 */
+	schedtune_dequeue_task(p, cpu_of(rq));
+
 	if (!se) {
 		if (rq->cfs.nr_running)
 			update_capacity_of(cpu_of(rq));
@@ -4793,9 +5022,6 @@
 			set_cfs_cpu_capacity(cpu_of(rq), false, 0);
 	}
 
-	/* Update SchedTune accouting */
-	schedtune_dequeue_task(p, cpu_of(rq));
-
 #endif /* CONFIG_SMP */
 
 	hrtick_update(rq);
@@ -5449,9 +5675,11 @@
 	return idx;
 }
 
-static int group_idle_state(struct sched_group *sg)
+static int group_idle_state(struct energy_env *eenv, struct sched_group *sg)
 {
 	int i, state = INT_MAX;
+	int src_in_grp, dst_in_grp;
+	long grp_util = 0;
 
 	/* Find the shallowest idle state in the sched group. */
 	for_each_cpu(i, sched_group_cpus(sg))
@@ -5463,6 +5691,54 @@
 	/* Take non-cpuidle idling into account (active idle/arch_cpu_idle()) */
 	state++;
 
+	/*
+	 * Try to estimate if a deeper idle state is
+	 * achievable when we move the task.
+	 */
+	for_each_cpu(i, sched_group_cpus(sg))
+		grp_util += cpu_util(i);
+
+	src_in_grp = cpumask_test_cpu(eenv->src_cpu, sched_group_cpus(sg));
+	dst_in_grp = cpumask_test_cpu(eenv->dst_cpu, sched_group_cpus(sg));
+	if (src_in_grp == dst_in_grp) {
+		/* both CPUs under consideration are in the same group or not in
+		 * either group, migration should leave idle state the same.
+		 */
+		goto end;
+	}
+	/* add or remove util as appropriate to indicate what group util
+	 * will be (worst case - no concurrent execution) after moving the task
+	 */
+	grp_util += src_in_grp ? -eenv->util_delta : eenv->util_delta;
+
+	if (grp_util <=
+		((long)sg->sgc->max_capacity * (int)sg->group_weight)) {
+		/* after moving, this group is at most partly
+		 * occupied, so it should have some idle time.
+		 */
+		int max_idle_state_idx = sg->sge->nr_idle_states - 2;
+		int new_state = grp_util * max_idle_state_idx;
+		if (grp_util <= 0)
+			/* group will have no util, use lowest state */
+			new_state = max_idle_state_idx + 1;
+		else {
+			/* for partially idle, linearly map util to idle
+			 * states, excluding the lowest one. This does not
+			 * correspond to the state we expect to enter in
+			 * reality, but an indication of what might happen.
+			 */
+			new_state = min(max_idle_state_idx, (int)
+					(new_state / sg->sgc->max_capacity));
+			new_state = max_idle_state_idx - new_state;
+		}
+		state = new_state;
+	} else {
+		/* After moving, the group will be fully occupied
+		 * so assume it will not be idle at all.
+		 */
+		state = 0;
+	}
+end:
 	return state;
 }
 
@@ -5499,15 +5775,7 @@
 		 */
 		sd = rcu_dereference(per_cpu(sd_scs, cpu));
 
-		if (!sd)
-			/*
-			 * We most probably raced with hotplug; returning a
-			 * wrong energy estimation is better than entering an
-			 * infinite loop.
-			 */
-			return -EINVAL;
-
-		if (sd->parent)
+		if (sd && sd->parent)
 			sg_shared_cap = sd->parent->groups;
 
 		for_each_domain(cpu, sd) {
@@ -5544,7 +5812,7 @@
 					}
 				}
 
-				idle_idx = group_idle_state(sg);
+				idle_idx = group_idle_state(eenv, sg);
 				if (unlikely(idle_idx < 0))
 					return idle_idx;
 
@@ -5577,6 +5845,14 @@
 
 			} while (sg = sg->next, sg != sd->groups);
 		}
+
+		/*
+		 * If we raced with hotplug and got an sd NULL-pointer;
+		 * returning a wrong energy estimation is better than
+		 * entering an infinite loop.
+		 */
+		if (cpumask_test_cpu(cpu, &visit_cpus))
+			return -EINVAL;
 next_cpu:
 		cpumask_clear_cpu(cpu, &visit_cpus);
 		continue;
@@ -5603,6 +5879,7 @@
 	struct sched_domain *sd;
 	struct sched_group *sg;
 	int sd_cpu = -1, energy_before = 0, energy_after = 0;
+	int diff, margin;
 
 	struct energy_env eenv_before = {
 		.util_delta	= 0,
@@ -5647,12 +5924,22 @@
 	eenv->nrg.after = energy_after;
 	eenv->nrg.diff = eenv->nrg.after - eenv->nrg.before;
 	eenv->payoff = 0;
-
+#ifndef CONFIG_SCHED_TUNE
 	trace_sched_energy_diff(eenv->task,
 			eenv->src_cpu, eenv->dst_cpu, eenv->util_delta,
 			eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff,
 			eenv->cap.before, eenv->cap.after, eenv->cap.delta,
 			eenv->nrg.delta, eenv->payoff);
+#endif
+	/*
+	 * Dead-zone margin preventing too many migrations.
+	 */
+
+	margin = eenv->nrg.before >> 6; /* ~1.56% */
+
+	diff = eenv->nrg.after - eenv->nrg.before;
+
+	eenv->nrg.diff = (abs(diff) < margin) ? 0 : eenv->nrg.diff;
 
 	return eenv->nrg.diff;
 }
@@ -5660,23 +5947,30 @@
 #ifdef CONFIG_SCHED_TUNE
 
 struct target_nrg schedtune_target_nrg;
-
+extern bool schedtune_initialized;
 /*
  * System energy normalization
- * Returns the normalized value, in the range [0..SCHED_LOAD_SCALE],
+ * Returns the normalized value, in the range [0..SCHED_CAPACITY_SCALE],
  * corresponding to the specified energy variation.
  */
 static inline int
 normalize_energy(int energy_diff)
 {
 	u32 normalized_nrg;
+
+	/* during early setup, we don't know the extents */
+	if (unlikely(!schedtune_initialized))
+		return energy_diff < 0 ? -1 : 1 ;
+
 #ifdef CONFIG_SCHED_DEBUG
+	{
 	int max_delta;
 
 	/* Check for boundaries */
 	max_delta  = schedtune_target_nrg.max_power;
 	max_delta -= schedtune_target_nrg.min_power;
 	WARN_ON(abs(energy_diff) >= max_delta);
+	}
 #endif
 
 	/* Do scaling using positive numbers to increase the range */
@@ -5695,18 +5989,13 @@
 static inline int
 energy_diff(struct energy_env *eenv)
 {
-	unsigned int boost;
+	int boost = schedtune_task_boost(eenv->task);
 	int nrg_delta;
 
 	/* Conpute "absolute" energy diff */
 	__energy_diff(eenv);
 
 	/* Return energy diff when boost margin is 0 */
-#ifdef CONFIG_CGROUP_SCHEDTUNE
-	boost = schedtune_task_boost(eenv->task);
-#else
-	boost = get_sysctl_sched_cfs_boost();
-#endif
 	if (boost == 0)
 		return eenv->nrg.diff;
 
@@ -5719,6 +6008,12 @@
 			eenv->cap.delta,
 			eenv->task);
 
+	trace_sched_energy_diff(eenv->task,
+			eenv->src_cpu, eenv->dst_cpu, eenv->util_delta,
+			eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff,
+			eenv->cap.before, eenv->cap.after, eenv->cap.delta,
+			eenv->nrg.delta, eenv->payoff);
+
 	/*
 	 * When SchedTune is enabled, the energy_diff() function will return
 	 * the computed energy payoff value. Since the energy_diff() return
@@ -5878,6 +6173,8 @@
 
 #ifdef CONFIG_SCHED_TUNE
 
+struct reciprocal_value schedtune_spc_rdiv;
+
 static long
 schedtune_margin(unsigned long signal, long boost)
 {
@@ -5888,30 +6185,16 @@
 	 *
 	 * The Boost (B) value is used to compute a Margin (M) which is
 	 * proportional to the complement of the original Signal (S):
-	 *   M = B * (SCHED_LOAD_SCALE - S), if B is positive
-	 *   M = B * S, if B is negative
+	 *   M = B * (SCHED_CAPACITY_SCALE - S)
 	 * The obtained M could be used by the caller to "boost" S.
 	 */
-
 	if (boost >= 0) {
 		margin  = SCHED_CAPACITY_SCALE - signal;
 		margin *= boost;
 	} else
 		margin = -signal * boost;
-	/*
-	 * Fast integer division by constant:
-	 *  Constant   :                 (C) = 100
-	 *  Precision  : 0.1%            (P) = 0.1
-	 *  Reference  : C * 100 / P     (R) = 100000
-	 *
-	 * Thus:
-	 *  Shift bits : ceil(log(R,2))  (S) = 17
-	 *  Mult const : round(2^S/C)    (M) = 1311
-	 *
-	 *
-	 */
-	margin  *= 1311;
-	margin >>= 17;
+
+	margin  = reciprocal_divide(margin, schedtune_spc_rdiv);
 
 	if (boost < 0)
 		margin *= -1;
@@ -5921,13 +6204,8 @@
 static inline int
 schedtune_cpu_margin(unsigned long util, int cpu)
 {
-	int boost;
+	int boost = schedtune_cpu_boost(cpu);
 
-#ifdef CONFIG_CGROUP_SCHEDTUNE
-	boost = schedtune_cpu_boost(cpu);
-#else
-	boost = get_sysctl_sched_cfs_boost();
-#endif
 	if (boost == 0)
 		return 0;
 
@@ -5937,15 +6215,10 @@
 static inline long
 schedtune_task_margin(struct task_struct *task)
 {
-	int boost;
+	int boost = schedtune_task_boost(task);
 	unsigned long util;
 	long margin;
 
-#ifdef CONFIG_CGROUP_SCHEDTUNE
-	boost = schedtune_task_boost(task);
-#else
-	boost = get_sysctl_sched_cfs_boost();
-#endif
 	if (boost == 0)
 		return 0;
 
@@ -5971,7 +6244,7 @@
 
 #endif /* CONFIG_SCHED_TUNE */
 
-static inline unsigned long
+unsigned long
 boosted_cpu_util(int cpu)
 {
 	unsigned long util = cpu_util_freq(cpu, NULL);
@@ -6317,20 +6590,29 @@
 	struct sched_domain *sd;
 	struct sched_group *sg;
 	int i = task_cpu(p);
-	int best_idle = -1;
-	int best_idle_cstate = -1;
-	int best_idle_capacity = INT_MAX;
+	int best_idle_cpu = -1;
+	int best_idle_cstate = INT_MAX;
+	unsigned long best_idle_capacity = ULONG_MAX;
+
+	schedstat_inc(p->se.statistics.nr_wakeups_sis_attempts);
+	schedstat_inc(this_rq()->eas_stats.sis_attempts);
 
 	if (!sysctl_sched_cstate_aware) {
-		if (idle_cpu(target) && !cpu_isolated(target))
+		if (idle_cpu(target) && !cpu_isolated(target)) {
+			schedstat_inc(p->se.statistics.nr_wakeups_sis_idle);
+			schedstat_inc(this_rq()->eas_stats.sis_idle);
 			return target;
+		}
 
 		/*
 		 * If the prevous cpu is cache affine and idle, don't be stupid.
 		 */
 		if (i != target && cpus_share_cache(i, target) &&
-				idle_cpu(i) && !cpu_isolated(i))
+				idle_cpu(i) && !cpu_isolated(i)) {
+			schedstat_inc(p->se.statistics.nr_wakeups_sis_cache_affine);
+			schedstat_inc(this_rq()->eas_stats.sis_cache_affine);
 			return i;
+		}
 
 		sd = rcu_dereference(per_cpu(sd_llc, target));
 		if (!sd)
@@ -6363,8 +6645,7 @@
 
 			if (sysctl_sched_cstate_aware) {
 				for_each_cpu_and(i, tsk_cpus_allowed(p), sched_group_cpus(sg)) {
-					struct rq *rq = cpu_rq(i);
-					int idle_idx = idle_get_state_idx(rq);
+					int idle_idx = idle_get_state_idx(cpu_rq(i));
 					unsigned long new_usage = boosted_task_util(p);
 					unsigned long capacity_orig = capacity_orig_of(i);
 
@@ -6374,11 +6655,16 @@
 					if (new_usage > capacity_orig || !idle_cpu(i))
 						goto next;
 
-					if (i == target && new_usage <= capacity_curr_of(target))
+					if (i == target && new_usage <= capacity_curr_of(target)) {
+						schedstat_inc(p->se.statistics.nr_wakeups_sis_suff_cap);
+						schedstat_inc(this_rq()->eas_stats.sis_suff_cap);
+						schedstat_inc(sd->eas_stats.sis_suff_cap);
 						return target;
+					}
 
-					if (best_idle < 0 || (idle_idx < best_idle_cstate && capacity_orig <= best_idle_capacity)) {
-						best_idle = i;
+					if (idle_idx < best_idle_cstate &&
+					    capacity_orig <= best_idle_capacity) {
+						best_idle_cpu = i;
 						best_idle_cstate = idle_idx;
 						best_idle_capacity = capacity_orig;
 					}
@@ -6394,19 +6680,26 @@
 
 				target = cpumask_first_and(sched_group_cpus(sg),
 					tsk_cpus_allowed(p));
+				schedstat_inc(p->se.statistics.nr_wakeups_sis_idle_cpu);
+				schedstat_inc(this_rq()->eas_stats.sis_idle_cpu);
+				schedstat_inc(sd->eas_stats.sis_idle_cpu);
 				goto done;
 			}
 next:
 			sg = sg->next;
 		} while (sg != sd->groups);
 	}
-	if (best_idle > 0)
-		target = best_idle;
+
+	if (best_idle_cpu >= 0)
+		target = best_idle_cpu;
 
 done:
+	schedstat_inc(p->se.statistics.nr_wakeups_sis_count);
+	schedstat_inc(this_rq()->eas_stats.sis_count);
+
 	return target;
 }
-
+ 
 static inline int find_best_target(struct task_struct *p, bool boosted, bool prefer_idle)
 {
 	int iter_cpu;
@@ -8046,6 +8339,10 @@
 
 		if (update_cfs_rq_load_avg(cfs_rq_clock_task(cfs_rq), cfs_rq, true))
 			update_tg_load_avg(cfs_rq, 0);
+
+		/* Propagate pending load changes to the parent */
+		if (cfs_rq->tg->se[cpu])
+			update_load_avg(cfs_rq->tg->se[cpu], 0);
 	}
 	raw_spin_unlock_irqrestore(&rq->lock, flags);
 }
@@ -8270,7 +8567,6 @@
 	raw_spin_unlock_irqrestore(&mcc->lock, flags);
 
 skip_unlock: __attribute__ ((unused));
-	sdg->sgc->max_capacity = capacity;
 
 	capacity *= scale_rt_capacity(cpu);
 	capacity >>= SCHED_CAPACITY_SHIFT;
@@ -8280,13 +8576,15 @@
 
 	cpu_rq(cpu)->cpu_capacity = capacity;
 	sdg->sgc->capacity = capacity;
+	sdg->sgc->max_capacity = capacity;
+	sdg->sgc->min_capacity = capacity;
 }
 
 void update_group_capacity(struct sched_domain *sd, int cpu)
 {
 	struct sched_domain *child = sd->child;
 	struct sched_group *group, *sdg = sd->groups;
-	unsigned long capacity, max_capacity;
+	unsigned long capacity, max_capacity, min_capacity;
 	unsigned long interval;
 
 	interval = msecs_to_jiffies(sd->balance_interval);
@@ -8300,6 +8598,7 @@
 
 	capacity = 0;
 	max_capacity = 0;
+	min_capacity = ULONG_MAX;
 
 	if (child->flags & SD_OVERLAP) {
 		/*
@@ -8332,6 +8631,7 @@
 			}
 
 			max_capacity = max(capacity, max_capacity);
+			min_capacity = min(capacity, min_capacity);
 		}
 	} else  {
 		/*
@@ -8348,6 +8648,7 @@
 			if (!cpu_isolated(cpumask_first(cpus))) {
 				capacity += sgc->capacity;
 				max_capacity = max(sgc->max_capacity, max_capacity);
+				min_capacity = min(sgc->min_capacity, min_capacity);
 			}
 			group = group->next;
 		} while (group != child->groups);
@@ -8355,6 +8656,7 @@
 
 	sdg->sgc->capacity = capacity;
 	sdg->sgc->max_capacity = max_capacity;
+	sdg->sgc->min_capacity = min_capacity;
 }
 
 /*
@@ -8598,6 +8900,16 @@
 	if (sgs->avg_load <= busiest->avg_load)
 		return false;
 
+	if (!(env->sd->flags & SD_ASYM_CPUCAPACITY))
+		goto asym_packing;
+
+	/*
+	 * Candidate sg has no more than one task per CPU and
+	 * has higher per-CPU capacity. Migrating tasks to less
+	 * capable CPUs may harm throughput. Maximize throughput,
+	 * power/energy consequences are not considered.
+	 */
+
 	/*
 	 * Candiate sg has no more than one task per cpu and has higher
 	 * per-cpu capacity. No reason to pull tasks to less capable cpus.
@@ -8606,6 +8918,7 @@
 	    group_smaller_cpu_capacity(sds->local, sg))
 		return false;
 
+asym_packing:
 	/* This is the busiest node in its class. */
 	if (!(env->sd->flags & SD_ASYM_PACKING))
 		return true;
@@ -8660,6 +8973,9 @@
 }
 #endif /* CONFIG_NUMA_BALANCING */
 
+#define lb_sd_parent(sd) \
+	(sd->parent && sd->parent->groups != sd->parent->groups->next)
+
 /**
  * update_sd_lb_stats - Update sched_domain's statistics for load balancing.
  * @env: The load balancing environment.
@@ -8744,7 +9060,7 @@
 
 	env->src_grp_nr_running = sds->busiest_stat.sum_nr_running;
 
-	if (!env->sd->parent) {
+	if (!lb_sd_parent(env->sd)) {
 		/* update overload indicator if we are at root domain */
 		if (env->dst_rq->rd->overload != overload)
 			env->dst_rq->rd->overload = overload;
@@ -10246,8 +10562,13 @@
 	if (time_before(now, nohz.next_balance))
 		return false;
 
+	if (rq->nr_running >= 2 &&
+	    (!energy_aware() || cpu_overutilized(cpu)))
+		return true;
+
+	/* Do idle load balance if there have misfit task */
 	if (energy_aware())
-		return rq->nr_running >= 2 && cpu_overutilized(cpu);
+		return rq->misfit_task;
 
 	rcu_read_lock();
 	sds = rcu_dereference(per_cpu(sd_llc_shared, cpu));
@@ -10475,11 +10796,65 @@
 	return false;
 }
 
+#ifdef CONFIG_FAIR_GROUP_SCHED
+/*
+ * Propagate the changes of the sched_entity across the tg tree to make it
+ * visible to the root
+ */
+static void propagate_entity_cfs_rq(struct sched_entity *se)
+{
+	struct cfs_rq *cfs_rq;
+
+	/* Start to propagate at parent */
+	se = se->parent;
+
+	for_each_sched_entity(se) {
+		cfs_rq = cfs_rq_of(se);
+
+		if (cfs_rq_throttled(cfs_rq))
+			break;
+
+		update_load_avg(se, UPDATE_TG);
+	}
+}
+#else
+static void propagate_entity_cfs_rq(struct sched_entity *se) { }
+#endif
+
+static void detach_entity_cfs_rq(struct sched_entity *se)
+{
+	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+	/* Catch up with the cfs_rq and remove our load when we leave */
+	update_load_avg(se, 0);
+	detach_entity_load_avg(cfs_rq, se);
+	update_tg_load_avg(cfs_rq, false);
+	propagate_entity_cfs_rq(se);
+}
+
+static void attach_entity_cfs_rq(struct sched_entity *se)
+{
+	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+	/*
+	 * Since the real-depth could have been changed (only FAIR
+	 * class maintain depth value), reset depth properly.
+	 */
+	se->depth = se->parent ? se->parent->depth + 1 : 0;
+#endif
+
+	/* Synchronize entity with its cfs_rq */
+	update_load_avg(se, sched_feat(ATTACH_AGE_LOAD) ? 0 : SKIP_AGE_LOAD);
+	attach_entity_load_avg(cfs_rq, se);
+	update_tg_load_avg(cfs_rq, false);
+	propagate_entity_cfs_rq(se);
+}
+
 static void detach_task_cfs_rq(struct task_struct *p)
 {
 	struct sched_entity *se = &p->se;
 	struct cfs_rq *cfs_rq = cfs_rq_of(se);
-	u64 now = cfs_rq_clock_task(cfs_rq);
 
 	if (!vruntime_normalized(p)) {
 		/*
@@ -10490,30 +10865,15 @@
 		se->vruntime -= cfs_rq->min_vruntime;
 	}
 
-	/* Catch up with the cfs_rq and remove our load when we leave */
-	update_cfs_rq_load_avg(now, cfs_rq, false);
-	detach_entity_load_avg(cfs_rq, se);
-	update_tg_load_avg(cfs_rq, false);
+	detach_entity_cfs_rq(se);
 }
 
 static void attach_task_cfs_rq(struct task_struct *p)
 {
 	struct sched_entity *se = &p->se;
 	struct cfs_rq *cfs_rq = cfs_rq_of(se);
-	u64 now = cfs_rq_clock_task(cfs_rq);
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
-	/*
-	 * Since the real-depth could have been changed (only FAIR
-	 * class maintain depth value), reset depth properly.
-	 */
-	se->depth = se->parent ? se->parent->depth + 1 : 0;
-#endif
-
-	/* Synchronize task with its cfs_rq */
-	update_cfs_rq_load_avg(now, cfs_rq, false);
-	attach_entity_load_avg(cfs_rq, se);
-	update_tg_load_avg(cfs_rq, false);
+	attach_entity_cfs_rq(se);
 
 	if (!vruntime_normalized(p))
 		se->vruntime += cfs_rq->min_vruntime;
@@ -10567,6 +10927,9 @@
 	cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime;
 #endif
 #ifdef CONFIG_SMP
+#ifdef CONFIG_FAIR_GROUP_SCHED
+	cfs_rq->propagate_avg = 0;
+#endif
 	atomic_long_set(&cfs_rq->removed_load_avg, 0);
 	atomic_long_set(&cfs_rq->removed_util_avg, 0);
 #endif
@@ -10767,8 +11130,10 @@
 
 		/* Possible calls to update_curr() need rq clock */
 		update_rq_clock(rq);
-		for_each_sched_entity(se)
-			update_cfs_shares(group_cfs_rq(se));
+		for_each_sched_entity(se) {
+			update_load_avg(se, UPDATE_TG);
+			update_cfs_shares(se);
+		}
 		raw_spin_unlock_irqrestore(&rq->lock, flags);
 	}
 
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 3df55ac..72b79bb 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -477,6 +477,7 @@
 	unsigned long runnable_load_avg;
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	unsigned long tg_load_avg_contrib;
+	unsigned long propagate_avg;
 #endif
 	atomic_long_t removed_load_avg, removed_util_avg;
 #ifndef CONFIG_64BIT
@@ -662,6 +663,9 @@
 
 	/* Maximum cpu capacity in the system. */
 	struct max_cpu_capacity max_cpu_capacity;
+
+	/* First cpu with maximum and minimum original capacity */
+	int max_cap_orig_cpu, min_cap_orig_cpu;
 };
 
 extern struct root_domain def_root_domain;
@@ -720,6 +724,7 @@
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	/* list of leaf cfs_rq on this cpu: */
 	struct list_head leaf_cfs_rq_list;
+	struct list_head *tmp_alone_branch;
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 	/*
@@ -842,6 +847,9 @@
 	/* try_to_wake_up() stats */
 	unsigned int ttwu_count;
 	unsigned int ttwu_local;
+#ifdef CONFIG_SMP
+	struct eas_stats eas_stats;
+#endif
 #endif
 
 #ifdef CONFIG_SMP
@@ -1012,6 +1020,7 @@
 	 */
 	unsigned long capacity;
 	unsigned long max_capacity; /* Max per-cpu capacity in group */
+	unsigned long min_capacity; /* Min per-CPU capacity in group */
 	unsigned long next_update;
 	int imbalance; /* XXX unrelated to capacity but shared group state */
 
diff --git a/kernel/sched/stats.c b/kernel/sched/stats.c
index 87e2c9f..6d74a7c 100644
--- a/kernel/sched/stats.c
+++ b/kernel/sched/stats.c
@@ -12,6 +12,28 @@
  */
 #define SCHEDSTAT_VERSION 15
 
+#ifdef CONFIG_SMP
+static inline void show_easstat(struct seq_file *seq, struct eas_stats *stats)
+{
+	/* eas-specific runqueue stats */
+	seq_printf(seq, "eas %llu %llu %llu %llu %llu %llu ",
+	    stats->sis_attempts, stats->sis_idle, stats->sis_cache_affine,
+	    stats->sis_suff_cap, stats->sis_idle_cpu, stats->sis_count);
+
+	seq_printf(seq, "%llu %llu %llu %llu %llu %llu %llu ",
+	    stats->secb_attempts, stats->secb_sync, stats->secb_idle_bt,
+	    stats->secb_insuff_cap, stats->secb_no_nrg_sav,
+	    stats->secb_nrg_sav, stats->secb_count);
+
+	seq_printf(seq, "%llu %llu %llu %llu %llu ",
+	    stats->fbt_attempts, stats->fbt_no_cpu, stats->fbt_no_sd,
+	    stats->fbt_pref_idle, stats->fbt_count);
+
+	seq_printf(seq, "%llu %llu\n",
+	    stats->cas_attempts, stats->cas_count);
+}
+#endif
+
 static int show_schedstat(struct seq_file *seq, void *v)
 {
 	int cpu;
@@ -40,6 +62,8 @@
 		seq_printf(seq, "\n");
 
 #ifdef CONFIG_SMP
+		show_easstat(seq, &rq->eas_stats);
+
 		/* domain-specific stats */
 		rcu_read_lock();
 		for_each_domain(cpu, sd) {
@@ -66,6 +90,8 @@
 			    sd->sbf_count, sd->sbf_balanced, sd->sbf_pushed,
 			    sd->ttwu_wake_remote, sd->ttwu_move_affine,
 			    sd->ttwu_move_balance);
+
+			show_easstat(seq, &sd->eas_stats);
 		}
 		rcu_read_unlock();
 #endif
diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c
index 86a167b..217bafe 100644
--- a/kernel/sched/tune.c
+++ b/kernel/sched/tune.c
@@ -14,11 +14,12 @@
 unsigned int sysctl_sched_cfs_boost __read_mostly;
 
 #ifdef CONFIG_CGROUP_SCHEDTUNE
-static bool schedtune_initialized = false;
-#endif /* CONFIG_CGROUP_SCHEDTUNE */
+bool schedtune_initialized = false;
+#endif
 
 unsigned int sysctl_sched_cfs_boost __read_mostly;
 
+extern struct reciprocal_value schedtune_spc_rdiv;
 extern struct target_nrg schedtune_target_nrg;
 
 /* Performance Boost region (B) threshold params */
@@ -680,6 +681,9 @@
 	struct schedtune *st;
 	int task_boost;
 
+	if (!unlikely(schedtune_initialized))
+		return 0;
+
 	/* Get task boost value */
 	rcu_read_lock();
 	st = task_schedtune(p);
@@ -694,6 +698,9 @@
 	struct schedtune *st;
 	int prefer_idle;
 
+	if (!unlikely(schedtune_initialized))
+		return 0;
+
 	/* Get prefer_idle value */
 	rcu_read_lock();
 	st = task_schedtune(p);
@@ -831,6 +838,7 @@
 		bg = &per_cpu(cpu_boost_groups, cpu);
 		bg->group[st->idx].boost = 0;
 		bg->group[st->idx].tasks = 0;
+		raw_spin_lock_init(&bg->lock);
 	}
 
 	return 0;
@@ -1126,9 +1134,12 @@
 	pr_info("schedtune: configured to support global boosting only\n");
 #endif /* CONFIG_CGROUP_SCHEDTUNE */
 
+	schedtune_spc_rdiv = reciprocal_value(100);
+
 	return 0;
 
 nodata:
+	pr_warning("schedtune: disabled!\n");
 	rcu_read_unlock();
 	return -EINVAL;
 }
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index cbc75c0..60249e4 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -69,6 +69,20 @@
 	local_irq_restore(*flags);
 }
 
+#ifdef CONFIG_HZ_300
+/*
+ * Tick interval becomes to 3333333 due to
+ * rounding error when HZ=300.
+ */
+#define MIN_SCHED_RAVG_WINDOW (3333333 * 6)
+#else
+/* Min window size (in ns) = 20ms */
+#define MIN_SCHED_RAVG_WINDOW 20000000
+#endif
+
+/* Max window size (in ns) = 1s */
+#define MAX_SCHED_RAVG_WINDOW 1000000000
+
 /* 1 -> use PELT based load stats, 0 -> use window-based load stats */
 unsigned int __read_mostly walt_disabled = 0;
 
@@ -132,7 +146,6 @@
  */
 __read_mostly unsigned int sched_load_granule =
 			MIN_SCHED_RAVG_WINDOW / NUM_LOAD_INDICES;
-
 /* Size of bitmaps maintained to track top tasks */
 static const unsigned int top_tasks_bitmap_size =
 		BITS_TO_LONGS(NUM_LOAD_INDICES + 1) * sizeof(unsigned long);
diff --git a/kernel/sched/walt.h b/kernel/sched/walt.h
index 535f14b..86d5bfd 100644
--- a/kernel/sched/walt.h
+++ b/kernel/sched/walt.h
@@ -24,12 +24,6 @@
 #define WINDOW_STATS_AVG		3
 #define WINDOW_STATS_INVALID_POLICY	4
 
-/* Min window size (in ns) = 20ms */
-#define MIN_SCHED_RAVG_WINDOW 20000000
-
-/* Max window size (in ns) = 1s */
-#define MAX_SCHED_RAVG_WINDOW 1000000000
-
 #define EXITING_TASK_MARKER	0xdeaddead
 
 #define FREQ_REPORT_MAX_CPU_LOAD_TOP_TASK	0
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 1d894fc..2c4cd17 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -335,8 +335,8 @@
 		.extra2		= &max_sched_granularity_ns,
 	},
 	{
-		.procname	= "sched_is_big_little",
-		.data		= &sysctl_sched_is_big_little,
+		.procname	= "sched_sync_hint_enable",
+		.data		= &sysctl_sched_sync_hint_enable,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
@@ -367,13 +367,6 @@
 	},
 #endif
 	{
-		.procname	= "sched_sync_hint_enable",
-		.data		= &sysctl_sched_sync_hint_enable,
-		.maxlen		= sizeof(unsigned int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "sched_initial_task_util",
 		.data		= &sysctl_sched_initial_task_util,
 		.maxlen		= sizeof(unsigned int),
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 44cc350..df3191e 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -1020,6 +1020,18 @@
 	return ts->sleep_length;
 }
 
+/**
+ * tick_nohz_get_idle_calls - return the current idle calls counter value
+ *
+ * Called from the schedutil frequency scaling governor in scheduler context.
+ */
+unsigned long tick_nohz_get_idle_calls(void)
+{
+	struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
+
+	return ts->idle_calls;
+}
+
 static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
 {
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 4a848f7..66b0714 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1599,11 +1599,11 @@
 
 #define SAVED_CMDLINES_DEFAULT 128
 #define NO_CMDLINE_MAP UINT_MAX
-static unsigned saved_tgids[SAVED_CMDLINES_DEFAULT];
 static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED;
 struct saved_cmdlines_buffer {
 	unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
 	unsigned *map_cmdline_to_pid;
+	unsigned *map_cmdline_to_tgid;
 	unsigned cmdline_num;
 	int cmdline_idx;
 	char *saved_cmdlines;
@@ -1637,12 +1637,23 @@
 		return -ENOMEM;
 	}
 
+	s->map_cmdline_to_tgid = kmalloc_array(val,
+					       sizeof(*s->map_cmdline_to_tgid),
+					       GFP_KERNEL);
+	if (!s->map_cmdline_to_tgid) {
+		kfree(s->map_cmdline_to_pid);
+		kfree(s->saved_cmdlines);
+		return -ENOMEM;
+	}
+
 	s->cmdline_idx = 0;
 	s->cmdline_num = val;
 	memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP,
 	       sizeof(s->map_pid_to_cmdline));
 	memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP,
 	       val * sizeof(*s->map_cmdline_to_pid));
+	memset(s->map_cmdline_to_tgid, NO_CMDLINE_MAP,
+	       val * sizeof(*s->map_cmdline_to_tgid));
 
 	return 0;
 }
@@ -1808,14 +1819,17 @@
 	if (!tsk->pid || unlikely(tsk->pid > PID_MAX_DEFAULT))
 		return 0;
 
+	preempt_disable();
 	/*
 	 * It's not the end of the world if we don't get
 	 * the lock, but we also don't want to spin
 	 * nor do we want to disable interrupts,
 	 * so if we miss here, then better luck next time.
 	 */
-	if (!arch_spin_trylock(&trace_cmdline_lock))
+	if (!arch_spin_trylock(&trace_cmdline_lock)) {
+		preempt_enable();
 		return 0;
+	}
 
 	idx = savedcmd->map_pid_to_cmdline[tsk->pid];
 	if (idx == NO_CMDLINE_MAP) {
@@ -1838,8 +1852,9 @@
 	}
 
 	set_cmdline(idx, tsk->comm);
-	saved_tgids[idx] = tsk->tgid;
+	savedcmd->map_cmdline_to_tgid[idx] = tsk->tgid;
 	arch_spin_unlock(&trace_cmdline_lock);
+	preempt_enable();
 
 	return 1;
 }
@@ -1881,19 +1896,29 @@
 	preempt_enable();
 }
 
-int trace_find_tgid(int pid)
+static int __find_tgid_locked(int pid)
 {
 	unsigned map;
 	int tgid;
 
-	preempt_disable();
-	arch_spin_lock(&trace_cmdline_lock);
 	map = savedcmd->map_pid_to_cmdline[pid];
 	if (map != NO_CMDLINE_MAP)
-		tgid = saved_tgids[map];
+		tgid = savedcmd->map_cmdline_to_tgid[map];
 	else
 		tgid = -1;
 
+	return tgid;
+}
+
+int trace_find_tgid(int pid)
+{
+	int tgid;
+
+	preempt_disable();
+	arch_spin_lock(&trace_cmdline_lock);
+
+	tgid = __find_tgid_locked(pid);
+
 	arch_spin_unlock(&trace_cmdline_lock);
 	preempt_enable();
 
@@ -4386,10 +4411,15 @@
 {
 	char buf[64];
 	int r;
+	unsigned int n;
 
+	preempt_disable();
 	arch_spin_lock(&trace_cmdline_lock);
-	r = scnprintf(buf, sizeof(buf), "%u\n", savedcmd->cmdline_num);
+	n = savedcmd->cmdline_num;
 	arch_spin_unlock(&trace_cmdline_lock);
+	preempt_enable();
+
+	r = scnprintf(buf, sizeof(buf), "%u\n", n);
 
 	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
 }
@@ -4398,6 +4428,7 @@
 {
 	kfree(s->saved_cmdlines);
 	kfree(s->map_cmdline_to_pid);
+	kfree(s->map_cmdline_to_tgid);
 	kfree(s);
 }
 
@@ -4414,10 +4445,12 @@
 		return -ENOMEM;
 	}
 
+	preempt_disable();
 	arch_spin_lock(&trace_cmdline_lock);
 	savedcmd_temp = savedcmd;
 	savedcmd = s;
 	arch_spin_unlock(&trace_cmdline_lock);
+	preempt_enable();
 	free_saved_cmdlines_buffer(savedcmd_temp);
 
 	return 0;
@@ -4636,33 +4669,61 @@
 	char *file_buf;
 	char *buf;
 	int len = 0;
-	int pid;
 	int i;
+	int *pids;
+	int n = 0;
 
-	file_buf = kmalloc(SAVED_CMDLINES_DEFAULT*(16+1+16), GFP_KERNEL);
-	if (!file_buf)
+	preempt_disable();
+	arch_spin_lock(&trace_cmdline_lock);
+
+	pids = kmalloc_array(savedcmd->cmdline_num, 2*sizeof(int), GFP_KERNEL);
+	if (!pids) {
+		arch_spin_unlock(&trace_cmdline_lock);
+		preempt_enable();
 		return -ENOMEM;
+	}
 
-	buf = file_buf;
-
-	for (i = 0; i < SAVED_CMDLINES_DEFAULT; i++) {
-		int tgid;
-		int r;
+	for (i = 0; i < savedcmd->cmdline_num; i++) {
+		int pid;
 
 		pid = savedcmd->map_cmdline_to_pid[i];
 		if (pid == -1 || pid == NO_CMDLINE_MAP)
 			continue;
 
-		tgid = trace_find_tgid(pid);
-		r = sprintf(buf, "%d %d\n", pid, tgid);
+		pids[n] = pid;
+		pids[n+1] = __find_tgid_locked(pid);
+		n += 2;
+	}
+	arch_spin_unlock(&trace_cmdline_lock);
+	preempt_enable();
+
+	if (n == 0) {
+		kfree(pids);
+		return 0;
+	}
+
+	/* enough to hold max pair of pids + space, lr and nul */
+	len = n * 12;
+	file_buf = kmalloc(len, GFP_KERNEL);
+	if (!file_buf) {
+		kfree(pids);
+		return -ENOMEM;
+	}
+
+	buf = file_buf;
+	for (i = 0; i < n && len > 0; i += 2) {
+		int r;
+
+		r = snprintf(buf, len, "%d %d\n", pids[i], pids[i+1]);
 		buf += r;
-		len += r;
+		len -= r;
 	}
 
 	len = simple_read_from_buffer(ubuf, cnt, ppos,
-				      file_buf, len);
+				      file_buf, buf - file_buf);
 
 	kfree(file_buf);
+	kfree(pids);
 
 	return len;
 }
diff --git a/mm/internal.h b/mm/internal.h
index 537ac99..df6319f 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -74,11 +74,16 @@
 extern unsigned long highest_memmap_pfn;
 
 /*
+ * Maximum number of reclaim retries without progress before the OOM
+ * killer is consider the only way forward.
+ */
+#define MAX_RECLAIM_RETRIES 16
+
+/*
  * in mm/vmscan.c:
  */
 extern int isolate_lru_page(struct page *page);
 extern void putback_lru_page(struct page *page);
-extern bool pgdat_reclaimable(struct pglist_data *pgdat);
 
 /*
  * in mm/rmap.c:
diff --git a/mm/migrate.c b/mm/migrate.c
index f0b786d..4213d27 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1738,9 +1738,6 @@
 {
 	int z;
 
-	if (!pgdat_reclaimable(pgdat))
-		return false;
-
 	for (z = pgdat->nr_zones - 1; z >= 0; z--) {
 		struct zone *zone = pgdat->node_zones + z;
 
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 44085b2..3eb5f68 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1099,14 +1099,10 @@
 {
 	int migratetype = 0;
 	int batch_free = 0;
-	unsigned long nr_scanned;
 	bool isolated_pageblocks;
 
 	spin_lock(&zone->lock);
 	isolated_pageblocks = has_isolate_pageblock(zone);
-	nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
-	if (nr_scanned)
-		__mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
 
 	while (count) {
 		struct page *page;
@@ -1159,12 +1155,7 @@
 				unsigned int order,
 				int migratetype)
 {
-	unsigned long nr_scanned;
 	spin_lock(&zone->lock);
-	nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED);
-	if (nr_scanned)
-		__mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned);
-
 	if (unlikely(has_isolate_pageblock(zone) ||
 		is_migrate_isolate(migratetype))) {
 		migratetype = get_pfnblock_migratetype(page, pfn);
@@ -3501,19 +3492,12 @@
 }
 
 /*
- * Maximum number of reclaim retries without any progress before OOM killer
- * is consider as the only way to move forward.
- */
-#define MAX_RECLAIM_RETRIES 16
-
-/*
  * Checks whether it makes sense to retry the reclaim to make a forward progress
  * for the given allocation request.
- * The reclaim feedback represented by did_some_progress (any progress during
- * the last reclaim round) and no_progress_loops (number of reclaim rounds without
- * any progress in a row) is considered as well as the reclaimable pages on the
- * applicable zone list (with a backoff mechanism which is a function of
- * no_progress_loops).
+ *
+ * We give up when we either have tried MAX_RECLAIM_RETRIES in a row
+ * without success, or when we couldn't even meet the watermark if we
+ * reclaimed all remaining pages on the LRU lists.
  *
  * Returns true if a retry is viable or false to enter the oom path.
  */
@@ -3556,13 +3540,11 @@
 		unsigned long reclaimable;
 
 		available = reclaimable = zone_reclaimable_pages(zone);
-		available -= DIV_ROUND_UP((*no_progress_loops) * available,
-					  MAX_RECLAIM_RETRIES);
 		available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
 
 		/*
-		 * Would the allocation succeed if we reclaimed the whole
-		 * available?
+		 * Would the allocation succeed if we reclaimed all
+		 * reclaimable pages?
 		 */
 		if (__zone_watermark_ok(zone, order, min_wmark_pages(zone),
 				ac_classzone_idx(ac), alloc_flags, available)) {
@@ -4442,7 +4424,6 @@
 #endif
 			" writeback_tmp:%lukB"
 			" unstable:%lukB"
-			" pages_scanned:%lu"
 			" all_unreclaimable? %s"
 			"\n",
 			pgdat->node_id,
@@ -4465,8 +4446,8 @@
 #endif
 			K(node_page_state(pgdat, NR_WRITEBACK_TEMP)),
 			K(node_page_state(pgdat, NR_UNSTABLE_NFS)),
-			node_page_state(pgdat, NR_PAGES_SCANNED),
-			!pgdat_reclaimable(pgdat) ? "yes" : "no");
+			pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES ?
+				"yes" : "no");
 	}
 
 	for_each_populated_zone(zone) {
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 7b5848cf..ecd6c359 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -235,12 +235,6 @@
 	return nr;
 }
 
-bool pgdat_reclaimable(struct pglist_data *pgdat)
-{
-	return node_page_state_snapshot(pgdat, NR_PAGES_SCANNED) <
-		pgdat_reclaimable_pages(pgdat) * 6;
-}
-
 /**
  * lruvec_lru_size -  Returns the number of pages on the given LRU list.
  * @lruvec: lru vector
@@ -1514,11 +1508,12 @@
 	unsigned long nr_taken = 0;
 	unsigned long nr_zone_taken[MAX_NR_ZONES] = { 0 };
 	unsigned long nr_skipped[MAX_NR_ZONES] = { 0, };
+	unsigned long skipped = 0;
 	unsigned long scan, nr_pages;
 	LIST_HEAD(pages_skipped);
 
 	for (scan = 0; scan < nr_to_scan && nr_taken < nr_to_scan &&
-					!list_empty(src);) {
+					!list_empty(src); scan++) {
 		struct page *page;
 
 		page = lru_to_page(src);
@@ -1532,12 +1527,6 @@
 			continue;
 		}
 
-		/*
-		 * Account for scanned and skipped separetly to avoid the pgdat
-		 * being prematurely marked unreclaimable by pgdat_reclaimable.
-		 */
-		scan++;
-
 		switch (__isolate_lru_page(page, mode)) {
 		case 0:
 			nr_pages = hpage_nr_pages(page);
@@ -1565,28 +1554,20 @@
 	 */
 	if (!list_empty(&pages_skipped)) {
 		int zid;
-		unsigned long total_skipped = 0;
 
+		list_splice(&pages_skipped, src);
 		for (zid = 0; zid < MAX_NR_ZONES; zid++) {
 			if (!nr_skipped[zid])
 				continue;
 
 			__count_zid_vm_events(PGSCAN_SKIP, zid, nr_skipped[zid]);
-			total_skipped += nr_skipped[zid];
+			skipped += nr_skipped[zid];
 		}
-
-		/*
-		 * Account skipped pages as a partial scan as the pgdat may be
-		 * close to unreclaimable. If the LRU list is empty, account
-		 * skipped pages as a full scan.
-		 */
-		scan += list_empty(src) ? total_skipped : total_skipped >> 2;
-
-		list_splice(&pages_skipped, src);
 	}
 	*nr_scanned = scan;
-	trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scan,
-				    nr_taken, mode, is_file_lru(lru));
+	trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan,
+				    scan, skipped, nr_taken, mode,
+				    is_file_lru(lru));
 	update_lru_sizes(lruvec, lru, nr_zone_taken);
 	return nr_taken;
 }
@@ -1849,7 +1830,6 @@
 	reclaim_stat->recent_scanned[file] += nr_taken;
 
 	if (global_reclaim(sc)) {
-		__mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned);
 		if (current_is_kswapd())
 			__count_vm_events(PGSCAN_KSWAPD, nr_scanned);
 		else
@@ -2038,8 +2018,6 @@
 	__mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken);
 	reclaim_stat->recent_scanned[file] += nr_taken;
 
-	if (global_reclaim(sc))
-		__mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned);
 	__count_vm_events(PGREFILL, nr_scanned);
 
 	spin_unlock_irq(&pgdat->lru_lock);
@@ -2199,30 +2177,8 @@
 	unsigned long anon_prio, file_prio;
 	enum scan_balance scan_balance;
 	unsigned long anon, file;
-	bool force_scan = false;
 	unsigned long ap, fp;
 	enum lru_list lru;
-	bool some_scanned;
-	int pass;
-
-	/*
-	 * If the zone or memcg is small, nr[l] can be 0.  This
-	 * results in no scanning on this priority and a potential
-	 * priority drop.  Global direct reclaim can go to the next
-	 * zone and tends to have no problems. Global kswapd is for
-	 * zone balancing and it needs to scan a minimum amount. When
-	 * reclaiming for a memcg, a priority drop can cause high
-	 * latencies, so it's better to scan a minimum amount there as
-	 * well.
-	 */
-	if (current_is_kswapd()) {
-		if (!pgdat_reclaimable(pgdat))
-			force_scan = true;
-		if (!mem_cgroup_online(memcg))
-			force_scan = true;
-	}
-	if (!global_reclaim(sc))
-		force_scan = true;
 
 	/* If we have no swap space, do not bother scanning anon pages. */
 	if (!sc->may_swap || mem_cgroup_get_nr_swap_pages(memcg) <= 0) {
@@ -2354,55 +2310,48 @@
 	fraction[1] = fp;
 	denominator = ap + fp + 1;
 out:
-	some_scanned = false;
-	/* Only use force_scan on second pass. */
-	for (pass = 0; !some_scanned && pass < 2; pass++) {
-		*lru_pages = 0;
-		for_each_evictable_lru(lru) {
-			int file = is_file_lru(lru);
-			unsigned long size;
-			unsigned long scan;
+	*lru_pages = 0;
+	for_each_evictable_lru(lru) {
+		int file = is_file_lru(lru);
+		unsigned long size;
+		unsigned long scan;
 
-			size = lruvec_lru_size(lruvec, lru, sc->reclaim_idx);
-			scan = size >> sc->priority;
+		size = lruvec_lru_size(lruvec, lru, sc->reclaim_idx);
+		scan = size >> sc->priority;
+		/*
+		 * If the cgroup's already been deleted, make sure to
+		 * scrape out the remaining cache.
+		 */
+		if (!scan && !mem_cgroup_online(memcg))
+			scan = min(size, SWAP_CLUSTER_MAX);
 
-			if (!scan && pass && force_scan)
-				scan = min(size, SWAP_CLUSTER_MAX);
-
-			switch (scan_balance) {
-			case SCAN_EQUAL:
-				/* Scan lists relative to size */
-				break;
-			case SCAN_FRACT:
-				/*
-				 * Scan types proportional to swappiness and
-				 * their relative recent reclaim efficiency.
-				 */
-				scan = div64_u64(scan * fraction[file],
-							denominator);
-				break;
-			case SCAN_FILE:
-			case SCAN_ANON:
-				/* Scan one type exclusively */
-				if ((scan_balance == SCAN_FILE) != file) {
-					size = 0;
-					scan = 0;
-				}
-				break;
-			default:
-				/* Look ma, no brain */
-				BUG();
-			}
-
-			*lru_pages += size;
-			nr[lru] = scan;
-
+		switch (scan_balance) {
+		case SCAN_EQUAL:
+			/* Scan lists relative to size */
+			break;
+		case SCAN_FRACT:
 			/*
-			 * Skip the second pass and don't force_scan,
-			 * if we found something to scan.
+			 * Scan types proportional to swappiness and
+			 * their relative recent reclaim efficiency.
 			 */
-			some_scanned |= !!scan;
+			scan = div64_u64(scan * fraction[file],
+					 denominator);
+			break;
+		case SCAN_FILE:
+		case SCAN_ANON:
+			/* Scan one type exclusively */
+			if ((scan_balance == SCAN_FILE) != file) {
+				size = 0;
+				scan = 0;
+			}
+			break;
+		default:
+			/* Look ma, no brain */
+			BUG();
 		}
+
+		*lru_pages += size;
+		nr[lru] = scan;
 	}
 }
 
@@ -2704,6 +2653,15 @@
 	} while (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed,
 					 sc->nr_scanned - nr_scanned, sc));
 
+	/*
+	 * Kswapd gives up on balancing particular nodes after too
+	 * many failures to reclaim anything from them and goes to
+	 * sleep. On reclaim progress, reset the failure counter. A
+	 * successful direct reclaim run will revive a dormant kswapd.
+	 */
+	if (reclaimable)
+		pgdat->kswapd_failures = 0;
+
 	return reclaimable;
 }
 
@@ -2778,10 +2736,6 @@
 						 GFP_KERNEL | __GFP_HARDWALL))
 				continue;
 
-			if (sc->priority != DEF_PRIORITY &&
-			    !pgdat_reclaimable(zone->zone_pgdat))
-				continue;	/* Let kswapd poll it */
-
 			/*
 			 * If we already have plenty of memory free for
 			 * compaction in this zone, don't free any more.
@@ -2918,7 +2872,7 @@
 	return 0;
 }
 
-static bool pfmemalloc_watermark_ok(pg_data_t *pgdat)
+static bool allow_direct_reclaim(pg_data_t *pgdat)
 {
 	struct zone *zone;
 	unsigned long pfmemalloc_reserve = 0;
@@ -2926,10 +2880,15 @@
 	int i;
 	bool wmark_ok;
 
+	if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES)
+		return true;
+
 	for (i = 0; i <= ZONE_NORMAL; i++) {
 		zone = &pgdat->node_zones[i];
-		if (!managed_zone(zone) ||
-		    pgdat_reclaimable_pages(pgdat) == 0)
+		if (!managed_zone(zone))
+			continue;
+
+		if (!zone_reclaimable_pages(zone))
 			continue;
 
 		pfmemalloc_reserve += min_wmark_pages(zone);
@@ -3006,7 +2965,7 @@
 
 		/* Throttle based on the first usable node */
 		pgdat = zone->zone_pgdat;
-		if (pfmemalloc_watermark_ok(pgdat))
+		if (allow_direct_reclaim(pgdat))
 			goto out;
 		break;
 	}
@@ -3028,14 +2987,14 @@
 	 */
 	if (!(gfp_mask & __GFP_FS)) {
 		wait_event_interruptible_timeout(pgdat->pfmemalloc_wait,
-			pfmemalloc_watermark_ok(pgdat), HZ);
+			allow_direct_reclaim(pgdat), HZ);
 
 		goto check_pending;
 	}
 
 	/* Throttle until kswapd wakes the process */
 	wait_event_killable(zone->zone_pgdat->pfmemalloc_wait,
-		pfmemalloc_watermark_ok(pgdat));
+		allow_direct_reclaim(pgdat));
 
 check_pending:
 	if (fatal_signal_pending(current))
@@ -3198,6 +3157,7 @@
 	 */
 	clear_bit(PGDAT_CONGESTED, &zone->zone_pgdat->flags);
 	clear_bit(PGDAT_DIRTY, &zone->zone_pgdat->flags);
+	clear_bit(PGDAT_WRITEBACK, &zone->zone_pgdat->flags);
 
 	return true;
 }
@@ -3214,7 +3174,7 @@
 
 	/*
 	 * The throttled processes are normally woken up in balance_pgdat() as
-	 * soon as pfmemalloc_watermark_ok() is true. But there is a potential
+	 * soon as allow_direct_reclaim() is true. But there is a potential
 	 * race between when kswapd checks the watermarks and a process gets
 	 * throttled. There is also a potential race if processes get
 	 * throttled, kswapd wakes, a large process exits thereby balancing the
@@ -3228,17 +3188,21 @@
 	if (waitqueue_active(&pgdat->pfmemalloc_wait))
 		wake_up_all(&pgdat->pfmemalloc_wait);
 
+	/* Hopeless node, leave it to direct reclaim */
+	if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES)
+		return true;
+
 	for (i = 0; i <= classzone_idx; i++) {
 		struct zone *zone = pgdat->node_zones + i;
 
 		if (!managed_zone(zone))
 			continue;
 
-		if (!zone_balanced(zone, order, classzone_idx))
-			return false;
+		if (zone_balanced(zone, order, classzone_idx))
+			return true;
 	}
 
-	return true;
+	return false;
 }
 
 /*
@@ -3314,9 +3278,9 @@
 	count_vm_event(PAGEOUTRUN);
 
 	do {
+		unsigned long nr_reclaimed = sc.nr_reclaimed;
 		bool raise_priority = true;
 
-		sc.nr_reclaimed = 0;
 		sc.reclaim_idx = classzone_idx;
 
 		/*
@@ -3371,7 +3335,7 @@
 		 * If we're getting trouble reclaiming, start doing writepage
 		 * even in laptop mode.
 		 */
-		if (sc.priority < DEF_PRIORITY - 2 || !pgdat_reclaimable(pgdat))
+		if (sc.priority < DEF_PRIORITY - 2)
 			sc.may_writepage = 1;
 
 		/* Call soft limit reclaim before calling shrink_node. */
@@ -3395,7 +3359,7 @@
 		 * able to safely make forward progress. Wake them
 		 */
 		if (waitqueue_active(&pgdat->pfmemalloc_wait) &&
-				pfmemalloc_watermark_ok(pgdat))
+				allow_direct_reclaim(pgdat))
 			wake_up_all(&pgdat->pfmemalloc_wait);
 
 		/* Check if kswapd should be suspending */
@@ -3406,10 +3370,14 @@
 		 * Raise priority if scanning rate is too low or there was no
 		 * progress in reclaiming pages
 		 */
-		if (raise_priority || !sc.nr_reclaimed)
+		nr_reclaimed = sc.nr_reclaimed - nr_reclaimed;
+		if (raise_priority || !nr_reclaimed)
 			sc.priority--;
 	} while (sc.priority >= 1);
 
+	if (!sc.nr_reclaimed)
+		pgdat->kswapd_failures++;
+
 out:
 	/*
 	 * Return the order kswapd stopped reclaiming at as
@@ -3431,7 +3399,13 @@
 
 	prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 
-	/* Try to sleep for a short interval */
+	/*
+	 * Try to sleep for a short interval. Note that kcompactd will only be
+	 * woken if it is possible to sleep for a short interval. This is
+	 * deliberate on the assumption that if reclaim cannot keep an
+	 * eligible zone balanced that it's also unlikely that compaction will
+	 * succeed.
+	 */
 	if (prepare_kswapd_sleep(pgdat, reclaim_order, classzone_idx)) {
 		/*
 		 * Compaction records what page blocks it recently failed to
@@ -3609,6 +3583,10 @@
 	if (!waitqueue_active(&pgdat->kswapd_wait))
 		return;
 
+	/* Hopeless node, leave it to direct reclaim */
+	if (pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES)
+		return;
+
 	/* Only wake kswapd if all zones are unbalanced */
 	for (z = 0; z <= classzone_idx; z++) {
 		zone = pgdat->node_zones + z;
@@ -3879,9 +3857,6 @@
 	    sum_zone_node_page_state(pgdat->node_id, NR_SLAB_RECLAIMABLE) <= pgdat->min_slab_pages)
 		return NODE_RECLAIM_FULL;
 
-	if (!pgdat_reclaimable(pgdat))
-		return NODE_RECLAIM_FULL;
-
 	/*
 	 * Do not scan if the allocation should not be delayed.
 	 */
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 513c37a..2ab7973 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -954,7 +954,6 @@
 	"nr_unevictable",
 	"nr_isolated_anon",
 	"nr_isolated_file",
-	"nr_pages_scanned",
 	"workingset_refault",
 	"workingset_activate",
 	"workingset_nodereclaim",
@@ -1379,7 +1378,6 @@
 		   "\n        min      %lu"
 		   "\n        low      %lu"
 		   "\n        high     %lu"
-		   "\n   node_scanned  %lu"
 		   "\n        spanned  %lu"
 		   "\n        present  %lu"
 		   "\n        managed  %lu",
@@ -1387,7 +1385,6 @@
 		   min_wmark_pages(zone),
 		   low_wmark_pages(zone),
 		   high_wmark_pages(zone),
-		   node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED),
 		   zone->spanned_pages,
 		   zone->present_pages,
 		   zone->managed_pages);
@@ -1426,7 +1423,7 @@
 		   "\n  node_unreclaimable:  %u"
 		   "\n  start_pfn:           %lu"
 		   "\n  node_inactive_ratio: %u",
-		   !pgdat_reclaimable(zone->zone_pgdat),
+		   pgdat->kswapd_failures >= MAX_RECLAIM_RETRIES,
 		   zone->zone_start_pfn,
 		   zone->zone_pgdat->inactive_ratio);
 	seq_putc(m, '\n');
@@ -1588,22 +1585,9 @@
 	for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
 		val = atomic_long_read(&vm_zone_stat[i]);
 		if (val < 0) {
-			switch (i) {
-			case NR_PAGES_SCANNED:
-				/*
-				 * This is often seen to go negative in
-				 * recent kernels, but not to go permanently
-				 * negative.  Whilst it would be nicer not to
-				 * have exceptions, rooting them out would be
-				 * another task, of rather low priority.
-				 */
-				break;
-			default:
-				pr_warn("%s: %s %ld\n",
-					__func__, vmstat_text[i], val);
-				err = -EINVAL;
-				break;
-			}
+			pr_warn("%s: %s %ld\n",
+				__func__, vmstat_text[i], val);
+			err = -EINVAL;
 		}
 	}
 	if (err)
diff --git a/net/core/dev.c b/net/core/dev.c
index 7e168d0..610e5f8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2704,9 +2704,10 @@
 static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path)
 {
 	if (tx_path)
-		return skb->ip_summed != CHECKSUM_PARTIAL;
-	else
-		return skb->ip_summed == CHECKSUM_NONE;
+		return skb->ip_summed != CHECKSUM_PARTIAL &&
+		       skb->ip_summed != CHECKSUM_NONE;
+
+	return skb->ip_summed == CHECKSUM_NONE;
 }
 
 /**
@@ -2725,11 +2726,12 @@
 struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
 				  netdev_features_t features, bool tx_path)
 {
+	struct sk_buff *segs;
+
 	if (unlikely(skb_needs_check(skb, tx_path))) {
 		int err;
 
-		skb_warn_bad_offload(skb);
-
+		/* We're going to init ->check field in TCP or UDP header */
 		err = skb_cow_head(skb, 0);
 		if (err < 0)
 			return ERR_PTR(err);
@@ -2757,7 +2759,12 @@
 	skb_reset_mac_header(skb);
 	skb_reset_mac_len(skb);
 
-	return skb_mac_gso_segment(skb, features);
+	segs = skb_mac_gso_segment(skb, features);
+
+	if (unlikely(skb_needs_check(skb, tx_path)))
+		skb_warn_bad_offload(skb);
+
+	return segs;
 }
 EXPORT_SYMBOL(__skb_gso_segment);
 
diff --git a/net/core/dst.c b/net/core/dst.c
index 39cc119..b5de366 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -349,8 +349,15 @@
 
 	new = ((unsigned long) &dst_default_metrics) | DST_METRICS_READ_ONLY;
 	prev = cmpxchg(&dst->_metrics, old, new);
-	if (prev == old)
-		kfree(__DST_METRICS_PTR(old));
+	if (prev == old) {
+		struct dst_metrics *old_p = (struct dst_metrics *)
+					    __DST_METRICS_PTR(old);
+
+		if (prev & DST_METRICS_REFCOUNTED) {
+			if (atomic_dec_and_test(&old_p->refcnt))
+				kfree(old_p);
+		}
+	}
 }
 EXPORT_SYMBOL(__dst_destroy_metrics_generic);
 
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 3e42221..4403260 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1384,7 +1384,7 @@
 	 */
 
 	cork->length += length;
-	if (((length > mtu) ||
+	if ((((length + fragheaderlen) > mtu) ||
 	     (skb && skb_is_gso(skb))) &&
 	    (sk->sk_protocol == IPPROTO_UDP) &&
 	    (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
diff --git a/net/key/af_key.c b/net/key/af_key.c
index d8d95b6..2e1050e 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -63,6 +63,7 @@
 		} u;
 		struct sk_buff	*skb;
 	} dump;
+	struct mutex dump_lock;
 };
 
 static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
@@ -143,6 +144,7 @@
 {
 	struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
 	struct sock *sk;
+	struct pfkey_sock *pfk;
 	int err;
 
 	if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
@@ -157,6 +159,9 @@
 	if (sk == NULL)
 		goto out;
 
+	pfk = pfkey_sk(sk);
+	mutex_init(&pfk->dump_lock);
+
 	sock->ops = &pfkey_ops;
 	sock_init_data(sock, sk);
 
@@ -285,13 +290,23 @@
 	struct sadb_msg *hdr;
 	int rc;
 
+	mutex_lock(&pfk->dump_lock);
+	if (!pfk->dump.dump) {
+		rc = 0;
+		goto out;
+	}
+
 	rc = pfk->dump.dump(pfk);
-	if (rc == -ENOBUFS)
-		return 0;
+	if (rc == -ENOBUFS) {
+		rc = 0;
+		goto out;
+	}
 
 	if (pfk->dump.skb) {
-		if (!pfkey_can_dump(&pfk->sk))
-			return 0;
+		if (!pfkey_can_dump(&pfk->sk)) {
+			rc = 0;
+			goto out;
+		}
 
 		hdr = (struct sadb_msg *) pfk->dump.skb->data;
 		hdr->sadb_msg_seq = 0;
@@ -302,6 +317,9 @@
 	}
 
 	pfkey_terminate_dump(pfk);
+
+out:
+	mutex_unlock(&pfk->dump_lock);
 	return rc;
 }
 
@@ -1806,19 +1824,26 @@
 	struct xfrm_address_filter *filter = NULL;
 	struct pfkey_sock *pfk = pfkey_sk(sk);
 
-	if (pfk->dump.dump != NULL)
+	mutex_lock(&pfk->dump_lock);
+	if (pfk->dump.dump != NULL) {
+		mutex_unlock(&pfk->dump_lock);
 		return -EBUSY;
+	}
 
 	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
-	if (proto == 0)
+	if (proto == 0) {
+		mutex_unlock(&pfk->dump_lock);
 		return -EINVAL;
+	}
 
 	if (ext_hdrs[SADB_X_EXT_FILTER - 1]) {
 		struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1];
 
 		filter = kmalloc(sizeof(*filter), GFP_KERNEL);
-		if (filter == NULL)
+		if (filter == NULL) {
+			mutex_unlock(&pfk->dump_lock);
 			return -ENOMEM;
+		}
 
 		memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr,
 		       sizeof(xfrm_address_t));
@@ -1834,6 +1859,7 @@
 	pfk->dump.dump = pfkey_dump_sa;
 	pfk->dump.done = pfkey_dump_sa_done;
 	xfrm_state_walk_init(&pfk->dump.u.state, proto, filter);
+	mutex_unlock(&pfk->dump_lock);
 
 	return pfkey_do_dump(pfk);
 }
@@ -2693,14 +2719,18 @@
 {
 	struct pfkey_sock *pfk = pfkey_sk(sk);
 
-	if (pfk->dump.dump != NULL)
+	mutex_lock(&pfk->dump_lock);
+	if (pfk->dump.dump != NULL) {
+		mutex_unlock(&pfk->dump_lock);
 		return -EBUSY;
+	}
 
 	pfk->dump.msg_version = hdr->sadb_msg_version;
 	pfk->dump.msg_portid = hdr->sadb_msg_pid;
 	pfk->dump.dump = pfkey_dump_sp;
 	pfk->dump.done = pfkey_dump_sp_done;
 	xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN);
+	mutex_unlock(&pfk->dump_lock);
 
 	return pfkey_do_dump(pfk);
 }
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 74d0d33..96efe47 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -64,7 +64,7 @@
 	struct sock *sk;
 
 	sk_for_each_bound(sk, &l2tp_ip6_bind_table) {
-		const struct in6_addr *addr = inet6_rcv_saddr(sk);
+		const struct in6_addr *sk_laddr = inet6_rcv_saddr(sk);
 		struct l2tp_ip6_sock *l2tp = l2tp_ip6_sk(sk);
 
 		if (l2tp == NULL)
@@ -72,7 +72,7 @@
 
 		if ((l2tp->conn_id == tunnel_id) &&
 		    net_eq(sock_net(sk), net) &&
-		    (!addr || ipv6_addr_equal(addr, laddr)) &&
+		    (!sk_laddr || ipv6_addr_any(sk_laddr) || ipv6_addr_equal(sk_laddr, laddr)) &&
 		    (!sk->sk_bound_dev_if || !dif ||
 		     sk->sk_bound_dev_if == dif))
 			goto found;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 8da67f7..e26b515 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1248,7 +1248,7 @@
 }
 
 static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
-						 const struct flowi *fl)
+						 const struct flowi *fl, u16 family)
 {
 	struct xfrm_policy *pol;
 
@@ -1256,8 +1256,7 @@
  again:
 	pol = rcu_dereference(sk->sk_policy[dir]);
 	if (pol != NULL) {
-		bool match = xfrm_selector_match(&pol->selector, fl,
-						 sk->sk_family);
+		bool match = xfrm_selector_match(&pol->selector, fl, family);
 		int err = 0;
 
 		if (match) {
@@ -2206,7 +2205,7 @@
 	sk = sk_const_to_full_sk(sk);
 	if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
 		num_pols = 1;
-		pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
+		pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family);
 		err = xfrm_expand_policies(fl, family, pols,
 					   &num_pols, &num_xfrms);
 		if (err < 0)
@@ -2485,7 +2484,7 @@
 	pol = NULL;
 	sk = sk_to_full_sk(sk);
 	if (sk && sk->sk_policy[dir]) {
-		pol = xfrm_sk_policy_lookup(sk, dir, &fl);
+		pol = xfrm_sk_policy_lookup(sk, dir, &fl, family);
 		if (IS_ERR(pol)) {
 			XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
 			return 0;
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index c47287d..a178e0d 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1235,8 +1235,6 @@
 		}
 	}
 
-	snd_fm801_chip_init(chip);
-
 	if ((chip->tea575x_tuner & TUNER_ONLY) == 0) {
 		if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
 				IRQF_SHARED, KBUILD_MODNAME, chip)) {
@@ -1248,6 +1246,8 @@
 		pci_set_master(pci);
 	}
 
+	snd_fm801_chip_init(chip);
+
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_fm801_free(chip);
 		return err;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 4bf4833..775c678 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -3600,11 +3600,15 @@
 HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI",	patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI",	patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI",	patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI",	patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",	patch_nvhdmi_8ch_7x),
 HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",	patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",	patch_nvhdmi),
@@ -3631,17 +3635,40 @@
 HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",	patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP",	patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP",	patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",	patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI",	patch_nvhdmi_2ch),
 HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",	patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",	patch_via_hdmi),
 HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",	patch_generic_hdmi),
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index e643be9..f9f2737 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -1928,7 +1928,8 @@
 			NAU8825_FLL_INTEGER_MASK, fll_param->fll_int);
 	/* FLL pre-scaler */
 	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL4,
-			NAU8825_FLL_REF_DIV_MASK, fll_param->clk_ref_div);
+			NAU8825_FLL_REF_DIV_MASK,
+			fll_param->clk_ref_div << NAU8825_FLL_REF_DIV_SFT);
 	/* select divided VCO input */
 	regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
 		NAU8825_FLL_CLK_SW_MASK, NAU8825_FLL_CLK_SW_REF);
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h
index 1c63e2a..574d6f9 100644
--- a/sound/soc/codecs/nau8825.h
+++ b/sound/soc/codecs/nau8825.h
@@ -129,7 +129,8 @@
 #define NAU8825_FLL_CLK_SRC_FS			(0x3 << NAU8825_FLL_CLK_SRC_SFT)
 
 /* FLL4 (0x07) */
-#define NAU8825_FLL_REF_DIV_MASK		(0x3 << 10)
+#define NAU8825_FLL_REF_DIV_SFT	10
+#define NAU8825_FLL_REF_DIV_MASK	(0x3 << NAU8825_FLL_REF_DIV_SFT)
 
 /* FLL5 (0x08) */
 #define NAU8825_FLL_PDB_DAC_EN		(0x1 << 15)
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 5a8d96e..fe45a16 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -126,6 +126,16 @@
 	{ 108, 0x00 }, { 109, 0x00 },
 };
 
+static bool aic3x_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AIC3X_RESET:
+		return true;
+	default:
+		return false;
+	}
+}
+
 static const struct regmap_config aic3x_regmap = {
 	.reg_bits = 8,
 	.val_bits = 8,
@@ -133,6 +143,9 @@
 	.max_register = DAC_ICC_ADJ,
 	.reg_defaults = aic3x_reg,
 	.num_reg_defaults = ARRAY_SIZE(aic3x_reg),
+
+	.volatile_reg = aic3x_volatile_reg,
+
 	.cache_type = REGCACHE_RBTREE,
 };
 
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 5034943..fde08660 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -224,6 +224,12 @@
  * @dbg_stats: Debugging statistics
  *
  * @soc: SoC specific data
+ *
+ * @fifo_watermark: the FIFO watermark setting.  Notifies DMA when
+ *             there are @fifo_watermark or fewer words in TX fifo or
+ *             @fifo_watermark or more empty words in RX fifo.
+ * @dma_maxburst: max number of words to transfer in one go.  So far,
+ *             this is always the same as fifo_watermark.
  */
 struct fsl_ssi_private {
 	struct regmap *regs;
@@ -263,6 +269,9 @@
 
 	const struct fsl_ssi_soc_data *soc;
 	struct device *dev;
+
+	u32 fifo_watermark;
+	u32 dma_maxburst;
 };
 
 /*
@@ -1051,21 +1060,7 @@
 	regmap_write(regs, CCSR_SSI_SRCR, srcr);
 	regmap_write(regs, CCSR_SSI_SCR, scr);
 
-	/*
-	 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
-	 * use FIFO 1. We program the transmit water to signal a DMA transfer
-	 * if there are only two (or fewer) elements left in the FIFO. Two
-	 * elements equals one frame (left channel, right channel). This value,
-	 * however, depends on the depth of the transmit buffer.
-	 *
-	 * We set the watermark on the same level as the DMA burstsize.  For
-	 * fiq it is probably better to use the biggest possible watermark
-	 * size.
-	 */
-	if (ssi_private->use_dma)
-		wm = ssi_private->fifo_depth - 2;
-	else
-		wm = ssi_private->fifo_depth;
+	wm = ssi_private->fifo_watermark;
 
 	regmap_write(regs, CCSR_SSI_SFCSR,
 			CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
@@ -1373,12 +1368,8 @@
 		dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
 			 PTR_ERR(ssi_private->baudclk));
 
-	/*
-	 * We have burstsize be "fifo_depth - 2" to match the SSI
-	 * watermark setting in fsl_ssi_startup().
-	 */
-	ssi_private->dma_params_tx.maxburst = ssi_private->fifo_depth - 2;
-	ssi_private->dma_params_rx.maxburst = ssi_private->fifo_depth - 2;
+	ssi_private->dma_params_tx.maxburst = ssi_private->dma_maxburst;
+	ssi_private->dma_params_rx.maxburst = ssi_private->dma_maxburst;
 	ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0;
 	ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0;
 
@@ -1543,6 +1534,47 @@
                 /* Older 8610 DTs didn't have the fifo-depth property */
 		ssi_private->fifo_depth = 8;
 
+	/*
+	 * Set the watermark for transmit FIFO 0 and receive FIFO 0. We don't
+	 * use FIFO 1 but set the watermark appropriately nontheless.
+	 * We program the transmit water to signal a DMA transfer
+	 * if there are N elements left in the FIFO. For chips with 15-deep
+	 * FIFOs, set watermark to 8.  This allows the SSI to operate at a
+	 * high data rate without channel slipping. Behavior is unchanged
+	 * for the older chips with a fifo depth of only 8.  A value of 4
+	 * might be appropriate for the older chips, but is left at
+	 * fifo_depth-2 until sombody has a chance to test.
+	 *
+	 * We set the watermark on the same level as the DMA burstsize.  For
+	 * fiq it is probably better to use the biggest possible watermark
+	 * size.
+	 */
+	switch (ssi_private->fifo_depth) {
+	case 15:
+		/*
+		 * 2 samples is not enough when running at high data
+		 * rates (like 48kHz @ 16 bits/channel, 16 channels)
+		 * 8 seems to split things evenly and leave enough time
+		 * for the DMA to fill the FIFO before it's over/under
+		 * run.
+		 */
+		ssi_private->fifo_watermark = 8;
+		ssi_private->dma_maxburst = 8;
+		break;
+	case 8:
+	default:
+		/*
+		 * maintain old behavior for older chips.
+		 * Keeping it the same because I don't have an older
+		 * board to test with.
+		 * I suspect this could be changed to be something to
+		 * leave some more space in the fifo.
+		 */
+		ssi_private->fifo_watermark = ssi_private->fifo_depth - 2;
+		ssi_private->dma_maxburst = ssi_private->fifo_depth - 2;
+		break;
+	}
+
 	dev_set_drvdata(&pdev->dev, ssi_private);
 
 	if (ssi_private->soc->imx) {
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index d5873ee..bd19fad 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -142,7 +142,7 @@
 		 * for Jack detection and button press
 		 */
 		ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK,
-					     0,
+					     48000 * 512,
 					     SND_SOC_CLOCK_IN);
 		if (!ret) {
 			if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk)
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c
index 8fc3178..b30bd38 100644
--- a/sound/soc/intel/skylake/skl-sst.c
+++ b/sound/soc/intel/skylake/skl-sst.c
@@ -515,6 +515,9 @@
 
 void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
 {
+
+	if (ctx->dsp->fw)
+		release_firmware(ctx->dsp->fw);
 	skl_clear_module_table(ctx->dsp);
 	skl_freeup_uuid_list(ctx);
 	skl_ipc_free(&ctx->ipc);
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 70e1477..6bd424b 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -384,6 +384,9 @@
 	if (unlikely(atomic_read(&ep->chip->shutdown)))
 		goto exit_clear;
 
+	if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+		goto exit_clear;
+
 	if (usb_pipeout(ep->pipe)) {
 		retire_outbound_urb(ep, ctx);
 		/* can be stopped during retire callback */
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c
index f1ce600..ec30c2f 100644
--- a/tools/lib/traceevent/plugin_sched_switch.c
+++ b/tools/lib/traceevent/plugin_sched_switch.c
@@ -111,7 +111,7 @@
 	trace_seq_printf(s, "%lld ", val);
 
 	if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
-		trace_seq_printf(s, "[%lld] ", val);
+		trace_seq_printf(s, "[%d] ", (int) val);
 
 	if (pevent_get_field_val(s,  event, "prev_state", record, &val, 0) == 0)
 		write_state(s, val);
@@ -129,7 +129,7 @@
 	trace_seq_printf(s, "%lld", val);
 
 	if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
-		trace_seq_printf(s, " [%lld]", val);
+		trace_seq_printf(s, " [%d]", (int) val);
 
 	return 0;
 }
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 982d643..ef52d1e 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -729,9 +729,9 @@
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
 		$(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
 
-install-bin: install-tools install-tests
+install-bin: install-tools install-tests install-traceevent-plugins
 
-install: install-bin try-install-man install-traceevent-plugins
+install: install-bin try-install-man
 
 install-python_ext:
 	$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 7ea13f4..6c50d9f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -268,21 +268,6 @@
 }
 
 /*
- * NOTE:
- * '.gnu.linkonce.this_module' section of kernel module elf directly
- * maps to 'struct module' from linux/module.h. This section contains
- * actual module name which will be used by kernel after loading it.
- * But, we cannot use 'struct module' here since linux/module.h is not
- * exposed to user-space. Offset of 'name' has remained same from long
- * time, so hardcoding it here.
- */
-#ifdef __LP64__
-#define MOD_NAME_OFFSET 24
-#else
-#define MOD_NAME_OFFSET 12
-#endif
-
-/*
  * @module can be module name of module file path. In case of path,
  * inspect elf and find out what is actual module name.
  * Caller has to free mod_name after using it.
@@ -296,6 +281,7 @@
 	Elf_Data *data;
 	Elf_Scn *sec;
 	char *mod_name = NULL;
+	int name_offset;
 
 	fd = open(module, O_RDONLY);
 	if (fd < 0)
@@ -317,7 +303,21 @@
 	if (!data || !data->d_buf)
 		goto ret_err;
 
-	mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET);
+	/*
+	 * NOTE:
+	 * '.gnu.linkonce.this_module' section of kernel module elf directly
+	 * maps to 'struct module' from linux/module.h. This section contains
+	 * actual module name which will be used by kernel after loading it.
+	 * But, we cannot use 'struct module' here since linux/module.h is not
+	 * exposed to user-space. Offset of 'name' has remained same from long
+	 * time, so hardcoding it here.
+	 */
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
+		name_offset = 12;
+	else	/* expect ELFCLASS64 by default */
+		name_offset = 24;
+
+	mod_name = strdup((char *)data->d_buf + name_offset);
 
 ret_err:
 	elf_end(elf);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 99400b0..adbc6c0 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -537,6 +537,12 @@
 				break;
 		} else {
 			int n = namesz + descsz;
+
+			if (n > (int)sizeof(bf)) {
+				n = sizeof(bf);
+				pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n",
+					 __func__, filename, nhdr.n_namesz, nhdr.n_descsz);
+			}
 			if (read(fd, bf, n) != n)
 				break;
 		}