Merge "drm/msm/sde: print fence information during failure" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 53e4295..592fcef 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -73,9 +73,6 @@
 	  AMBA markee):
 		- "arm,coresight-replicator"
 		- "qcom,coresight-csr"
-		- "arm,coresight-cti"
-		- "qcom,coresight-tpda"
-		- "qcom,coresight-tpdm"
 		- "qcom,coresight-remote-etm"
 		- "qcom,coresight-hwevent"
 		- "qcom,coresight-dummy"
@@ -144,6 +141,20 @@
 	* qcom,msr-fix-req: boolean, indicating if MSRs need to be programmed
 	  after enabling the subunit.
 
+* Optional properties for CTI:
+
+	* qcom,cti-gpio-trigin: cti trigger input driven by gpio.
+
+	* qcom,cti-gpio-trigout: cti trigger output sent to gpio.
+
+	* pinctrl-names: names corresponding to the numbered pinctrl. The
+	  allowed names are subset of the following: cti-trigin-pinctrl,
+	  cti-trigout-pctrl.
+
+	* pinctrl-<n>: list of pinctrl phandles for the different pinctrl
+	  states. Refer to
+	  "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt"
+
 * Required property for Remote ETMs:
 
 	* qcom,inst-id: must be present. QMI instance id for remote ETMs.
@@ -264,7 +275,7 @@
 	};
 
 	tpda_mss: tpda@7043000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "qcom,coresight-tpda", "arm,primecell";
 		reg = <0x7043000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -274,9 +285,8 @@
 		qcom,dsb-elem-size = <0 32>;
 		qcom,cmb-elem-size = <0 32>;
 
-		clocks = <&clock_gcc clk_qdss_clk>,
-			 <&clock_gcc clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop clk_qdss_clk>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -345,15 +355,14 @@
 	};
 
 	tpdm_mss: tpdm@7042000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "qcom,coresight-tpdm", "arm,primecell";
 		reg = <0x7042000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-mss";
 
-		clocks = <&clock_gcc clk_qdss_clk>,
-			 <&clock_gcc clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop qdss_clk>;
+		clock-names = "apb_pclk";
 
 		port{
 			tpdm_mss_out_tpda_mss: endpoint {
@@ -364,15 +373,14 @@
 
 4. CTIs
 	cti0: cti@6010000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,coresight-cti", "arm,primecell";
 		reg = <0x6010000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti0";
 
-		clocks = <&clock_gcc clk_qdss_clk>,
-			 <&clock_gcc clk_qdss_a_clk>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop qdss_clk>;
+		clock-names = "apb_pclk";
 	};
 
 [1]. There is currently two version of STM: STM32 and STM500.  Both
diff --git a/Documentation/devicetree/bindings/arm/msm/cmd-db.txt b/Documentation/devicetree/bindings/arm/msm/cmd-db.txt
index b989d8a..e704d70 100644
--- a/Documentation/devicetree/bindings/arm/msm/cmd-db.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cmd-db.txt
@@ -24,10 +24,12 @@
 	Value type: <prop-encoded-array>
 	Definition: First element is the base address of shared memory
 		Second element is the size of the shared memory region
+		Points to the dictionary address that houses the command DB
+		start address and the size of the command DB region
 
 Example:
 
 qcom,cmd-db@861e0000 {
 	compatible = "qcom,cmd-db";
-	reg = <0x861e0000 0x4000>;
+	reg = <0xc3f000c 0x8>;
 }
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index bc226a7..a3ef34c 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -128,6 +128,8 @@
 				feature is available or not.
 - qcom,sde-has-dim-layer:	Boolean property to indicate if mixer has dim layer
 				feature is available or not.
+- qcom,sde-has-idle-pc:		Boolean property to indicate if target has idle
+				power collapse feature available or not.
 - qcom,sde-has-mixer-gc:	Boolean property to indicate if mixer has gamma correction
 				feature available or not.
 - qcom,sde-has-cdp:		Boolean property to indicate if cdp feature is
@@ -420,6 +422,7 @@
     qcom,sde-csc-type = "csc-10bit";
     qcom,sde-highest-bank-bit = <15>;
     qcom,sde-has-mixer-gc;
+    qcom,sde-has-idle-pc;
     qcom,sde-sspp-max-rects = <1 1 1 1
 				1 1 1 1
 				1 1
diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
index 3e7fcb7..ffba081 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt
@@ -35,7 +35,7 @@
 - qcom,mdss-dsi-panel-destination:	A string that specifies the destination display for the panel.
 					"display_1" = DISPLAY_1
 					"display_2" = DISPLAY_2
-- qcom,mdss-dsi-panel-timings:		An array of length 12 that specifies the PHY
+- qcom,mdss-dsi-panel-phy-timings:	An array of length 12 that specifies the PHY
 					timing settings for the panel.
 - qcom,mdss-dsi-panel-timings-8996:		An array of length 40 char that specifies the 8996 PHY lane
 					timing settings for the panel.
@@ -456,28 +456,6 @@
 					with the supply entry index. For a detailed description of
 					fields in the supply entry, refer to the qcom,ctrl-supply-entries
 					binding above.
-- qcom,config-select:			Optional property to select default configuration.
-
-[[Optional config sub-nodes]]		These subnodes provide different configurations for a given same panel.
-					Default configuration can be chosen by specifying phandle of the
-					selected subnode in the qcom,config-select.
-Required properties for sub-nodes:	None
-Optional properites:
-- qcom,lm-split:			An array of two values indicating MDP should use two layer
-					mixers to reduce power.
-					Ex: Normally 1080x1920 display uses single DSI and thus one layer
-					    mixer. But if we use two layer mixers then mux the output of
-					    those two mixers into single stream and route it to single DSI
-					    then we can lower the clock requirements of MDP. To use this
-					    configuration we need two fill this array with <540 540>.
-					Both values doesn't have to be same, but recommended, however sum of
-					both values has to be equal to the panel-width.
-					By default two mixer streams are merged using 2D mux, however if
-					2 DSC encoders are used then merge is performed within compression
-					engine.
-- qcom,split-mode:			String property indicating which split mode MDP should use. Valid
-					entries are "pingpong-split" and "dualctl-split".
-					This property is mutually exclusive with qcom,lm-split.
 - qcom,mdss-dsc-version:		An 8 bit value indicates the DSC version supported by panel. Bits[0.3]
 					provides information about minor version while Bits[4.7] provides
 					major version information. It supports only DSC rev 1(Major).1(Minor)
@@ -500,6 +478,21 @@
 - qcom,mdss-dsc-block-prediction-enable: A boolean value to enable/disable the block prediction at decoder.
 - qcom,mdss-dsc-config-by-manufacture-cmd: A boolean to indicates panel use manufacture command to setup pps
 					instead of standard dcs type 0x0A.
+- qcom,display-topology:  		Array of u32 values which specifies the	list of topologies available
+					for the display. A display topology is defined by a
+					set of 3 values in the order:
+					- number of mixers
+					- number of compression encoders
+					- number of interfaces
+					Therefore, the array should always contain a tuple of 3 elements.
+- qcom,default-topology-index:          An u32 value which indexes the topology set
+					specified by the node "qcom,display-topology"
+					to identify the default topology for the
+					display. The first set is indexed by the
+					value 0.
+
+Required properties for sub-nodes:	None
+Optional properties:
 - qcom,dba-panel:	Indicates whether the current panel is used as a display bridge
 					to a non-DSI interface.
 - qcom,bridge-name:			A string to indicate the name of the bridge chip connected to DSI. qcom,bridge-name
@@ -692,18 +685,15 @@
 					29 00 00 00 00 00 02 F1 00];
 				qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode";
 
-				qcom,config-select = <&dsi_sim_vid_config0>;
-				dsi_sim_vid_config0: config0 {
-					qcom,lm-split = <360 360>;
-					qcom,mdss-dsc-encoders = <2>;
-					qcom,mdss-dsc-slice-height = <16>;
-					qcom,mdss-dsc-slice-width = <360>;
-					qcom,mdss-dsc-slice-per-pkt = <2>;
-					qcom,mdss-dsc-bit-per-component = <8>;
-					qcom,mdss-dsc-bit-per-pixel = <8>;
-					qcom,mdss-dsc-block-prediction-enable;
-					qcom,mdss-dsc-config-by-manufacture-cmd;
-				};
+				qcom,mdss-dsc-slice-height = <16>;
+				qcom,mdss-dsc-slice-width = <360>;
+				qcom,mdss-dsc-slice-per-pkt = <2>;
+				qcom,mdss-dsc-bit-per-component = <8>;
+				qcom,mdss-dsc-bit-per-pixel = <8>;
+				qcom,mdss-dsc-block-prediction-enable;
+				qcom,mdss-dsc-config-by-manufacture-cmd;
+				qcom,display-topology = <1 1 1>;
+				qcom,default-topology-index = <0>;
 			};
 		};
 		qcom,panel-supply-entries {
@@ -737,41 +727,19 @@
 			};
 		};
 
-		qcom,config-select = <&dsi_sim_vid_config0>;
 		qcom,dba-panel;
 		qcom,bridge-name = "adv7533";
 		qcom,mdss-dsc-version = <0x11>;
 		qcom,mdss-dsc-scr-version = <0x1>;
-
-		dsi_sim_vid_config0: config0 {
-			qcom,lm-split = <360 360>;
-			qcom,mdss-dsc-encoders = <2>;
-			qcom,mdss-dsc-slice-height = <16>;
-			qcom,mdss-dsc-slice-width = <360>;
-			qcom,mdss-dsc-slice-per-pkt = <2>;
-			qcom,mdss-dsc-bit-per-component = <8>;
-			qcom,mdss-dsc-bit-per-pixel = <8>;
-			qcom,mdss-dsc-block-prediction-enable;
-			qcom,mdss-dsc-config-by-manufacture-cmd;
-		};
-
-		dsi_sim_vid_config1: config1 {
-			qcom,mdss-dsc-encoders = <1>;
-			qcom,mdss-dsc-slice-height = <16>;
-			qcom,mdss-dsc-slice-width = <360>;
-			qcom,mdss-dsc-slice-per-pkt = <2>;
-			qcom,mdss-dsc-bit-per-component = <8>;
-			qcom,mdss-dsc-bit-per-pixel = <8>;
-			qcom,mdss-dsc-block-prediction-enable;
-			qcom,mdss-dsc-config-by-manufacture-cmd;
-		};
-
-		dsi_sim_vid_config2: config2 {
-			qcom,split-mode = "dualctl-split";
-		};
-
-		dsi_sim_vid_config3: config3 {
-			qcom,split-mode = "pingpong-split";
-		};
+		qcom,mdss-dsc-slice-height = <16>;
+		qcom,mdss-dsc-slice-width = <360>;
+		qcom,mdss-dsc-slice-per-pkt = <2>;
+		qcom,mdss-dsc-bit-per-component = <8>;
+		qcom,mdss-dsc-bit-per-pixel = <8>;
+		qcom,mdss-dsc-block-prediction-enable;
+		qcom,mdss-dsc-config-by-manufacture-cmd;
+		qcom,display-topology = <1 1 1>,
+			                <2 2 1>;
+		qcom,default-topology-index = <0>;
 	};
 };
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
new file mode 100644
index 0000000..2ed913c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
@@ -0,0 +1,130 @@
+* Qualcomm Technologies, Inc. MSM Camera SMMU
+
+The MSM camera SMMU device provides SMMU context bank definitions
+for all HW blocks that need to map IOVA to physical memory. These
+definitions consist of various properties that define how the
+IOVA address space is laid out for each HW block in the camera
+subsystem.
+
+=======================
+Required Node Structure
+=======================
+The camera SMMU device must be described in three levels of device nodes. The
+first level describes the overall SMMU device. Within it, second level nodes
+describe individual context banks that map different stream ids. There can
+also be second level nodes describing firmware device nodes. Each HW block
+such as IFE, ICP maps into these second level device nodes. All context bank
+specific properties that define how the IOVA is laid out is contained within
+third level device nodes within the second level device nodes.
+
+During the kernel initialization all the devices are probed recursively and
+a device pointer is created for each context bank keeping track of the IOVA
+mapping information.
+
+Duplicate regions of the same type are not allowed within the same
+context bank. All context banks must contain an IO region at the very least.
+
+==================================
+First Level Node - CAM SMMU device
+==================================
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,msm-cam-smmu".
+
+===================================================================
+Second Level Node - CAM SMMU context bank device or firmware device
+===================================================================
+- compatible
+  Usage: required
+  Value type: <string>
+  Definition: Should be "qcom,msm-cam-smmu-cb" or "qcom,msm-cam-smmu-fw-dev".
+
+- memory-region
+  Usage: optional
+  Value type: <phandle>
+  Definition: Should specify the phandle of the memory region for firmware.
+    allocation
+
+- iommus
+  Usage: required
+  Value type: <phandle>
+  Definition: Should specify the phandle of the iommu sid.
+
+- label
+  Usage: required
+  Value type: <string>
+  Definition: Should specify a string label to identify the context bank.
+
+=============================================
+Third Level Node - CAM SMMU memory map device
+=============================================
+- iova-region-name
+  Usage: required
+  Value type: <string>
+  Definition: Should specify a string label to identify the IOVA region.
+
+- iova-region-start
+  Usage: required
+  Value type: <u32>
+  Definition: Should specify start IOVA for region.
+
+- iova-region-len
+  Usage: required
+  Value type: <u32>
+  Definition: Should specify length for IOVA region.
+
+- iova-region-id
+  Usage: required
+  Value type: <u32>
+  Definition: Should specify the numerical identifier for IOVA region.
+    Allowed values are: 0x00 to 0x03
+      - Firmware region: 0x00
+      - Shared region: 0x01
+      - Scratch region: 0x02
+      - IO region: 0x03
+
+Example:
+	qcom,cam_smmu@0 {
+		compatible = "qcom,msm-cam-smmu";
+
+		msm_cam_smmu_icp {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x1078>,
+				<&apps_smmu 0x1020>,
+				<&apps_smmu 0x1028>,
+				<&apps_smmu 0x1040>,
+				<&apps_smmu 0x1048>,
+				<&apps_smmu 0x1030>,
+				<&apps_smmu 0x1050>;
+			label = "icp";
+			icp_iova_mem_map: iova-mem-map {
+				iova-mem-region-firmware {
+					/* Firmware region is 5MB */
+				        iova-region-name = "firmware";
+				        iova-region-start = <0x0>;
+				        iova-region-len = <0x500000>;
+					iova-region-id = <0x0>;
+					status = "ok";
+				};
+
+			        iova-mem-region-shared {
+					/* Shared region is 100MB long */
+				        iova-region-name = "shared";
+				        iova-region-start = <0x7400000>;
+				        iova-region-len = <0x6400000>;
+					iova-region-id = <0x1>;
+				        status = "ok";
+				};
+
+			        iova-mem-region-io {
+				        /* IO region is approximately 3.5 GB */
+				        iova-region-name = "io";
+					iova-region-start = <0xd800000>;
+				        iova-region-len = <0xd2800000>;
+				        iova-region-id = <0x3>;
+				        status = "ok";
+				};
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index ea828da..bc844de 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -16,6 +16,10 @@
 		      If "halt_base" is in same 4K pages this register then
 		      this will be defined else "halt_q6", "halt_modem",
 		      "halt_nc" is required.
+		      "pdc_sync" is the power domain register introduced in
+		      sdm845 for power domain of subsystems.
+		      If alternative reset is required, "alt_reset" maps to
+		      mss_alt_ares.
 - interrupts:         The modem watchdog interrupt
 - vdd_cx-supply:      Reference to the regulator that supplies the vdd_cx domain.
 - vdd_cx-voltage:     Voltage corner/level(max) for cx rail.
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
index f4a22e0..e1f194f3 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
@@ -169,6 +169,18 @@
   Definition: Boolean flag which when present enables input suspend for
 		debug battery.
 
+- qcom,min-freq-khz
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the minimum charger buck/boost switching frequency
+		in KHz. It overrides the min frequency defined for the charger.
+
+- qcom,max-freq-khz
+  Usage:      optional
+  Value type: <u32>
+  Definition: Specifies the maximum charger buck/boost switching frequency in
+		 KHz. It overrides the max frequency defined for the charger.
+
 =============================================
 Second Level Nodes - SMB2 Charger Peripherals
 =============================================
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
index 92ef23c..5529e308 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
@@ -22,7 +22,8 @@
   Definition: String which indicates the charging mode. Can be one of the
 	      following:
               Standalone/Parallel Master	- "qcom,smb138x-charger"
-	      Parallel Slave			- "qcom,smb138x-parallel-slave"
+	      smb138x Parallel Slave		- "qcom,smb138x-parallel-slave"
+	      smb1355 Parallel Slave		- "qcom,smb1355-parallel-slave",
 
 - qcom,pmic-revid
   Usage:      required
@@ -35,7 +36,8 @@
   Usage:      optional
   Value type: <u32>
   Definition: Specifies parallel charging mode. If not specified, MID-MID
-	      option is selected by default.
+	      option is selected by default. Note that smb1355 can only
+	      run in MID-MID configuration.
 
 - qcom,suspend-input
   Usage:      optional
@@ -125,7 +127,7 @@
 =======
 
 smb138x_charger: qcom,smb138x-charger {
-	compatible = "qcom,qpnp-smb138x-charger";
+	compatible = "qcom,smb138x-charger";
 	#address-cells = <1>;
 	#size-cells = <1>;
 
diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
index 5bf560e..846bd22 100644
--- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
@@ -216,6 +216,15 @@
 		    as the corresponding addresses are specified in
 		    the qcom,cpr-panic-reg-addr-list property.
 
+- qcom,cpr-reset-step-quot-loop-en
+	Usage:      optional; only meaningful for CPR4 and CPRh controllers
+	Value type: <empty>
+	Definition: Boolean value which indicates that the CPR controller should
+		    be configured to reset step_quot on each loop_en = 0
+		    transition. This configuration allows the CPR controller to
+		    first use the default step_quot and then later switch to the
+		    run-time calibrated step_quot.
+
 - qcom,saw-avs-ctrl
 	Usage:      required if "saw" registers are specified by reg and
 		    reg-names properties
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
index bb20644..fc8ec87 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-temp-alarm.txt
@@ -12,10 +12,17 @@
 - interrupts:      PMIC temperature alarm interrupt
 - label:           A string used as a descriptive name for this thermal device.
 		    This name should be 19 characters or less.
+- #thermal-sensor-cells: Must be 0. Please refer to
+			 <devicetree/bindings/thermal/thermal.txt> for more
+			 details.
 
 Required structure:
 - A qcom,qpnp-temp-alarm node must be a child of an SPMI node that has specified
    the spmi-slave-container property
+- A top level device tree node named "thermal-zones" must exist. It must
+   contain a subnode with a property named "thermal-sensors" which is assigned
+   a phandle to the qpnp-temp-alarm device node. See
+   <devicetree/bindings/thermal/thermal.txt> for more details.
 
 Optional properties:
 - qcom,channel-num:    VADC channel number associated PMIC DIE_TEMP thermistor.
@@ -38,11 +45,6 @@
 			 1 = 50 Hz
 			 2 = 25 Hz
 			 3 = 12.5 Hz
-- qcom,allow-override: Boolean which controls the ability of software to
-			override shutdowns.  If present, then software is
-			allowed to override automatic PMIC hardware stage 2 and
-			stage 3 over temperature shutdowns.  Otherwise, software
-			is not allowed to override automatic shutdown.
 - qcom,default-temp:   Specifies the default temperature in millicelcius to use
 			if no ADC channel is present to read the real time
 			temperature.
@@ -64,7 +66,7 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		qcom,temp-alarm@2400 {
+		pm8941_tz: qcom,temp-alarm@2400 {
 			compatible = "qcom,qpnp-temp-alarm";
 			reg = <0x2400 0x100>;
 			interrupts = <0x0 0x24 0x0>;
@@ -72,6 +74,36 @@
 			qcom,channel-num = <8>;
 			qcom,threshold-set = <0>;
 			qcom,temp_alarm-vadc = <&pm8941_vadc>;
+			#thermal-sensor-cells = <0>;
+		};
+	};
+};
+
+Below is an example thermal zone definition for the temperature alarm
+peripheral.
+thermal-zones {
+	pm8941_tz {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&pm8941_tz>;
+
+		trips {
+			pm8941-trip0 {
+				temperature = <105000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm8941-trip1 {
+				temperature = <125000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm8941-trip2 {
+				temperature = <145000>;
+				hysteresis = <0>;
+				type = "critical";
+			};
 		};
 	};
 };
diff --git a/Makefile b/Makefile
index 7040118..2b8f550 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 24
+SUBLEVEL = 25
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
index 967e71f..78a26c2 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
@@ -26,4 +26,5 @@
 &blsp1_uart2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart2_console_active>;
+	status = "ok";
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 0afa5a8..0078617 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -153,5 +153,8 @@
 		reg = <0x831000 0x200>;
 		interrupts = <0 26 0>;
 		status = "disabled";
+		clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>,
+			<&clock_gcc GCC_BLSP1_AHB_CLK>;
+		clock-names = "core", "iface";
 	};
 };
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index dc44f9d..1f6d2cc 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -207,6 +207,7 @@
 CONFIG_POWER_RESET=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_THERMAL=y
+CONFIG_REGULATOR=y
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
@@ -257,6 +258,7 @@
 CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_USB_BAM=y
 CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_QCOM_SCM=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_MSM_SMEM=y
 CONFIG_TRACER_PKT=y
@@ -264,6 +266,7 @@
 CONFIG_MSM_SMP2P_TEST=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_PWM=y
+CONFIG_QCOM_SHOW_RESUME_IRQ=y
 CONFIG_ANDROID=y
 CONFIG_EXT3_FS=y
 CONFIG_EXT4_FS_SECURITY=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 2bfcf87..5d61163 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -198,6 +198,7 @@
 CONFIG_THERMAL=y
 CONFIG_MSM_CDC_PINCTRL=y
 CONFIG_MSM_CDC_SUPPLY=y
+CONFIG_REGULATOR=y
 CONFIG_FB=y
 CONFIG_SOUND=y
 CONFIG_SND=y
@@ -247,13 +248,13 @@
 CONFIG_HWSPINLOCK_QCOM=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
+CONFIG_QCOM_SCM=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_TRACER_PKT=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
 CONFIG_PWM=y
 CONFIG_QCOM_SHOW_RESUME_IRQ=y
-CONFIG_RESET_CONTROLLER=y
 CONFIG_ANDROID=y
 CONFIG_STM=y
 CONFIG_EXT3_FS=y
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index c32324f..ff2cc3e 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -11,7 +11,8 @@
 	sdm845-v2-cdp.dtb \
 	sdm845-qrd.dtb \
 	sdm845-4k-panel-mtp.dtb \
-	sdm845-4k-panel-cdp.dtb
+	sdm845-4k-panel-cdp.dtb \
+	sdm845-4k-panel-qrd.dtb
 
 dtb-$(CONFIG_ARCH_SDM830) += sdm830-sim.dtb \
 	sdm830-rumi.dtb \
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index f1501fa..16d2474 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -61,7 +61,7 @@
 		reg = <0x15000000 0x80000>,
 			<0x150c2000 0x20>;
 		reg-names = "base", "tcu-base";
-		#iommu-cells = <1>;
+		#iommu-cells = <2>;
 		qcom,skip-init;
 		#global-interrupts = <1>;
 		#size-cells = <1>;
@@ -339,6 +339,6 @@
 		 * This SID belongs to PCIE. We can't use a fake SID for
 		 * the apps_smmu device.
 		 */
-		iommus = <&apps_smmu 0x1c03>;
+		iommus = <&apps_smmu 0x1c03 0>;
 	};
 };
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
index 4036ce5..655f447 100644
--- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -362,7 +362,7 @@
 		compatible = "qcom,msm-audio-ion";
 		qcom,smmu-version = <2>;
 		qcom,smmu-enabled;
-		iommus = <&apps_smmu 0x1821>;
+		iommus = <&apps_smmu 0x1821 0x0>;
 	};
 
 	qcom,msm-adsp-loader {
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index 15db8da..b119305 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -62,11 +62,12 @@
 			};
 		};
 
-		qcom,temp-alarm@2400 {
+		pm8998_tz: qcom,temp-alarm@2400 {
 			compatible = "qcom,qpnp-temp-alarm";
 			reg = <0x2400 0x100>;
 			interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
 			label = "pm8998_tz";
+			#thermal-sensor-cells = <0>;
 		};
 
 		pm8998_gpios: pinctrl@c000 {
@@ -197,3 +198,30 @@
 		#size-cells = <0>;
 	};
 };
+
+&thermal_zones {
+	pm8998_temp_alarm: pm8998_tz {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-governor = "step_wise";
+		thermal-sensors = <&pm8998_tz>;
+
+		trips {
+			pm8998_trip0: pm8998-trip0 {
+				temperature = <105000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm8998_trip1: pm8998-trip1 {
+				temperature = <125000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			pm8998_trip2: pm8998-trip2 {
+				temperature = <145000>;
+				hysteresis = <0>;
+				type = "critical";
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 923804f..b53f7ac 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -31,11 +31,12 @@
 			reg = <0x800 0x100>;
 		};
 
-		qcom,temp-alarm@2400 {
+		pmi8998_tz: qcom,temp-alarm@2400 {
 			compatible = "qcom,qpnp-temp-alarm";
 			reg = <0x2400 0x100>;
 			interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
 			label = "pmi8998_tz";
+			#thermal-sensor-cells = <0>;
 		};
 
 		pmi8998_gpios: pinctrl@c000 {
@@ -796,4 +797,28 @@
 			};
 		};
 	};
+
+	pmi8998_tz {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pmi8998_tz>;
+
+		trips {
+			pmi8998_trip0: pmi8998-trip0 {
+				temperature = <105000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			 pmi8998_trip1: pmi8998-trip1 {
+				temperature = <125000>;
+				hysteresis = <0>;
+				type = "passive";
+			};
+			 pmi8998_trip2: pmi8998-trip2 {
+				temperature = <145000>;
+				hysteresis = <0>;
+				type = "critical";
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
index d5646bf..6569219 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-cdp.dts
@@ -21,3 +21,26 @@
 	compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
 	qcom,board-id = <1 1>;
 };
+
+&dsi_dual_nt35597_truly_video_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+	connectors = <&sde_wb &dsi_sharp_4k_dsc_video_display>;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-panel-mode-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+	qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
index d641276..2e893de 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-mtp.dts
@@ -21,3 +21,26 @@
 	compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
 	qcom,board-id = <8 1>;
 };
+
+&dsi_dual_nt35597_truly_video_display {
+	/delete-property/ qcom,dsi-display-active;
+};
+
+&mdss_mdp {
+	connectors = <&sde_wb &dsi_sharp_4k_dsc_video_display>;
+};
+
+&dsi_sharp_4k_dsc_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-panel-mode-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-te-gpio = <&tlmm 10 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_sharp_4k_dsc_video_display {
+	qcom,dsi-display-active;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
new file mode 100644
index 0000000..6171c7b
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd.dts
@@ -0,0 +1,23 @@
+/* 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 "sdm845.dtsi"
+#include "sdm845-qrd.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. sdm845 4K Display Panel QRD";
+	compatible = "qcom,sdm845-qrd", "qcom,sdm845", "qcom,qrd";
+	qcom,board-id = <11 1>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
index 9d59a16..69dfe46 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
@@ -17,7 +17,7 @@
 #include <dt-bindings/clock/qcom,audio-ext-clk.h>
 
 &msm_audio_ion {
-	iommus = <&apps_smmu 0x1821>;
+	iommus = <&apps_smmu 0x1821 0x0>;
 	qcom,smmu-sid-mask = /bits/ 64 <0xf>;
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
index c0189a4..922e990 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
@@ -118,10 +118,12 @@
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_vdig-supply = <&camera_rear_ldo>;
-		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
-		qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
-		qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
-		qcom,cam-vreg-op-mode = <0 80000 105000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+		qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+		qcom,cam-vreg-op-mode = <0 80000 105000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk0_active
@@ -157,10 +159,12 @@
 		cam_vdig-supply = <&camera_ldo>;
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
-		qcom,cam-vreg-min-voltage = <1050000 0 3312000>;
-		qcom,cam-vreg-max-voltage = <1050000 0 3600000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <1050000 0 3312000 0>;
+		qcom,cam-vreg-max-voltage = <1050000 0 3600000 0>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk2_active
@@ -193,10 +197,12 @@
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_vdig-supply = <&camera_ldo>;
-		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
-		qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
-		qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
-		qcom,cam-vreg-op-mode = <0 80000 105000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+		qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+		qcom,cam-vreg-op-mode = <0 80000 105000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk1_active
@@ -240,10 +246,12 @@
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_vdig-supply = <&camera_rear_ldo>;
-		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
-		qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
-		qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
-		qcom,cam-vreg-op-mode = <0 80000 105000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+		qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+		qcom,cam-vreg-op-mode = <0 80000 105000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk0_active
@@ -280,10 +288,12 @@
 		cam_vdig-supply = <&camera_ldo>;
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
-		qcom,cam-vreg-min-voltage = <1050000 0 3312000>;
-		qcom,cam-vreg-max-voltage = <1050000 0 3600000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <1050000 0 3312000 0>;
+		qcom,cam-vreg-max-voltage = <1050000 0 3600000 0>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk2_active
@@ -322,10 +332,12 @@
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_vdig-supply = <&camera_ldo>;
-		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
-		qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
-		qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
-		qcom,cam-vreg-op-mode = <0 80000 105000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+		qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+		qcom,cam-vreg-op-mode = <0 80000 105000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk1_active
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
index c0189a4..922e990 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
@@ -118,10 +118,12 @@
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_vdig-supply = <&camera_rear_ldo>;
-		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
-		qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
-		qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
-		qcom,cam-vreg-op-mode = <0 80000 105000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+		qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+		qcom,cam-vreg-op-mode = <0 80000 105000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk0_active
@@ -157,10 +159,12 @@
 		cam_vdig-supply = <&camera_ldo>;
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
-		qcom,cam-vreg-min-voltage = <1050000 0 3312000>;
-		qcom,cam-vreg-max-voltage = <1050000 0 3600000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <1050000 0 3312000 0>;
+		qcom,cam-vreg-max-voltage = <1050000 0 3600000 0>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk2_active
@@ -193,10 +197,12 @@
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_vdig-supply = <&camera_ldo>;
-		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
-		qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
-		qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
-		qcom,cam-vreg-op-mode = <0 80000 105000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+		qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+		qcom,cam-vreg-op-mode = <0 80000 105000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk1_active
@@ -240,10 +246,12 @@
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_vdig-supply = <&camera_rear_ldo>;
-		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
-		qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
-		qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
-		qcom,cam-vreg-op-mode = <0 80000 105000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+		qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+		qcom,cam-vreg-op-mode = <0 80000 105000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk0_active
@@ -280,10 +288,12 @@
 		cam_vdig-supply = <&camera_ldo>;
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
-		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
-		qcom,cam-vreg-min-voltage = <1050000 0 3312000>;
-		qcom,cam-vreg-max-voltage = <1050000 0 3600000>;
-		qcom,cam-vreg-op-mode = <105000 0 80000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <1050000 0 3312000 0>;
+		qcom,cam-vreg-max-voltage = <1050000 0 3600000 0>;
+		qcom,cam-vreg-op-mode = <105000 0 80000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk2_active
@@ -322,10 +332,12 @@
 		cam_vio-supply = <&pm8998_lvs1>;
 		cam_vana-supply = <&pmi8998_bob>;
 		cam_vdig-supply = <&camera_ldo>;
-		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
-		qcom,cam-vreg-min-voltage = <0 3312000 1050000>;
-		qcom,cam-vreg-max-voltage = <0 3600000 1050000>;
-		qcom,cam-vreg-op-mode = <0 80000 105000>;
+		cam_clk-supply = <&titan_top_gdsc>;
+		qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig",
+			"cam_clk";
+		qcom,cam-vreg-min-voltage = <0 3312000 1050000 0>;
+		qcom,cam-vreg-max-voltage = <0 3600000 1050000 0>;
+		qcom,cam-vreg-op-mode = <0 80000 105000 0>;
 		qcom,gpio-no-mux = <0>;
 		pinctrl-names = "cam_default", "cam_suspend";
 		pinctrl-0 = <&cam_sensor_mclk1_active
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index cd9c8a8..3b9c26f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -71,7 +71,7 @@
 			<&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>,
 			<&clock_camcc CAM_CC_CSIPHY1_CLK>,
 			<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>,
-			<&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>,
+			<&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>,
 			<&clock_camcc CAM_CC_IFE_1_CSID_CLK>,
 			<&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>;
 		clock-names = "camnoc_axi_clk",
@@ -225,4 +225,108 @@
 			status = "ok";
 		};
 	};
+
+	qcom,cam_smmu {
+		compatible = "qcom,msm-cam-smmu";
+		status = "ok";
+
+		msm_cam_smmu_ife {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x808>,
+				<&apps_smmu 0x810>,
+				<&apps_smmu 0x818>,
+				<&apps_smmu 0xc08>,
+				<&apps_smmu 0xc10>,
+				<&apps_smmu 0xc18>;
+			label = "ife";
+			ife_iova_mem_map: iova-mem-map {
+				/* IO region is approximately 3.4 GB */
+				iova-mem-region-io {
+					iova-region-name = "io";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0xd8c00000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
+
+		msm_cam_icp_fw {
+			compatible = "qcom,msm-cam-smmu-fw-dev";
+			label="icp";
+			memory-region = <&pil_camera_mem>;
+		};
+
+		msm_cam_smmu_icp {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x1078>,
+				<&apps_smmu 0x1020>,
+				<&apps_smmu 0x1028>,
+				<&apps_smmu 0x1040>,
+				<&apps_smmu 0x1048>,
+				<&apps_smmu 0x1030>,
+				<&apps_smmu 0x1050>;
+			label = "icp";
+			icp_iova_mem_map: iova-mem-map {
+				iova-mem-region-firmware {
+					/* Firmware region is 5MB */
+					iova-region-name = "firmware";
+					iova-region-start = <0x0>;
+					iova-region-len = <0x500000>;
+					iova-region-id = <0x0>;
+					status = "ok";
+				};
+
+				iova-mem-region-shared {
+					/* Shared region is 100MB long */
+					iova-region-name = "shared";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0x6400000>;
+					iova-region-id = <0x1>;
+					status = "ok";
+				};
+
+				iova-mem-region-io {
+					/* IO region is approximately 3.3 GB */
+					iova-region-name = "io";
+					iova-region-start = <0xd800000>;
+					iova-region-len = <0xd2800000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
+
+		msm_cam_smmu_cpas_cdm {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x1000>;
+			label = "cpas-cdm0";
+			cpas_cdm_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";
+				};
+			};
+		};
+
+		msm_cam_smmu_secure {
+			compatible = "qcom,msm-cam-smmu-cb";
+			iommus = <&apps_smmu 0x1001>;
+			label = "cam-secure";
+			cam_secure_iova_mem_map: iova-mem-map {
+				/* Secure IO region is approximately 3.4 GB */
+				iova-mem-region-io {
+					iova-region-name = "io";
+					iova-region-start = <0x7400000>;
+					iova-region-len = <0xd8c00000>;
+					iova-region-id = <0x3>;
+					status = "ok";
+				};
+			};
+		};
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 6f35bf7..6f40fae 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -93,6 +93,10 @@
 	};
 };
 
+&mdss_mdp {
+	#cooling-cells = <2>;
+};
+
 &ufsphy_mem {
 	compatible = "qcom,ufs-phy-qmp-v3";
 
@@ -209,6 +213,30 @@
 	status = "ok";
 };
 
+&labibb {
+	status = "ok";
+	qcom,qpnp-labibb-mode = "lcd";
+};
+
+&dsi_dual_nt35597_truly_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-panel-mode-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+	qcom,dsi-display-active;
+};
+
+&pmi8998_wled {
+	status = "okay";
+	qcom,led-strings-list = [01 02];
+};
+
 &qupv3_se8_spi {
 	status = "ok";
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index 1a0ec0b..91946d7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -21,9 +21,8 @@
 
 		coresight-name = "coresight-replicator";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -57,9 +56,8 @@
 
 		coresight-name = "coresight-replicator-swao";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -106,9 +104,8 @@
 
 		coresight-name = "coresight-tmc-etf-swao";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -143,9 +140,8 @@
 
 		coresight-name = "coresight-funnel-swao";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -171,7 +167,8 @@
 	};
 
 	tpda_swao: tpda@6b01000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
 		reg = <0x6b01000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -181,9 +178,8 @@
 		qcom,dsb-elem-size = <1 32>;
 		qcom,cmb-elem-size = <0 64>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -220,16 +216,16 @@
 	};
 
 	tpdm_swao0: tpdm@6b02000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 
 		reg = <0x6b02000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-swao-0";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_swao0_out_tpda_swao: endpoint {
@@ -239,15 +235,15 @@
 	};
 
 	tpdm_swao1: tpdm@6b03000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x6b03000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name="coresight-tpdm-swao-1";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_swao1_out_tpda_swao: endpoint {
@@ -265,13 +261,13 @@
 		reg-names = "tmc-base", "bam-base";
 
 		arm,buffer-size = <0x400000>;
+		arm,sg-enable;
 
 		coresight-name = "coresight-tmc-etr";
 		coresight-ctis = <&cti0 &cti8>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tmc_etr_in_replicator: endpoint {
@@ -292,9 +288,8 @@
 		coresight-ctis = <&cti0 &cti8>;
 		arm,default-sink;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -329,9 +324,8 @@
 
 		coresight-name = "coresight-funnel-merg";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -375,9 +369,8 @@
 
 		coresight-name = "coresight-stm";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			stm_out_funnel_in0: endpoint {
@@ -387,6 +380,32 @@
 
 	};
 
+	hwevent: hwevent@0x014066f0 {
+		compatible = "qcom,coresight-hwevent";
+		reg = <0x14066f0 0x4>,
+		      <0x14166f0 0x4>,
+		      <0x1406038 0x4>,
+		      <0x1416038 0x4>;
+		reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl",
+			    "ddr-ch23-ctrl";
+
+		coresight-name = "coresight-hwevent";
+
+		clocks = <&clock_gcc RPMH_QDSS_CLK>,
+			 <&clock_gcc RPMH_QDSS_A_CLK>;
+		clock-names = "core_clk", "core_a_clk";
+	};
+
+	csr: csr@6001000 {
+		compatible = "qcom,coresight-csr";
+		reg = <0x6001000 0x1000>;
+		reg-names = "csr-base";
+
+		coresight-name = "coresight-csr";
+
+		qcom,blk-size = <1>;
+	};
+
 	funnel_in0: funnel@0x6041000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b908>;
@@ -396,9 +415,8 @@
 
 		coresight-name = "coresight-funnel-in0";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -449,9 +467,8 @@
 
 		coresight-name = "coresight-funnel-in2";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -498,7 +515,8 @@
 	};
 
 	tpda: tpda@6004000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
 		reg = <0x6004000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -512,6 +530,7 @@
 				     <2 32>,
 				     <3 32>,
 				     <5 32>,
+				     <6 32>,
 				     <10 32>,
 				     <11 32>,
 				     <13 32>;
@@ -519,9 +538,8 @@
 				     <7 64>,
 				     <13 64>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -572,6 +590,15 @@
 			};
 
 			port@5 {
+				reg = <6>;
+				tpda_in_funnel_turing: endpoint {
+					slave-mode;
+					remote-endpoint =
+						<&funnel_turing_out_tpda>;
+				};
+			};
+
+			port@6 {
 				reg = <7>;
 				tpda_in_tpdm_vsense: endpoint {
 					slave-mode;
@@ -580,7 +607,7 @@
 				};
 			};
 
-			port@6 {
+			port@7 {
 				reg = <10>;
 				tpda_in_tpdm_qm: endpoint {
 					slave-mode;
@@ -589,7 +616,7 @@
 				};
 			};
 
-			port@7 {
+			port@8 {
 				reg = <11>;
 				tpda_in_tpdm_north: endpoint {
 					slave-mode;
@@ -598,7 +625,7 @@
 				};
 			};
 
-			port@8 {
+			port@9 {
 				reg = <13>;
 				tpda_in_tpdm_pimem: endpoint {
 					slave-mode;
@@ -618,9 +645,8 @@
 
 		coresight-name = "coresight-funnel-modem";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -646,7 +672,8 @@
 	};
 
 	tpda_modem: tpda@6831000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
 		reg = <0x6831000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -656,9 +683,8 @@
 		qcom,dsb-elem-size = <0 32>;
 		qcom,cmb-elem-size = <0 64>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -683,15 +709,15 @@
 	};
 
 	tpdm_modem: tpdm@6830000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x6830000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-modem";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_modem_out_tpda_modem: endpoint {
@@ -709,9 +735,8 @@
 
 		coresight-name = "coresight-funnel-lpass";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -743,9 +768,8 @@
 
 		coresight-name = "coresight-tpdm-lpass";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "core_clk";
 
 		port {
 			tpdm_lpass_out_funnel_lpass: endpoint {
@@ -755,15 +779,15 @@
 	};
 
 	tpdm_center: tpdm@6c28000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x6c28000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-center";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_center_out_tpda: endpoint {
@@ -773,15 +797,15 @@
 	};
 
 	tpdm_north: tpdm@6a24000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x6a24000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-north";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_north_out_tpda: endpoint {
@@ -791,15 +815,15 @@
 	};
 
 	tpdm_qm: tpdm@69d0000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x69d0000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-qm";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_qm_out_tpda: endpoint {
@@ -809,7 +833,8 @@
 	};
 
 	tpda_apss: tpda@7862000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
 		reg = <0x7862000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -818,9 +843,8 @@
 		qcom,tpda-atid = <66>;
 		qcom,dsb-elem-size = <0 32>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -845,15 +869,15 @@
 	};
 
 	tpdm_apss: tpdm@7860000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x7860000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-apss";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_apss_out_tpda_apss: endpoint {
@@ -863,7 +887,8 @@
 	};
 
 	tpda_llm_silver: tpda@78c0000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
 		reg = <0x78c0000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -872,9 +897,8 @@
 		qcom,tpda-atid = <72>;
 		qcom,cmb-elem-size = <0 64>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -899,15 +923,15 @@
 	};
 
 	tpdm_llm_silver: tpdm@78a0000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x78a0000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-llm-silver";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_llm_silver_out_tpda_llm_silver: endpoint {
@@ -918,7 +942,8 @@
 	};
 
 	tpda_llm_gold: tpda@78d0000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
 		reg = <0x78d0000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -927,9 +952,8 @@
 		qcom,tpda-atid = <73>;
 		qcom,cmb-elem-size = <0 64>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -954,15 +978,15 @@
 	};
 
 	tpdm_llm_gold: tpdm@78b0000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x78b0000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-llm-gold";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_llm_gold_out_tpda_llm_gold: endpoint {
@@ -981,9 +1005,8 @@
 
 		coresight-name = "coresight-funnel-dl-mm";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -1009,15 +1032,15 @@
 	};
 
 	tpdm_mm: tpdm@6c08000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x6c08000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-mm";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_mm_out_funnel_dl_mm: endpoint {
@@ -1026,6 +1049,68 @@
 		};
 	};
 
+	funnel_turing: funnel@6861000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b908>;
+
+		reg = <0x6861000 0x1000>;
+		reg-names = "funnel-base";
+
+		coresight-name = "coresight-funnel-turing";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+				funnel_turing_out_tpda: endpoint {
+					remote-endpoint =
+					    <&tpda_in_funnel_turing>;
+				};
+			};
+
+			port@1 {
+				reg = <0>;
+				funnel_turing_in_tpdm_turing: endpoint {
+					slave-mode;
+					remote-endpoint =
+					    <&tpdm_turing_out_funnel_turing>;
+				};
+			};
+
+			port@2 {
+				reg = <1>;
+				funnel_turing_in_turing_etm0: endpoint {
+					slave-mode;
+					remote-endpoint =
+					    <&turing_etm0_out_funnel_turing>;
+				};
+			};
+		};
+	};
+
+	tpdm_turing: tpdm@6860000 {
+		compatible = "qcom,coresight-tpdm";
+		reg = <0x6860000 0x1000>;
+		reg-names = "tpdm-base";
+
+		coresight-name = "coresight-tpdm-turing";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		port {
+			tpdm_turing_out_funnel_turing: endpoint {
+				remote-endpoint =
+				    <&funnel_turing_in_tpdm_turing>;
+			};
+		};
+	};
+
 	funnel_ddr_0: funnel@69e2000 {
 		compatible = "arm,primecell";
 		arm,primecell-periphid = <0x0003b908>;
@@ -1035,9 +1120,8 @@
 
 		coresight-name = "coresight-funnel-ddr-0";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -1063,15 +1147,15 @@
 	};
 
 	tpdm_ddr: tpdm@69e0000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x69e0000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-ddr";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_ddr_out_funnel_ddr_0: endpoint {
@@ -1081,15 +1165,15 @@
 	};
 
 	tpdm_pimem: tpdm@6850000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x6850000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-pimem";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			tpdm_pimem_out_tpda: endpoint {
@@ -1099,15 +1183,15 @@
 	};
 
 	tpdm_vsense: tpdm@6840000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x6840000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-vsense";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port{
 			tpdm_vsense_out_tpda: endpoint {
@@ -1117,7 +1201,8 @@
 	};
 
 	tpda_olc: tpda@7832000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
 		reg = <0x7832000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -1126,9 +1211,8 @@
 		qcom,tpda-atid = <69>;
 		qcom,cmb-elem-size = <0 64>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -1152,15 +1236,15 @@
 	};
 
 	tpdm_olc: tpdm@7830000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x7830000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-olc";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port{
 			tpdm_olc_out_tpda_olc: endpoint {
@@ -1170,7 +1254,8 @@
 	};
 
 	tpda_spss: tpda@6882000 {
-		compatible = "qcom,coresight-tpda";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
 		reg = <0x6882000 0x1000>;
 		reg-names = "tpda-base";
 
@@ -1179,9 +1264,8 @@
 		qcom,tpda-atid = <70>;
 		qcom,dsb-elem-size = <0 32>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -1205,16 +1289,15 @@
 	};
 
 	tpdm_spss: tpdm@6880000 {
-		compatible = "qcom,coresight-tpdm";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b968>;
 		reg = <0x6880000 0x1000>;
 		reg-names = "tpdm-base";
 
 		coresight-name = "coresight-tpdm-spss";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
-
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 		qcom,msr-fix-req;
 
 		port{
@@ -1233,9 +1316,8 @@
 
 		coresight-name = "coresight-funnel-spss";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -1269,9 +1351,8 @@
 
 		coresight-name = "coresight-funnel-qatb";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -1296,300 +1377,358 @@
 		};
 	};
 
+	cti_ddr0: cti@69e1000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+		reg = <0x69e1000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr0";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	cti_ddr1: cti@69e4000 {
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b969>;
+		reg = <0x69e4000 0x1000>;
+		reg-names = "cti-base";
+
+		coresight-name = "coresight-cti-ddr1";
+
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
 	cti0: cti@6010000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6010000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti0";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti1: cti@6011000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6011000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti1";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti2: cti@6012000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6012000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti2";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
+		qcom,cti-gpio-trigout = <4>;
+		pinctrl-names = "cti-trigout-pctrl";
+		pinctrl-0 = <&trigout_a>;
 	};
 
 	cti3: cti@6013000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6013000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti3";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti4: cti@6014000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6014000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti4";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti5: cti@6015000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6015000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti5";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti6: cti@6016000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6016000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti6";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti7: cti@6017000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6017000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti7";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti8: cti@6018000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6018000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti8";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti9: cti@6019000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x6019000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti9";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti10: cti@601a000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x601a000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti10";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti11: cti@601b000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x601b000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti11";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti12: cti@601c000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x601c000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti12";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti13: cti@601d000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x601d000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti13";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti14: cti@601e000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x601e000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti14";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti15: cti@601f000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x601f000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti15";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti_cpu0: cti@7020000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x7020000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu0";
 		cpu = <&CPU0>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+
 	};
 
 	cti_cpu1: cti@7120000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x7120000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu1";
 		cpu = <&CPU1>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 	};
 
 	cti_cpu2: cti@7220000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x7220000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu2";
 		cpu = <&CPU2>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 	};
 
 	cti_cpu3: cti@7320000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x7320000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu3";
 		cpu = <&CPU3>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 	};
 
 	cti_cpu4: cti@7420000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x7420000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu4";
 		cpu = <&CPU4>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 	};
 
 	cti_cpu5: cti@7520000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x7520000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu5";
 		cpu = <&CPU5>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 	};
 
 	cti_cpu6: cti@7620000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x7620000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu6";
 		cpu = <&CPU6>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 	};
 
 	cti_cpu7: cti@7720000 {
-		compatible = "arm,coresight-cti";
+		compatible = "arm,primecell";
+		arm,primecell-periphid = <0x0003b966>;
 		reg = <0x7720000 0x1000>;
 		reg-names = "cti-base";
 
 		coresight-name = "coresight-cti-cpu7";
 		cpu = <&CPU7>;
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "core_clk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
+	};
+
+	turing_etm0 {
+		compatible = "qcom,coresight-remote-etm";
+
+		coresight-name = "coresight-turing-etm0";
+		qcom,inst-id = <1>;
+
+		port{
+			turing_etm0_out_funnel_turing: endpoint {
+				remote-endpoint =
+					<&funnel_turing_in_turing_etm0>;
+			};
+		};
 	};
 
 	dummy_eud: dummy_sink {
@@ -1616,9 +1755,8 @@
 
 		coresight-name = "coresight-funnel-apss-merg";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
@@ -1688,9 +1826,8 @@
 
 		coresight-name = "coresight-etm0";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			etm0_out_funnel_apss: endpoint {
@@ -1708,9 +1845,8 @@
 
 		coresight-name = "coresight-etm1";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			etm1_out_funnel_apss: endpoint {
@@ -1728,9 +1864,8 @@
 
 		coresight-name = "coresight-etm2";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			etm2_out_funnel_apss: endpoint {
@@ -1748,9 +1883,8 @@
 
 		coresight-name = "coresight-etm3";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			etm3_out_funnel_apss: endpoint {
@@ -1768,9 +1902,8 @@
 
 		coresight-name = "coresight-etm4";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			etm4_out_funnel_apss: endpoint {
@@ -1788,9 +1921,8 @@
 
 		coresight-name = "coresight-etm5";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			etm5_out_funnel_apss: endpoint {
@@ -1808,9 +1940,8 @@
 
 		coresight-name = "coresight-etm6";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			etm6_out_funnel_apss: endpoint {
@@ -1828,9 +1959,8 @@
 
 		coresight-name = "coresight-etm7";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		port {
 			etm7_out_funnel_apss: endpoint {
@@ -1848,9 +1978,8 @@
 
 		coresight-name = "coresight-funnel-apss";
 
-		clocks = <&clock_gcc RPMH_QDSS_CLK>,
-			 <&clock_gcc RPMH_QDSS_A_CLK>;
-		clock-names = "apb_pclk", "core_a_clk";
+		clocks = <&clock_aop QDSS_CLK>;
+		clock-names = "apb_pclk";
 
 		ports {
 			#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index bfbaabb..0ada391 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -77,13 +77,16 @@
 		#cooling-cells = <2>;
 
 		clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
-			<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
 			<&clock_gpucc GPU_CC_CXO_CLK>,
 			<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
-			<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+			<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+			<&clock_gpucc GPU_CC_CX_GMU_CLK>,
+			<&clock_gpucc GPU_CC_AHB_CLK>,
+			<&clock_gpucc GPU_CC_GX_CXO_CLK>;
 
-		clock-names = "core_clk", "iface_clk", "rbbmtimer_clk",
-			"mem_clk", "mem_iface_clk";
+		clock-names = "core_clk", "rbbmtimer_clk", "mem_clk",
+				"mem_iface_clk", "gmu_clk", "ahb_clk",
+				"cxo_clk";
 
 		qcom,isense-clk-on-level = <1>;
 
@@ -248,13 +251,13 @@
 
 
 		clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>,
-				<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
 				<&clock_gpucc GPU_CC_CXO_CLK>,
 				<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
-				<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+				<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
+				<&clock_gpucc GPU_CC_AHB_CLK>;
 
-		clock-names = "gmu_clk", "ahb_clk", "cxo_clk",
-				"axi_clk", "memnoc_clk";
+		clock-names = "gmu_clk", "cxo_clk", "axi_clk",
+				"memnoc_clk", "ahb_clk";
 
 		qcom,gmu-pwrlevels {
 			#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index faa0b5e..803843c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -78,6 +78,34 @@
 	};
 };
 
+&labibb {
+	status = "ok";
+	qcom,qpnp-labibb-mode = "lcd";
+};
+
+&dsi_dual_nt35597_truly_video {
+	qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+	qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+	qcom,mdss-dsi-bl-min-level = <1>;
+	qcom,mdss-dsi-bl-max-level = <4095>;
+	qcom,mdss-dsi-panel-mode-gpio-state = "dual_port";
+	qcom,panel-mode-gpio = <&tlmm 52 0>;
+	qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+	qcom,dsi-display-active;
+};
+
+&pmi8998_wled {
+	status = "okay";
+	qcom,led-strings-list = [01 02];
+};
+
+&mdss_mdp {
+	#cooling-cells = <2>;
+};
+
 &ufsphy_mem {
 	compatible = "qcom,ufs-phy-qmp-v3";
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index d6af58b..bc535d1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -2558,6 +2558,18 @@
 				drive-strength = <2>; /* 2 MA */
 			};
 		};
+
+		trigout_a: trigout_a {
+			mux {
+				pins = "gpio62", "gpio51";
+				function = "qdss_cti";
+			};
+			config {
+				pins = "gpio62", "gpio51";
+				drive-strength = <2>;
+				bias-disable;
+			};
+		};
 	};
 };
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 1d5bf3a..a4dc4753 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -22,6 +22,10 @@
 	qcom,battery-data = <&qrd_batterydata>;
 };
 
+&mdss_mdp {
+	#cooling-cells = <2>;
+};
+
 &soc {
 	sound-tavil {
 		qcom,wsa-max-devs = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 6989f326..f6c1d76 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -74,11 +74,12 @@
 		qcom,cpr-step-quot-init-min = <11>;
 		qcom,cpr-step-quot-init-max = <12>;
 		qcom,cpr-count-mode = <0>;		/* All at once */
-		qcom,cpr-count-repeat = <1>;
+		qcom,cpr-count-repeat = <20>;
 		qcom,cpr-down-error-step-limit = <1>;
 		qcom,cpr-up-error-step-limit = <1>;
 		qcom,cpr-corner-switch-delay-time = <1042>;
 		qcom,cpr-voltage-settling-time = <1760>;
+		qcom,cpr-reset-step-quot-loop-en;
 
 		qcom,voltage-step = <4000>;
 		qcom,voltage-base = <352000>;
@@ -103,7 +104,7 @@
 		thread@1 {
 			qcom,cpr-thread-id = <1>;
 			qcom,cpr-consecutive-up = <0>;
-			qcom,cpr-consecutive-down = <2>;
+			qcom,cpr-consecutive-down = <0>;
 			qcom,cpr-up-threshold = <2>;
 			qcom,cpr-down-threshold = <2>;
 
@@ -180,7 +181,7 @@
 		thread@0 {
 			qcom,cpr-thread-id = <0>;
 			qcom,cpr-consecutive-up = <0>;
-			qcom,cpr-consecutive-down = <2>;
+			qcom,cpr-consecutive-down = <0>;
 			qcom,cpr-up-threshold = <2>;
 			qcom,cpr-down-threshold = <2>;
 
@@ -264,11 +265,12 @@
 		qcom,cpr-step-quot-init-min = <9>;
 		qcom,cpr-step-quot-init-max = <14>;
 		qcom,cpr-count-mode = <0>;		/* All at once */
-		qcom,cpr-count-repeat = <1>;
+		qcom,cpr-count-repeat = <20>;
 		qcom,cpr-down-error-step-limit = <1>;
 		qcom,cpr-up-error-step-limit = <1>;
 		qcom,cpr-corner-switch-delay-time = <1042>;
 		qcom,cpr-voltage-settling-time = <1760>;
+		qcom,cpr-reset-step-quot-loop-en;
 
 		qcom,apm-threshold-voltage = <800000>;
 		qcom,apm-crossover-voltage = <880000>;
@@ -296,7 +298,7 @@
 		thread@0 {
 			qcom,cpr-thread-id = <0>;
 			qcom,cpr-consecutive-up = <0>;
-			qcom,cpr-consecutive-down = <2>;
+			qcom,cpr-consecutive-down = <0>;
 			qcom,cpr-up-threshold = <2>;
 			qcom,cpr-down-threshold = <2>;
 
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 2ff9b2f..efd8f45 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -23,6 +23,7 @@
 #include "dsi-panel-sharp-1080p-cmd.dtsi"
 #include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi"
 #include "dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi"
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
 
 &soc {
 	dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -106,8 +107,8 @@
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
 		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		       <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
 
 		pinctrl-names = "panel_active", "panel_suspend";
@@ -115,6 +116,7 @@
 		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
 		qcom,platform-te-gpio = <&tlmm 10 0>;
 		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
 
 		qcom,dsi-panel = <&dsi_sharp_4k_dsc_video>;
 		vddio-supply = <&pm8998_l14>;
@@ -129,8 +131,8 @@
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
 		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		       <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
 
 		pinctrl-names = "panel_active", "panel_suspend";
@@ -138,6 +140,7 @@
 		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
 		qcom,platform-te-gpio = <&tlmm 10 0>;
 		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
 
 		qcom,dsi-panel = <&dsi_sharp_4k_dsc_cmd>;
 		vddio-supply = <&pm8998_l14>;
@@ -152,8 +155,8 @@
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
 		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		       <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
 
 		pinctrl-names = "panel_active", "panel_suspend";
@@ -161,6 +164,7 @@
 		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
 		qcom,platform-te-gpio = <&tlmm 10 0>;
 		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
 
 		qcom,dsi-panel = <&dsi_sharp_1080_cmd>;
 		vddio-supply = <&pm8998_l14>;
@@ -175,8 +179,8 @@
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
 		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		       <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
 
 		pinctrl-names = "panel_active", "panel_suspend";
@@ -184,6 +188,7 @@
 		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
 		qcom,platform-te-gpio = <&tlmm 10 0>;
 		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
 
 		qcom,dsi-panel = <&dsi_dual_sharp_1080_120hz_cmd>;
 		vddio-supply = <&pm8998_l14>;
@@ -198,15 +203,15 @@
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
 		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		       <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
 
 		pinctrl-names = "panel_active", "panel_suspend";
 		pinctrl-0 = <&sde_dsi_active &sde_te_active>;
 		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
-		qcom,platform-te-gpio = <&tlmm 10 0>;
 		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
 
 		qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>;
 		vddio-supply = <&pm8998_l14>;
@@ -221,8 +226,8 @@
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
 		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		       <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
 
 		pinctrl-names = "panel_active", "panel_suspend";
@@ -230,6 +235,7 @@
 		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
 		qcom,platform-te-gpio = <&tlmm 10 0>;
 		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
 
 		qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>;
 		vddio-supply = <&pm8998_l14>;
@@ -244,8 +250,8 @@
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
 		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		       <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
 
 		pinctrl-names = "panel_active", "panel_suspend";
@@ -253,6 +259,7 @@
 		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
 		qcom,platform-te-gpio = <&tlmm 10 0>;
 		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
 
 		qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>;
 		vddio-supply = <&pm8998_l14>;
@@ -267,8 +274,8 @@
 
 		qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
 		qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		       <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+			<&mdss_dsi0_pll PCLK_MUX_0_CLK>;
 		clock-names = "src_byte_clk", "src_pixel_clk";
 
 		pinctrl-names = "panel_active", "panel_suspend";
@@ -276,6 +283,7 @@
 		pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
 		qcom,platform-te-gpio = <&tlmm 10 0>;
 		qcom,platform-reset-gpio = <&tlmm 6 0>;
+		qcom,panel-mode-gpio = <&tlmm 52 0>;
 
 		qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>;
 		vddio-supply = <&pm8998_l14>;
@@ -291,47 +299,47 @@
 };
 
 &mdss_mdp {
-	connectors = <&sde_wb>;
+	connectors = <&sde_wb &dsi_dual_nt35597_truly_video_display>;
 };
 
 &dsi_dual_nt35597_truly_video {
-	qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04];
+	qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0D>;
 	qcom,mdss-dsi-t-clk-pre = <0x2D>;
 };
 
 &dsi_dual_nt35597_truly_cmd {
-	qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04];
+	qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 07 05 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0D>;
 	qcom,mdss-dsi-t-clk-pre = <0x2D>;
 };
 
 &dsi_nt35597_truly_dsc_cmd {
-	qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04];
+	qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 05 03 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0b>;
 	qcom,mdss-dsi-t-clk-pre = <0x23>;
 };
 
 &dsi_nt35597_truly_dsc_video {
-	qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04];
+	qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 05 03 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0b>;
 	qcom,mdss-dsi-t-clk-pre = <0x23>;
 };
 
 &dsi_sharp_4k_dsc_video {
-	qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04];
-	qcom,mdss-dsi-t-clk-post = <0x0a>;
-	qcom,mdss-dsi-t-clk-pre = <0x1e>;
+	qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 06 04 03 04 00];
+	qcom,mdss-dsi-t-clk-post = <0x0c>;
+	qcom,mdss-dsi-t-clk-pre = <0x27>;
 };
 
 &dsi_sharp_4k_dsc_cmd {
-	qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04];
-	qcom,mdss-dsi-t-clk-post = <0x0a>;
-	qcom,mdss-dsi-t-clk-pre = <0x1e>;
+	qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 06 04 03 04 00];
+	qcom,mdss-dsi-t-clk-post = <0x0c>;
+	qcom,mdss-dsi-t-clk-pre = <0x27>;
 };
 
 &dsi_dual_sharp_1080_120hz_cmd {
-	qcom,mdss-dsi-panel-timings = [00 24 09 09 26 24 09 09 06 03 04];
+	qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 09 06 03 04 00];
 	qcom,mdss-dsi-t-clk-post = <0x0f>;
 	qcom,mdss-dsi-t-clk-pre = <0x36>;
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
new file mode 100644
index 0000000..168f2a9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
@@ -0,0 +1,67 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94a00 {
+		compatible = "qcom,mdss_dsi_pll_10nm";
+		label = "MDSS DSI 0 PLL";
+		cell-index = <0>;
+		#clock-cells = <1>;
+		reg = <0xae94a00 0x1e0>,
+		      <0xae94400 0x800>,
+		      <0xaf03000 0x8>;
+		reg-names = "pll_base", "phy_base", "gdsc_base";
+		clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+		gdsc-supply = <&mdss_core_gdsc>;
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+	};
+
+	mdss_dsi1_pll: qcom,mdss_dsi_pll@ae96a00 {
+		compatible = "qcom,mdss_dsi_pll_10nm";
+		label = "MDSS DSI 1 PLL";
+		cell-index = <1>;
+		#clock-cells = <1>;
+		reg = <0xae96a00 0x1e0>,
+		      <0xae96400 0x800>,
+		      <0xaf03000 0x8>;
+		reg-names = "pll_base", "phy_base", "gdsc_base";
+		clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>;
+		clock-names = "iface_clk";
+		clock-rate = <0>;
+		gdsc-supply = <&mdss_core_gdsc>;
+		qcom,platform-supply-entries {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			qcom,platform-supply-entry@0 {
+				reg = <0>;
+				qcom,supply-name = "gdsc";
+				qcom,supply-min-voltage = <0>;
+				qcom,supply-max-voltage = <0>;
+				qcom,supply-enable-load = <0>;
+				qcom,supply-disable-load = <0>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 522ad95..7812a48 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -37,8 +37,8 @@
 		interrupts = <0 83 0>;
 		interrupt-controller;
 		#interrupt-cells = <1>;
-		iommus = <&apps_smmu 0x880>, <&apps_smmu 0x888>,
-			<&apps_smmu 0xc80>, <&apps_smmu 0xc88>;
+		iommus = <&apps_smmu 0x880 0x0>, <&apps_smmu 0x888 0x0>,
+			<&apps_smmu 0xc80 0x0>, <&apps_smmu 0xc88 0x0>;
 
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -97,8 +97,6 @@
 					1 5 9 13>;
 		qcom,sde-sspp-excl-rect = <1 1 1 1
 						1 1 1 1>;
-		qcom,sde-sspp-smart-dma-priority = <5 6 7 8 1 2 3 4>;
-		qcom,sde-smart-dma-rev = "smart_dma_v2";
 
 		qcom,sde-mixer-pair-mask = <2 1 6 0 0 3>;
 
@@ -118,6 +116,9 @@
 		qcom,sde-wb-linewidth = <4096>;
 		qcom,sde-mixer-blendstages = <0xb>;
 		qcom,sde-highest-bank-bit = <0x2>;
+		qcom,sde-ubwc-version = <0x200>;
+		qcom,sde-ubwc-static = <0x100>;
+		qcom,sde-ubwc-swizzle = <1>;
 		qcom,sde-panic-per-pipe;
 		qcom,sde-has-cdp;
 		qcom,sde-has-src-split;
@@ -238,12 +239,10 @@
 			<&clock_gcc GCC_DISP_AHB_CLK>,
 			<&clock_gcc GCC_DISP_AXI_CLK>,
 			<&clock_dispcc DISP_CC_MDSS_AHB_CLK>,
-			<&clock_dispcc DISP_CC_MDSS_ROT_CLK_SRC>,
 			<&clock_dispcc DISP_CC_MDSS_ROT_CLK>,
 			<&clock_dispcc DISP_CC_MDSS_AXI_CLK>;
 		clock-names = "gcc_iface", "gcc_bus",
-			"iface_clk", "rot_core_clk",
-			"rot_clk", "axi_clk";
+			"iface_clk", "rot_clk", "axi_clk";
 
 		interrupt-parent = <&mdss_mdp>;
 		interrupts = <2 0>;
@@ -260,14 +259,14 @@
 
 		smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
 			compatible = "qcom,smmu_sde_rot_unsec";
-			iommus = <&apps_smmu 0x1090>;
+			iommus = <&apps_smmu 0x1090 0x0>;
 			gdsc-mdss-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>;
 		};
 
 		smmu_rot_sec: qcom,smmu_rot_sec_cb {
 			status = "disabled";
 			compatible = "qcom,smmu_sde_rot_sec";
-			iommus = <&apps_smmu 0x1091>;
+			iommus = <&apps_smmu 0x1091 0x0>;
 			gdsc-mdss-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>;
 		};
 	};
@@ -275,7 +274,6 @@
 	mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 {
 		compatible = "qcom,dsi-ctrl-hw-v2.2";
 		label = "dsi-ctrl-0";
-		status = "disabled";
 		cell-index = <0>;
 		reg =   <0xae94000 0x400>,
 			<0xaf08000 0x4>;
@@ -283,34 +281,27 @@
 		interrupt-parent = <&mdss_mdp>;
 		interrupts = <4 0>;
 		vdda-1p2-supply = <&pm8998_l26>;
-		vdda-0p9-supply = <&pm8998_l1>;
 		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>,
 		<&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
 		<&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
 		<&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>,
-		<&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		<&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>,
+		<&clock_dispcc DISP_CC_MDSS_ESC0_CLK>;
 		clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk",
-					"pixel_clk", "pixel_clk_rcg";
+					"pixel_clk", "pixel_clk_rcg",
+					"esc_clk";
 
 		qcom,ctrl-supply-entries {
 			#address-cells = <1>;
 			#size-cells = <0>;
+
 			qcom,ctrl-supply-entry@0 {
 				reg = <0>;
-				qcom,supply-name = "vdda-0p9";
-				qcom,supply-min-voltage = <925000>;
-				qcom,supply-max-voltage = <925000>;
-				qcom,supply-enable-load = <17000>;
-				qcom,supply-disable-load = <32>;
-			};
-
-			qcom,ctrl-supply-entry@1 {
-				reg = <0>;
 				qcom,supply-name = "vdda-1p2";
-				qcom,supply-min-voltage = <1250000>;
-				qcom,supply-max-voltage = <1250000>;
-				qcom,supply-enable-load = <18160>;
-				qcom,supply-disable-load = <1>;
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <21800>;
+				qcom,supply-disable-load = <4>;
 			};
 		};
 	};
@@ -318,7 +309,6 @@
 	mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 {
 		compatible = "qcom,dsi-ctrl-hw-v2.2";
 		label = "dsi-ctrl-1";
-		status = "disabled";
 		cell-index = <1>;
 		reg =   <0xae96000 0x400>,
 			<0xaf08000 0x4>;
@@ -326,47 +316,37 @@
 		interrupt-parent = <&mdss_mdp>;
 		interrupts = <5 0>;
 		vdda-1p2-supply = <&pm8998_l26>;
-		vdda-0p9-supply = <&pm8998_l1>;
-		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>,
-		<&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
-		<&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
-		<&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>,
-		<&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+		clocks = <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK>,
+		<&clock_dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>,
+		<&clock_dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>,
+		<&clock_dispcc DISP_CC_MDSS_PCLK1_CLK>,
+		<&clock_dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>,
+		<&clock_dispcc DISP_CC_MDSS_ESC1_CLK>;
 		clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk",
-				"pixel_clk", "pixel_clk_rcg";
+				"pixel_clk", "pixel_clk_rcg", "esc_clk";
 		qcom,ctrl-supply-entries {
 			#address-cells = <1>;
 			#size-cells = <0>;
 
 			qcom,ctrl-supply-entry@0 {
 				reg = <0>;
-				qcom,supply-name = "vdda-0p9";
-				qcom,supply-min-voltage = <925000>;
-				qcom,supply-max-voltage = <925000>;
-				qcom,supply-enable-load = <17000>;
-				qcom,supply-disable-load = <32>;
-			};
-
-			qcom,ctrl-supply-entry@1 {
-				reg = <0>;
 				qcom,supply-name = "vdda-1p2";
-				qcom,supply-min-voltage = <1250000>;
-				qcom,supply-max-voltage = <1250000>;
-				qcom,supply-enable-load = <18160>;
-				qcom,supply-disable-load = <1>;
+				qcom,supply-min-voltage = <1200000>;
+				qcom,supply-max-voltage = <1200000>;
+				qcom,supply-enable-load = <21800>;
+				qcom,supply-disable-load = <4>;
 			};
 		};
 	};
 
 	mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 {
 		compatible = "qcom,dsi-phy-v3.0";
-		status = "disabled";
 		label = "dsi-phy-0";
 		cell-index = <0>;
 		reg = <0xae94400 0x7c0>;
 		reg-names = "dsi_phy";
 		gdsc-supply = <&mdss_core_gdsc>;
-		vdda-1p2-supply = <&pm8998_l26>;
+		vdda-0p9-supply = <&pm8998_l1>;
 		qcom,platform-strength-ctrl = [55 03
 						55 03
 						55 03
@@ -383,24 +363,23 @@
 			#size-cells = <0>;
 			qcom,phy-supply-entry@0 {
 				reg = <0>;
-				qcom,supply-name = "vdda-1p2";
-				qcom,supply-min-voltage = <1250000>;
-				qcom,supply-max-voltage = <1250000>;
-				qcom,supply-enable-load = <2500>;
-				qcom,supply-disable-load = <1>;
+				qcom,supply-name = "vdda-0p9";
+				qcom,supply-min-voltage = <880000>;
+				qcom,supply-max-voltage = <880000>;
+				qcom,supply-enable-load = <36000>;
+				qcom,supply-disable-load = <32>;
 			};
 		};
 	};
 
 	mdss_dsi_phy1: qcom,mdss_dsi_phy0@ae96400 {
 		compatible = "qcom,dsi-phy-v3.0";
-		status = "disabled";
 		label = "dsi-phy-1";
 		cell-index = <1>;
 		reg = <0xae96400 0x7c0>;
 		reg-names = "dsi_phy";
 		gdsc-supply = <&mdss_core_gdsc>;
-		vdda-1p2-supply = <&pm8998_l26>;
+		vdda-0p9-supply = <&pm8998_l1>;
 		qcom,platform-strength-ctrl = [55 03
 						55 03
 						55 03
@@ -417,11 +396,11 @@
 			#size-cells = <0>;
 			qcom,phy-supply-entry@0 {
 				reg = <0>;
-				qcom,supply-name = "vdda-1p2";
-				qcom,supply-min-voltage = <1250000>;
-				qcom,supply-max-voltage = <1250000>;
-				qcom,supply-enable-load = <2500>;
-				qcom,supply-disable-load = <1>;
+				qcom,supply-name = "vdda-0p9";
+				qcom,supply-min-voltage = <880000>;
+				qcom,supply-max-voltage = <880000>;
+				qcom,supply-enable-load = <36000>;
+				qcom,supply-disable-load = <32>;
 			};
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index c80343a..aac63ee 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -303,6 +303,13 @@
 		qcom,reset-ep-after-lpm-resume;
 	};
 
+	usb_audio_qmi_dev {
+		compatible = "qcom,usb-audio-qmi-dev";
+		iommus = <&apps_smmu 0x182c>;
+		qcom,usb-audio-stream-id = <0xc>;
+		qcom,usb-audio-intr-num = <2>;
+	};
+
 	usb_nop_phy: usb_nop_phy {
 		compatible = "usb-nop-xceiv";
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 4fdf383..efd8c32 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -16,3 +16,7 @@
 	model = "Qualcomm Technologies, Inc. SDM845 V2";
 	qcom,msm-id = <321 0x20000>;
 };
+
+&spmi_debug_bus {
+	status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index b9dc816..6f4b4ca 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -97,9 +97,9 @@
 			compatible = "qcom,msm-vidc,context-bank";
 			label = "venus_ns";
 			iommus =
-				<&apps_smmu 0x10a0>,
-				<&apps_smmu 0x10a8>,
-				<&apps_smmu 0x10b0>;
+				<&apps_smmu 0x10a0 0x0>,
+				<&apps_smmu 0x10a8 0x0>,
+				<&apps_smmu 0x10b0 0x0>;
 			buffer-types = <0xfff>;
 			virtual-addr-pool = <0x70800000 0x6f800000>;
 		};
@@ -108,10 +108,10 @@
 			compatible = "qcom,msm-vidc,context-bank";
 			label = "venus_sec_bitstream";
 			iommus =
-				<&apps_smmu 0x10a1>,
-				<&apps_smmu 0x10a9>,
-				<&apps_smmu 0x10a5>,
-				<&apps_smmu 0x10ad>;
+				<&apps_smmu 0x10a1 0x0>,
+				<&apps_smmu 0x10a9 0x0>,
+				<&apps_smmu 0x10a5 0x0>,
+				<&apps_smmu 0x10ad 0x0>;
 			buffer-types = <0x241>;
 			virtual-addr-pool = <0x4b000000 0x25800000>;
 			qcom,secure-context-bank;
@@ -121,8 +121,8 @@
 			compatible = "qcom,msm-vidc,context-bank";
 			label = "venus_sec_pixel";
 			iommus =
-				<&apps_smmu 0x10a3>,
-				<&apps_smmu 0x10ab>;
+				<&apps_smmu 0x10a3 0x0>,
+				<&apps_smmu 0x10ab 0x0>;
 			buffer-types = <0x106>;
 			virtual-addr-pool = <0x25800000 0x25800000>;
 			qcom,secure-context-bank;
@@ -132,9 +132,9 @@
 			compatible = "qcom,msm-vidc,context-bank";
 			label = "venus_sec_non_pixel";
 			iommus =
-				<&apps_smmu 0x10a4>,
-				<&apps_smmu 0x10ac>,
-				<&apps_smmu 0x10b4>;
+				<&apps_smmu 0x10a4 0x0>,
+				<&apps_smmu 0x10ac 0x0>,
+				<&apps_smmu 0x10b4 0x0>;
 			buffer-types = <0x480>;
 			virtual-addr-pool = <0x1000000 0x24800000>;
 			qcom,secure-context-bank;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 2c48371..5660841 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -430,6 +430,7 @@
 };
 
 #include "msm-gdsc-sdm845.dtsi"
+#include "sdm845-sde-pll.dtsi"
 #include "sdm845-sde.dtsi"
 #include "sdm845-sde-display.dtsi"
 #include "sdm845-qupv3.dtsi"
@@ -552,6 +553,7 @@
 		qcom,fuse-disable-bit = <12>;
 		#address-cells = <2>;
 		#size-cells = <0>;
+		status = "disabled";
 
 		qcom,pm8998-debug@0 {
 			compatible = "qcom,spmi-pmic";
@@ -1019,6 +1021,29 @@
 		mbox-names = "qdss_clk";
 	};
 
+	ufs_ice: ufsice@1d90000 {
+		compatible = "qcom,ice";
+		reg = <0x1d90000 0x8000>;
+		qcom,enable-ice-clk;
+		clock-names = "ufs_core_clk", "bus_clk",
+				"iface_clk", "ice_core_clk";
+		clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>,
+			 <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>,
+			 <&clock_gcc GCC_UFS_PHY_AHB_CLK>,
+			 <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>;
+		qcom,op-freq-hz = <0>, <0>, <0>, <300000000>;
+		vdd-hba-supply = <&ufs_phy_gdsc>;
+		qcom,msm-bus,name = "ufs_ice_noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<1 650 0 0>,    /* No vote */
+				<1 650 1000 0>; /* Max. bandwidth */
+		qcom,bus-vector-names = "MIN",
+					"MAX";
+		qcom,instance-type = "ufs";
+	};
+
 	ufsphy_mem: ufsphy_mem@1d87000 {
 		reg = <0x1d87000 0xda8>; /* PHY regs */
 		reg-names = "phy_mem";
@@ -1042,6 +1067,7 @@
 		interrupts = <0 265 0>;
 		phys = <&ufsphy_mem>;
 		phy-names = "ufsphy";
+		ufs-qcom-crypto = <&ufs_ice>;
 
 		lanes-per-direction = <2>;
 		dev-ref-clk-freq = <0>; /* 19.2 MHz */
@@ -1288,9 +1314,12 @@
 		      <0x1f65000 0x008>,
 		      <0x1f64000 0x008>,
 		      <0x4180000 0x020>,
-		      <0xc2b0000 0x004>;
+		      <0xc2b0000 0x004>,
+		      <0xb2e0100 0x004>,
+		      <0x4180044 0x004>;
 		reg-names = "qdsp6_base", "halt_q6", "halt_modem",
-			    "halt_nc", "rmb_base", "restart_reg";
+			    "halt_nc", "rmb_base", "restart_reg",
+			    "pdc_sync", "alt_reset";
 
 		clocks = <&clock_rpmh RPMH_CXO_CLK>,
 			 <&clock_gcc GCC_MSS_CFG_AHB_CLK>,
@@ -1416,6 +1445,16 @@
 		qcom,ea-pc = <0x270>;
 	};
 
+	slim_qca: slim@17240000 {
+		cell-index = <3>;
+		compatible = "qcom,slim-ngd";
+		reg = <0x17240000 0x2c000>,
+			<0x17204000 0x20000>;
+		reg-names = "slimbus_physical", "slimbus_bam_physical";
+		interrupts = <0 291 0>, <0 292 0>;
+		interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+	};
+
 	eud: qcom,msm-eud@88e0000 {
 		compatible = "qcom,msm-eud";
 		interrupt-names = "eud_irq";
@@ -1503,61 +1542,98 @@
 		qcom,rtb-size = <0x100000>;
 	};
 
+	qcom,mpm2-sleep-counter@0x0c221000 {
+		compatible = "qcom,mpm2-sleep-counter";
+		reg = <0x0c221000 0x1000>;
+		clock-frequency = <32768>;
+	};
+
 	qcom,msm-cdsp-loader {
 		compatible = "qcom,cdsp-loader";
 		qcom,proc-img-to-load = "cdsp";
 	};
 
+	qcom,msm-adsprpc-mem {
+		compatible = "qcom,msm-adsprpc-mem-region";
+		memory-region = <&adsp_mem>;
+	};
+
 	qcom,msm_fastrpc {
 		compatible = "qcom,msm-fastrpc-compute";
 
 		qcom,msm_fastrpc_compute_cb1 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
 			label = "cdsprpc-smd";
-			iommus = <&apps_smmu 0x1401>,
-				 <&apps_smmu 0x1421>;
+			iommus = <&apps_smmu 0x1401 0x0>,
+				 <&apps_smmu 0x1421 0x0>;
 		};
 		qcom,msm_fastrpc_compute_cb2 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
 			label = "cdsprpc-smd";
-			iommus = <&apps_smmu 0x1402>,
-				 <&apps_smmu 0x1422>;
+			iommus = <&apps_smmu 0x1402 0x0>,
+				 <&apps_smmu 0x1422 0x0>;
 		};
 		qcom,msm_fastrpc_compute_cb3 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
 			label = "cdsprpc-smd";
-			iommus = <&apps_smmu 0x1403>,
-				 <&apps_smmu 0x1423>;
+			iommus = <&apps_smmu 0x1403 0x0>,
+				 <&apps_smmu 0x1423 0x0>;
 		};
 		qcom,msm_fastrpc_compute_cb4 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
 			label = "cdsprpc-smd";
-			iommus = <&apps_smmu 0x1404>,
-				 <&apps_smmu 0x1424>;
+			iommus = <&apps_smmu 0x1404 0x0>,
+				 <&apps_smmu 0x1424 0x0>;
 		};
 		qcom,msm_fastrpc_compute_cb5 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
 			label = "cdsprpc-smd";
-			iommus = <&apps_smmu 0x1405>,
-				 <&apps_smmu 0x1425>;
+			iommus = <&apps_smmu 0x1405 0x0>,
+				 <&apps_smmu 0x1425 0x0>;
 		};
 		qcom,msm_fastrpc_compute_cb6 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
 			label = "cdsprpc-smd";
-			iommus = <&apps_smmu 0x1406>,
-				 <&apps_smmu 0x1426>;
+			iommus = <&apps_smmu 0x1406 0x0>,
+				 <&apps_smmu 0x1426 0x0>;
 		};
 		qcom,msm_fastrpc_compute_cb7 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
 			label = "cdsprpc-smd";
-			iommus = <&apps_smmu 0x1407>,
-				 <&apps_smmu 0x1427>;
+			iommus = <&apps_smmu 0x1407 0x0>,
+				 <&apps_smmu 0x1427 0x0>;
 		};
 		qcom,msm_fastrpc_compute_cb8 {
 			compatible = "qcom,msm-fastrpc-compute-cb";
 			label = "cdsprpc-smd";
-			iommus = <&apps_smmu 0x1408>,
-				 <&apps_smmu 0x1428>;
+			iommus = <&apps_smmu 0x1408 0x0>,
+				 <&apps_smmu 0x1428 0x0>;
+		};
+		qcom,msm_fastrpc_compute_cb9 {
+			compatible = "qcom,msm-fastrpc-compute-cb";
+			label = "cdsprpc-smd";
+			qcom,secure-context-bank;
+			iommus = <&apps_smmu 0x1409 0x0>,
+				 <&apps_smmu 0x1419 0x0>,
+				 <&apps_smmu 0x1429 0x0>;
+		};
+		qcom,msm_fastrpc_compute_cb10 {
+			compatible = "qcom,msm-fastrpc-compute-cb";
+			label = "cdsprpc-smd";
+			qcom,secure-context-bank;
+			iommus = <&apps_smmu 0x140A 0x0>,
+				 <&apps_smmu 0x141A 0x0>,
+				 <&apps_smmu 0x142A 0x0>;
+		};
+		qcom,msm_fastrpc_compute_cb11 {
+			compatible = "qcom,msm-fastrpc-compute-cb";
+			label = "adsprpc-smd";
+			iommus = <&apps_smmu 0x1823 0x0>;
+		};
+		qcom,msm_fastrpc_compute_cb12 {
+			compatible = "qcom,msm-fastrpc-compute-cb";
+			label = "adsprpc-smd";
+			iommus = <&apps_smmu 0x1824 0x0>;
 		};
 	};
 
@@ -1578,6 +1654,11 @@
 			reg = <0x65c 4>;
 		};
 
+		boot_stats@6b0 {
+			compatible = "qcom,msm-imem-boot_stats";
+			reg = <0x6b0 32>;
+		};
+
 		pil@94c {
 			compatible = "qcom,msm-imem-pil";
 			reg = <0x94c 200>;
@@ -2094,6 +2175,65 @@
 		hyplog-size-offset = <0x414>;
 	};
 
+	qcom_cedev: qcedev@1de0000 {
+		compatible = "qcom,qcedev";
+		reg = <0x1de0000 0x20000>,
+			<0x1dc4000 0x24000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 272 0>;
+		qcom,bam-pipe-pair = <1>;
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		qcom,ce-hw-shared;
+		qcom,bam-ee = <0>;
+		qcom,msm-bus,name = "qcedev-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+				<125 512 0 0>,
+				<125 512 393600 393600>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		clocks = <&clock_gcc GCC_CE1_CLK>,
+			 <&clock_gcc GCC_CE1_CLK>,
+			 <&clock_gcc GCC_CE1_AHB_CLK>,
+			 <&clock_gcc GCC_CE1_AXI_CLK>;
+		qcom,ce-opp-freq = <171430000>;
+	};
+
+	qcom_crypto: qcrypto@1de0000 {
+		compatible = "qcom,qcrypto";
+		reg = <0x1de0000 0x20000>,
+			 <0x1dc4000 0x24000>;
+		reg-names = "crypto-base","crypto-bam-base";
+		interrupts = <0 272 0>;
+		qcom,bam-pipe-pair = <2>;
+		qcom,ce-hw-instance = <0>;
+		qcom,ce-device = <0>;
+		qcom,bam-ee = <0>;
+		qcom,ce-hw-shared;
+		qcom,clk-mgmt-sus-res;
+		qcom,msm-bus,name = "qcrypto-noc";
+		qcom,msm-bus,num-cases = <2>;
+		qcom,msm-bus,num-paths = <1>;
+		qcom,msm-bus,vectors-KBps =
+			<125 512 0 0>,
+			<125 512 393600 393600>;
+		clock-names = "core_clk_src", "core_clk",
+				"iface_clk", "bus_clk";
+		clocks = <&clock_gcc GCC_CE1_CLK>,
+			 <&clock_gcc GCC_CE1_CLK>,
+			 <&clock_gcc GCC_CE1_AHB_CLK>,
+			 <&clock_gcc GCC_CE1_AXI_CLK>;
+		qcom,ce-opp-freq = <171430000>;
+		qcom,use-sw-aes-cbc-ecb-ctr-algo;
+		qcom,use-sw-aes-xts-algo;
+		qcom,use-sw-aes-ccm-algo;
+		qcom,use-sw-ahash-algo;
+		qcom,use-sw-aead-algo;
+		qcom,use-sw-hmac-algo;
+	};
+
 	qcom,msm_gsi {
 		compatible = "qcom,msm_gsi";
 	};
@@ -2247,18 +2387,18 @@
 
 		ipa_smmu_ap: ipa_smmu_ap {
 			compatible = "qcom,ipa-smmu-ap-cb";
-			iommus = <&apps_smmu 0x720>;
+			iommus = <&apps_smmu 0x720 0x0>;
 			qcom,iova-mapping = <0x20000000 0x40000000>;
 		};
 
 		ipa_smmu_wlan: ipa_smmu_wlan {
 			compatible = "qcom,ipa-smmu-wlan-cb";
-			iommus = <&apps_smmu 0x721>;
+			iommus = <&apps_smmu 0x721 0x0>;
 		};
 
 		ipa_smmu_uc: ipa_smmu_uc {
 			compatible = "qcom,ipa-smmu-uc-cb";
-			iommus = <&apps_smmu 0x722>;
+			iommus = <&apps_smmu 0x722 0x0>;
 			qcom,iova-mapping = <0x40000000 0x20000000>;
 		};
 	};
@@ -2302,7 +2442,7 @@
 
 	cmd_db: qcom,cmd-db@861e0000 {
 		compatible = "qcom,cmd-db";
-		reg = <0x861e0000 0x4000>;
+		reg = <0xc3f000c 8>;
 	};
 
 	dcc: dcc_v2@10a2000 {
@@ -2325,8 +2465,8 @@
 		      <0xa0000000 0x10000000>,
 		      <0xb0000000 0x10000>;
 		reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa";
-		iommus = <&apps_smmu 0x0040>,
-			 <&apps_smmu 0x0041>;
+		iommus = <&apps_smmu 0x0040 0x0>,
+			 <&apps_smmu 0x0041 0x0>;
 		interrupts = <0 414 0 /* CE0 */ >,
 			     <0 415 0 /* CE1 */ >,
 			     <0 416 0 /* CE2 */ >,
@@ -3502,3 +3642,44 @@
 #include "sdm845-audio.dtsi"
 #include "sdm845-gpu.dtsi"
 #include "sdm845-usb.dtsi"
+
+&pm8998_temp_alarm {
+	cooling-maps {
+		trip0_cpu0 {
+			trip = <&pm8998_trip0>;
+			cooling-device = <&CPU0 21 21>;
+		};
+		trip0_cpu4 {
+			trip = <&pm8998_trip0>;
+			cooling-device = <&CPU4 21 21>;
+		};
+		trip1_cpu1 {
+			trip = <&pm8998_trip1>;
+			cooling-device = <&CPU1 22 22>;
+		};
+		trip1_cpu2 {
+			trip = <&pm8998_trip1>;
+			cooling-device = <&CPU2 22 22>;
+		};
+		trip1_cpu3 {
+			trip = <&pm8998_trip1>;
+			cooling-device = <&CPU3 22 22>;
+		};
+		trip1_cpu4 {
+			trip = <&pm8998_trip1>;
+			cooling-device = <&CPU4 22 22>;
+		};
+		trip1_cpu5 {
+			trip = <&pm8998_trip1>;
+			cooling-device = <&CPU5 22 22>;
+		};
+		trip1_cpu6 {
+			trip = <&pm8998_trip1>;
+			cooling-device = <&CPU6 22 22>;
+		};
+		trip1_cpu7 {
+			trip = <&pm8998_trip1>;
+			cooling-device = <&CPU7 22 22>;
+		};
+	};
+};
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index a2d659e..7f00787 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -55,6 +55,7 @@
 CONFIG_HZ_100=y
 CONFIG_CMA=y
 CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
@@ -335,6 +336,7 @@
 CONFIG_MSM_VIDC_GOVERNORS=y
 CONFIG_MSM_SDE_ROTATOR=y
 CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_QCOM_KGSL=y
 CONFIG_DRM=y
 CONFIG_DRM_SDE_EVTLOG_DEBUG=y
 CONFIG_DRM_SDE_RSC=y
@@ -391,6 +393,7 @@
 CONFIG_USB_CONFIGFS_F_GSI=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
+CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_TEST=y
@@ -440,8 +443,12 @@
 CONFIG_QCOM_LAZY_MAPPING=y
 CONFIG_IOMMU_DEBUG=y
 CONFIG_IOMMU_TESTS=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
 CONFIG_QCOM_LLCC=y
 CONFIG_QCOM_SDM845_LLCC=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_MSM_BOOT_STATS=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
 CONFIG_QCOM_MEMORY_DUMP_V2=y
@@ -469,10 +476,12 @@
 CONFIG_MSM_PIL_MSS_QDSP6V5=y
 CONFIG_ICNSS=y
 CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_PM=y
 CONFIG_APSS_CORE_EA=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_QCOM_BIMC_BWMON=y
 CONFIG_ARM_MEMLAT_MON=y
 CONFIG_QCOMCCI_HWMON=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 54f9d41..4fdbffa 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -61,6 +61,7 @@
 CONFIG_CLEANCACHE=y
 CONFIG_CMA=y
 CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
 CONFIG_SECCOMP=y
 CONFIG_ARMV8_DEPRECATED=y
 CONFIG_SWP_EMULATION=y
@@ -337,6 +338,7 @@
 CONFIG_VIDEO_ADV_DEBUG=y
 CONFIG_VIDEO_FIXED_MINOR_RANGES=y
 CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SPECTRA_CAMERA=y
 CONFIG_MSM_VIDC_V4L2=y
 CONFIG_MSM_VIDC_VMEM=y
 CONFIG_MSM_VIDC_GOVERNORS=y
@@ -398,6 +400,7 @@
 CONFIG_USB_CONFIGFS_F_GSI=y
 CONFIG_USB_CONFIGFS_F_QDSS=y
 CONFIG_MMC=y
+CONFIG_MMC_CLKGATE=y
 CONFIG_MMC_BLOCK_MINORS=32
 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
 CONFIG_MMC_TEST=y
@@ -456,8 +459,12 @@
 CONFIG_IOMMU_DEBUG=y
 CONFIG_IOMMU_TESTS=y
 CONFIG_QCOM_CPUSS_DUMP=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
 CONFIG_QCOM_LLCC=y
 CONFIG_QCOM_SDM845_LLCC=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_MSM_BOOT_STATS=y
 CONFIG_MSM_CORE_HANG_DETECT=y
 CONFIG_MSM_GLADIATOR_HANG_DETECT=y
 CONFIG_QCOM_EUD=y
@@ -488,11 +495,13 @@
 CONFIG_ICNSS=y
 CONFIG_ICNSS_DEBUG=y
 CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_ADSP_LOADER=y
 CONFIG_MSM_AVTIMER=y
 CONFIG_MSM_EVENT_TIMER=y
 CONFIG_MSM_PM=y
 CONFIG_APSS_CORE_EA=y
 CONFIG_QCOM_DCC_V2=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
 CONFIG_QCOM_BIMC_BWMON=y
 CONFIG_ARM_MEMLAT_MON=y
 CONFIG_QCOMCCI_HWMON=y
@@ -591,6 +600,7 @@
 CONFIG_CORESIGHT_TPDA=y
 CONFIG_CORESIGHT_TPDM=y
 CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_HWEVENT=y
 CONFIG_CORESIGHT_DUMMY=y
 CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
 CONFIG_SECURITY=y
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 296e139..0a34644 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -335,7 +335,8 @@
 
 	if (is_el0_instruction_abort(esr)) {
 		vm_flags = VM_EXEC;
-	} else if ((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) {
+	} else if (((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) ||
+			((esr & ESR_ELx_CM) && !(mm_flags & FAULT_FLAG_USER))) {
 		vm_flags = VM_WRITE;
 		mm_flags |= FAULT_FLAG_WRITE;
 	}
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 6432d4b..767ef6d 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -689,7 +689,7 @@
 
 	addi	r8,r1,INT_FRAME_SIZE	/* Get the kprobed function entry */
 
-	lwz	r3,GPR1(r1)
+	ld	r3,GPR1(r1)
 	subi	r3,r3,INT_FRAME_SIZE	/* dst: Allocate a trampoline exception frame */
 	mr	r4,r1			/* src:  current exception frame */
 	mr	r1,r3			/* Reroute the trampoline frame to r1 */
@@ -703,8 +703,8 @@
 	addi	r6,r6,8
 	bdnz	2b
 
-	/* Do real store operation to complete stwu */
-	lwz	r5,GPR1(r1)
+	/* Do real store operation to complete stdu */
+	ld	r5,GPR1(r1)
 	std	r8,0(r5)
 
 	/* Clear _TIF_EMULATE_STACK_STORE flag */
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 0362cd5..0cea702 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -1029,6 +1029,8 @@
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 			      pte_t *ptep, pte_t entry)
 {
+	if (pte_present(entry))
+		pte_val(entry) &= ~_PAGE_UNUSED;
 	if (mm_has_pgste(mm))
 		ptep_set_pte_at(mm, addr, ptep, entry);
 	else
diff --git a/arch/x86/kernel/cpu/mcheck/mce-genpool.c b/arch/x86/kernel/cpu/mcheck/mce-genpool.c
index 93d824e..040af19 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-genpool.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-genpool.c
@@ -85,7 +85,7 @@
 	head = llist_reverse_order(head);
 	llist_for_each_entry_safe(node, tmp, head, llnode) {
 		mce = &node->mce;
-		atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
+		blocking_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
 		gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node));
 	}
 }
diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h
index cd74a3f..de20902 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-internal.h
+++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h
@@ -13,7 +13,7 @@
 	MCE_PANIC_SEVERITY,
 };
 
-extern struct atomic_notifier_head x86_mce_decoder_chain;
+extern struct blocking_notifier_head x86_mce_decoder_chain;
 
 #define ATTR_LEN		16
 #define INITIAL_CHECK_INTERVAL	5 * 60 /* 5 minutes */
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index a7fdf45..22cda29 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -120,7 +120,7 @@
  * CPU/chipset specific EDAC code can register a notifier call here to print
  * MCE errors in a human-readable form.
  */
-ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
+BLOCKING_NOTIFIER_HEAD(x86_mce_decoder_chain);
 
 /* Do initial initialization of a struct mce */
 void mce_setup(struct mce *m)
@@ -213,13 +213,13 @@
 	if (nb != &mce_srao_nb && nb->priority == INT_MAX)
 		nb->priority -= 1;
 
-	atomic_notifier_chain_register(&x86_mce_decoder_chain, nb);
+	blocking_notifier_chain_register(&x86_mce_decoder_chain, nb);
 }
 EXPORT_SYMBOL_GPL(mce_register_decode_chain);
 
 void mce_unregister_decode_chain(struct notifier_block *nb)
 {
-	atomic_notifier_chain_unregister(&x86_mce_decoder_chain, nb);
+	blocking_notifier_chain_unregister(&x86_mce_decoder_chain, nb);
 }
 EXPORT_SYMBOL_GPL(mce_unregister_decode_chain);
 
@@ -272,8 +272,6 @@
 
 static void print_mce(struct mce *m)
 {
-	int ret = 0;
-
 	pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
 	       m->extcpu, m->mcgstatus, m->bank, m->status);
 
@@ -309,14 +307,6 @@
 		m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
 		cpu_data(m->extcpu).microcode);
 
-	/*
-	 * Print out human-readable details about the MCE error,
-	 * (if the CPU has an implementation for that)
-	 */
-	ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
-	if (ret == NOTIFY_STOP)
-		return;
-
 	pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n");
 }
 
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 9b54034..3dfca7b 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -59,7 +59,7 @@
 	"load_store",
 	"insn_fetch",
 	"combined_unit",
-	"",
+	"decode_unit",
 	"northbridge",
 	"execution_unit",
 };
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index fcd4ce6..1c2b846 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -200,6 +200,7 @@
 		return -EINVAL;
 
 	/* The state of the list is 'on' IFF all resources are 'on'. */
+	cur_state = 0;
 	list_for_each_entry(entry, list, node) {
 		struct acpi_power_resource *resource = entry->resource;
 		acpi_handle handle = resource->device.handle;
diff --git a/drivers/base/dma-removed.c b/drivers/base/dma-removed.c
index 4281801..09e77d5 100644
--- a/drivers/base/dma-removed.c
+++ b/drivers/base/dma-removed.c
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *  Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
  *  Copyright (C) 2000-2004 Russell King
  *
  * This program is free software; you can redistribute it and/or modify
@@ -294,6 +294,7 @@
 	bool no_kernel_mapping = attrs & DMA_ATTR_NO_KERNEL_MAPPING;
 	struct removed_region *dma_mem = dev->removed_mem;
 
+	size = PAGE_ALIGN(size);
 	if (!no_kernel_mapping)
 		iounmap(cpu_addr);
 	mutex_lock(&dma_mem->lock);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index a95e1e5..f18ae62 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -229,20 +229,22 @@
 static int fw_lookup_and_allocate_buf(const char *fw_name,
 				      struct firmware_cache *fwc,
 				      struct firmware_buf **buf, void *dbuf,
-				      size_t size)
+				      size_t size, unsigned int opt_flags)
 {
 	struct firmware_buf *tmp;
 
 	spin_lock(&fwc->lock);
-	tmp = __fw_lookup_buf(fw_name);
-	if (tmp) {
-		kref_get(&tmp->ref);
-		spin_unlock(&fwc->lock);
-		*buf = tmp;
-		return 1;
+	if (!(opt_flags & FW_OPT_NOCACHE)) {
+		tmp = __fw_lookup_buf(fw_name);
+		if (tmp) {
+			kref_get(&tmp->ref);
+			spin_unlock(&fwc->lock);
+			*buf = tmp;
+			return 1;
+		}
 	}
 	tmp = __allocate_fw_buf(fw_name, fwc, dbuf, size);
-	if (tmp)
+	if (tmp && !(opt_flags & FW_OPT_NOCACHE))
 		list_add(&tmp->list, &fwc->head);
 	spin_unlock(&fwc->lock);
 
@@ -1051,7 +1053,8 @@
  */
 static int
 _request_firmware_prepare(struct firmware **firmware_p, const char *name,
-			  struct device *device, void *dbuf, size_t size)
+			  struct device *device, void *dbuf, size_t size,
+			  unsigned int opt_flags)
 {
 	struct firmware *firmware;
 	struct firmware_buf *buf;
@@ -1069,7 +1072,8 @@
 		return 0; /* assigned */
 	}
 
-	ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size);
+	ret = fw_lookup_and_allocate_buf(name, &fw_cache, &buf, dbuf, size,
+					opt_flags);
 
 	/*
 	 * bind with 'buf' now to avoid warning in failure path
@@ -1147,7 +1151,8 @@
 		goto out;
 	}
 
-	ret = _request_firmware_prepare(&fw, name, device, buf, size);
+	ret = _request_firmware_prepare(&fw, name, device, buf, size,
+					opt_flags);
 	if (ret <= 0) /* error or already assigned */
 		goto out;
 
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index b248b1b..1b545d6 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1709,8 +1709,14 @@
 		}
 	}
 
+	/*
+	 * The Fabia PLLs only have 16 bits to program the fractional divider.
+	 * Hence the programmed rate might be slightly different than the
+	 * requested one.
+	 */
 	if ((core->flags & CLK_SET_RATE_PARENT) && parent &&
-	    best_parent_rate != parent->rate)
+		(DIV_ROUND_CLOSEST(best_parent_rate, 1000) !=
+			DIV_ROUND_CLOSEST(parent->rate, 1000)))
 		top = clk_calc_new_rates(parent, best_parent_rate);
 
 out:
@@ -2345,6 +2351,56 @@
 	NULL,
 };
 
+static void clk_state_subtree(struct clk_core *c)
+{
+	int vdd_level = 0;
+	struct clk_core *child;
+
+	if (!c)
+		return;
+
+	if (c->vdd_class) {
+		vdd_level = clk_find_vdd_level(c, c->rate);
+		if (vdd_level < 0)
+			vdd_level = 0;
+	}
+
+	trace_clk_state(c->name, c->prepare_count, c->enable_count,
+						c->rate, vdd_level);
+
+	hlist_for_each_entry(child, &c->children, child_node)
+		clk_state_subtree(child);
+}
+
+static int clk_state_show(struct seq_file *s, void *data)
+{
+	struct clk_core *c;
+	struct hlist_head **lists = (struct hlist_head **)s->private;
+
+	clk_prepare_lock();
+
+	for (; *lists; lists++)
+		hlist_for_each_entry(c, *lists, child_node)
+			clk_state_subtree(c);
+
+	clk_prepare_unlock();
+
+	return 0;
+}
+
+
+static int clk_state_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, clk_state_show, inode->i_private);
+}
+
+static const struct file_operations clk_state_fops = {
+	.open		= clk_state_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
 static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
 				 int level)
 {
@@ -2980,6 +3036,11 @@
 	if (!d)
 		return -ENOMEM;
 
+	d = debugfs_create_file("trace_clocks", 0444, rootdir, &all_lists,
+				&clk_state_fops);
+	if (!d)
+		return -ENOMEM;
+
 	mutex_lock(&clk_debug_lock);
 	hlist_for_each_entry(core, &clk_debug_list, debug_node)
 		clk_debug_create_one(core, rootdir);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 46a3d27..d47b66e 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -1,6 +1,7 @@
 config QCOM_GDSC
 	bool
 	select PM_GENERIC_DOMAINS if PM
+	depends on REGULATOR
 
 config COMMON_CLK_QCOM
 	tristate "Support for Qualcomm's clock controllers"
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
index 84e9698..6296c40 100644
--- a/drivers/clk/qcom/camcc-sdm845.c
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -1115,19 +1115,6 @@
 	},
 };
 
-static struct clk_branch cam_cc_debug_clk = {
-	.halt_reg = 0xc008,
-	.halt_check = BRANCH_HALT,
-	.clkr = {
-		.enable_reg = 0xc008,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "cam_cc_debug_clk",
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch cam_cc_fd_core_clk = {
 	.halt_reg = 0xb0c8,
 	.halt_check = BRANCH_HALT,
@@ -1764,7 +1751,6 @@
 	[CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr,
 	[CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr,
 	[CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr,
-	[CAM_CC_DEBUG_CLK] = &cam_cc_debug_clk.clkr,
 	[CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
 	[CAM_CC_FD_CORE_CLK] = &cam_cc_fd_core_clk.clkr,
 	[CAM_CC_FD_CORE_CLK_SRC] = &cam_cc_fd_core_clk_src.clkr,
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index 6ff621d..d15d1bb 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -307,6 +307,15 @@
 	u64 quotient;
 	int alpha_bw = ALPHA_BITWIDTH;
 
+	/*
+	 * The PLLs parent rate is zero probably since the parent hasn't
+	 * registered yet. Return early with the requested rate.
+	 */
+	if (!prate) {
+		pr_debug("PLLs parent rate hasn't been initialized.\n");
+		return rate;
+	}
+
 	quotient = rate;
 	remainder = do_div(quotient, prate);
 	*l = quotient;
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index 20ce78b..3b56fa1 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -478,19 +478,6 @@
 	},
 };
 
-static struct clk_branch disp_cc_debug_clk = {
-	.halt_reg = 0x600c,
-	.halt_check = BRANCH_HALT,
-	.clkr = {
-		.enable_reg = 0x600c,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "disp_cc_debug_clk",
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch disp_cc_mdss_ahb_clk = {
 	.halt_reg = 0x4004,
 	.halt_check = BRANCH_HALT,
@@ -949,7 +936,6 @@
 };
 
 static struct clk_regmap *disp_cc_sdm845_clocks[] = {
-	[DISP_CC_DEBUG_CLK] = &disp_cc_debug_clk.clkr,
 	[DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr,
 	[DISP_CC_MDSS_AXI_CLK] = &disp_cc_mdss_axi_clk.clkr,
 	[DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr,
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 5fcb1f5..678dd10 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -1468,19 +1468,6 @@
 	},
 };
 
-static struct clk_branch gcc_cxo_tx1_clkref_clk = {
-	.halt_reg = 0x8c020,
-	.halt_check = BRANCH_HALT,
-	.clkr = {
-		.enable_reg = 0x8c020,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_cxo_tx1_clkref_clk",
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch gcc_ddrss_gpu_axi_clk = {
 	.halt_reg = 0x44038,
 	.halt_check = BRANCH_VOTED,
@@ -2433,32 +2420,6 @@
 	},
 };
 
-static struct clk_branch gcc_rx1_usb2_clkref_clk = {
-	.halt_reg = 0x8c014,
-	.halt_check = BRANCH_HALT,
-	.clkr = {
-		.enable_reg = 0x8c014,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_rx1_usb2_clkref_clk",
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
-static struct clk_branch gcc_rx2_qlink_clkref_clk = {
-	.halt_reg = 0x8c018,
-	.halt_check = BRANCH_HALT,
-	.clkr = {
-		.enable_reg = 0x8c018,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gcc_rx2_qlink_clkref_clk",
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch gcc_sdcc2_ahb_clk = {
 	.halt_reg = 0x14008,
 	.halt_check = BRANCH_HALT,
@@ -3151,7 +3112,6 @@
 	[GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr,
 	[GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr,
 	[GCC_CPUSS_RBCPR_CLK_SRC] = &gcc_cpuss_rbcpr_clk_src.clkr,
-	[GCC_CXO_TX1_CLKREF_CLK] = &gcc_cxo_tx1_clkref_clk.clkr,
 	[GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr,
 	[GCC_DISP_AHB_CLK] = &gcc_disp_ahb_clk.clkr,
 	[GCC_DISP_AXI_CLK] = &gcc_disp_axi_clk.clkr,
@@ -3238,8 +3198,6 @@
 	[GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr,
 	[GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr,
 	[GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr,
-	[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
-	[GCC_RX2_QLINK_CLKREF_CLK] = &gcc_rx2_qlink_clkref_clk.clkr,
 	[GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
 	[GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
 	[GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
@@ -3337,6 +3295,8 @@
 	[GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 },
 	[GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 },
 	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+	[GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
+	[GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
 };
 
 static const struct regmap_config gcc_sdm845_regmap_config = {
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index d9a626e..0115bb1 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -413,19 +413,6 @@
 	},
 };
 
-static struct clk_branch gpu_cc_debug_clk = {
-	.halt_reg = 0x1100,
-	.halt_check = BRANCH_HALT,
-	.clkr = {
-		.enable_reg = 0x1100,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "gpu_cc_debug_clk",
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch gpu_cc_gx_cxo_clk = {
 	.halt_reg = 0x1060,
 	.halt_check = BRANCH_HALT,
@@ -544,7 +531,6 @@
 	[GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
 	[GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
 	[GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
-	[GPU_CC_DEBUG_CLK] = &gpu_cc_debug_clk.clkr,
 	[GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
 	[GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr,
 	[GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 3daefbc..2cb9d05 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -23,9 +23,10 @@
 
 #define VCO_DELAY_USEC 1
 
-#define MHZ_375		375000000UL
-#define MHZ_750		750000000UL
-#define MHZ_1500	1500000000UL
+#define MHZ_250		250000000UL
+#define MHZ_500		500000000UL
+#define MHZ_1000	1000000000UL
+#define MHZ_1100	1100000000UL
 #define MHZ_1900	1900000000UL
 #define MHZ_3000	3000000000UL
 
@@ -99,6 +100,7 @@
 	u32 frac_div_start_low;
 	u32 frac_div_start_mid;
 	u32 frac_div_start_high;
+	u32 pll_clock_inverters;
 	u32 ssc_stepsize_low;
 	u32 ssc_stepsize_high;
 	u32 ssc_div_per_low;
@@ -209,20 +211,36 @@
 	u64 dec, dec_multiple;
 	u32 frac;
 	u64 multiplier;
+	u32 i;
 
 	target_freq = rsc->vco_current_rate;
 	pr_debug("target_freq = %llu\n", target_freq);
 
 	if (config->div_override) {
 		computed_output_div = config->output_div;
+
+		/*
+		 * Computed_output_div = 2 ^ div_log
+		 * To get div_log from output div just get the index of the
+		 * 1 bit in the value.
+		 * div_log ranges from 0-3. so check the 4 lsbs
+		 */
+
+		for (i = 0; i < 4; i++) {
+			if (computed_output_div & (1 << i)) {
+				div_log = i;
+				break;
+			}
+		}
+
 	} else {
-		if (target_freq < MHZ_375) {
+		if (target_freq < MHZ_250) {
 			computed_output_div = 8;
 			div_log = 3;
-		} else if (target_freq < MHZ_750) {
+		} else if (target_freq < MHZ_500) {
 			computed_output_div = 4;
 			div_log = 2;
-		} else if (target_freq < MHZ_1500) {
+		} else if (target_freq < MHZ_1000) {
 			computed_output_div = 2;
 			div_log = 1;
 		} else {
@@ -251,6 +269,10 @@
 		regs->pll_prop_gain_rate = 10;
 	else
 		regs->pll_prop_gain_rate = 12;
+	if (pll_freq < MHZ_1100)
+		regs->pll_clock_inverters = 8;
+	else
+		regs->pll_clock_inverters = 0;
 
 	regs->pll_outdiv_rate = div_log;
 	regs->pll_lockdet_rate = config->lock_timer;
@@ -375,7 +397,7 @@
 	MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate);
 	MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06);
 	MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10);
-	MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters);
 
 }
 
@@ -1085,7 +1107,7 @@
 
 static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
 	.ref_clk_rate = 19200000UL,
-	.min_rate = 1500000000UL,
+	.min_rate = 1000000000UL,
 	.max_rate = 3500000000UL,
 	.hw.init = &(struct clk_init_data){
 			.name = "dsi0pll_vco_clk",
@@ -1098,7 +1120,7 @@
 
 static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
 	.ref_clk_rate = 19200000UL,
-	.min_rate = 1500000000UL,
+	.min_rate = 1000000000UL,
 	.max_rate = 3500000000UL,
 	.hw.init = &(struct clk_init_data){
 			.name = "dsi1pll_vco_clk",
@@ -1219,7 +1241,7 @@
 
 static struct clk_regmap_mux dsi0pll_byteclk_mux = {
 	.shift = 0,
-	.width = 0,
+	.width = 1,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi0_phy_pll_out_byteclk",
@@ -1233,7 +1255,7 @@
 
 static struct clk_regmap_mux dsi1pll_byteclk_mux = {
 	.shift = 0,
-	.width = 0,
+	.width = 1,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi1_phy_pll_out_byteclk",
@@ -1247,7 +1269,7 @@
 
 static struct clk_regmap_mux dsi0pll_pclk_src_mux = {
 	.shift = 0,
-	.width = 0,
+	.width = 1,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi0pll_pclk_src_mux",
@@ -1262,7 +1284,7 @@
 
 static struct clk_regmap_mux dsi1pll_pclk_src_mux = {
 	.shift = 0,
-	.width = 0,
+	.width = 1,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi1pll_pclk_src_mux",
@@ -1307,7 +1329,7 @@
 
 static struct clk_regmap_mux dsi0pll_pclk_mux = {
 	.shift = 0,
-	.width = 0,
+	.width = 1,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi0_phy_pll_out_dsiclk",
@@ -1321,7 +1343,7 @@
 
 static struct clk_regmap_mux dsi1pll_pclk_mux = {
 	.shift = 0,
-	.width = 0,
+	.width = 1,
 	.clkr = {
 		.hw.init = &(struct clk_init_data){
 			.name = "dsi1_phy_pll_out_dsiclk",
diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c
index 8b63979..4eb8a04 100644
--- a/drivers/clk/qcom/videocc-sdm845.c
+++ b/drivers/clk/qcom/videocc-sdm845.c
@@ -151,19 +151,6 @@
 	},
 };
 
-static struct clk_branch video_cc_debug_clk = {
-	.halt_reg = 0xa58,
-	.halt_check = BRANCH_HALT,
-	.clkr = {
-		.enable_reg = 0xa58,
-		.enable_mask = BIT(0),
-		.hw.init = &(struct clk_init_data){
-			.name = "video_cc_debug_clk",
-			.ops = &clk_branch2_ops,
-		},
-	},
-};
-
 static struct clk_branch video_cc_qdss_trig_clk = {
 	.halt_reg = 0x970,
 	.halt_check = BRANCH_HALT,
@@ -299,7 +286,6 @@
 static struct clk_regmap *video_cc_sdm845_clocks[] = {
 	[VIDEO_CC_APB_CLK] = &video_cc_apb_clk.clkr,
 	[VIDEO_CC_AT_CLK] = &video_cc_at_clk.clkr,
-	[VIDEO_CC_DEBUG_CLK] = &video_cc_debug_clk.clkr,
 	[VIDEO_CC_QDSS_TRIG_CLK] = &video_cc_qdss_trig_clk.clkr,
 	[VIDEO_CC_QDSS_TSCTR_DIV8_CLK] = &video_cc_qdss_tsctr_div8_clk.clkr,
 	[VIDEO_CC_VCODEC0_AXI_CLK] = &video_cc_vcodec0_axi_clk.clkr,
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 550a59c..5db1897 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -441,15 +441,14 @@
 {
 	u32 cntkctl = arch_timer_get_cntkctl();
 
-	/* Disable user access to the timers and the physical counter */
+	/* Disable user access to the timers */
 	/* Also disable virtual event stream */
 	cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
 			| ARCH_TIMER_USR_VT_ACCESS_EN
-			| ARCH_TIMER_VIRT_EVT_EN
-			| ARCH_TIMER_USR_PCT_ACCESS_EN);
+			| ARCH_TIMER_VIRT_EVT_EN);
 
-	/* Enable user access to the virtual counter */
-	cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
+	/* Enable user access to the virtual and physical counters */
+	cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN | ARCH_TIMER_USR_PCT_ACCESS_EN;
 
 	arch_timer_set_cntkctl(cntkctl);
 }
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index fd02eba..f61b78a 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -385,58 +385,6 @@
 	  Select this to offload Samsung S5PV210 or S5PC110, Exynos from AES
 	  algorithms execution.
 
-config CRYPTO_DEV_QCE50
-        bool
-
-config FIPS_ENABLE
-        bool "FIPS140-2 compliant build"
-        default n
-        help
-          This flag is used to make current build FIPS140-2
-          compliant. This flag will enable the patch of code
-          which will perform this task. Please select Y here
-          to enable.
-
-config CRYPTO_DEV_QCRYPTO
-        tristate "QTI Crypto accelerator"
-        select CRYPTO_DES
-        select CRYPTO_ALGAPI
-        select CRYPTO_AUTHENC
-        select CRYPTO_BLKCIPHER
-        default n
-        help
-          This driver supports QTI crypto acceleration
-          for kernel clients. To compile this driver as a module,
-          choose M here: the module will be called qcrypto. Please
-          select Y here to enable.
-
-config CRYPTO_DEV_QCOM_MSM_QCE
-        tristate "QTI Crypto Engine (QCE) module"
-        default n
-        help
-          This driver supports QTI Crypto Engine 5.0.
-          To compile this driver as a module, choose M here: the
-          module is called qce50.
-
-config CRYPTO_DEV_QCEDEV
-        tristate "QCEDEV Interface to CE module"
-        default n
-        help
-          This driver supports QTI QCEDEV Crypto Engine 5.0.
-          This exposes the interface to the QCE hardware accelerator
-          via IOCTLs.
-
-          To compile this driver as a module, choose M here: the
-          module will be called qcedev.
-
-config CRYPTO_DEV_OTA_CRYPTO
-        tristate "OTA Crypto module"
-        help
-          This driver supports QTI OTA Crypto in the FSM9xxx.
-          To compile this driver as a module, choose M here: the
-          module will be called ota_crypto. Please select Y here
-          to enable.
-
 config CRYPTO_DEV_NX
 	bool "Support for IBM PowerPC Nest (NX) cryptographic acceleration"
 	depends on PPC64
@@ -550,7 +498,49 @@
 	help
 	  This driver supports Qualcomm crypto engine accelerator
 	  hardware. To compile this driver as a module, choose M here. The
-	  module will be called qcrypto.
+	  module will be called qcrypt.
+
+config CRYPTO_DEV_QCOM_MSM_QCE
+	tristate "QTI Crypto Engine (QCE) module"
+	depends on ARCH_QCOM
+	help
+	  This driver supports QTI Crypto Engine accelerator hardware, which
+	  is present on SDM845. This is the core crypto driver which adds
+	  CE5.0 functionalities. To compile this driver as a module, choose
+	  M here. The module will be called QCE50.
+
+config CRYPTO_DEV_QCRYPTO
+	tristate "QTI Crypto accelerator"
+	depends on ARCH_QCOM
+	select CRYPTO_DES
+	select CRYPTO_ALGAPI
+	select CRYPTO_AUTHENC
+	select CRYPTO_BLKCIPHER
+	help
+	  This driver supports QTI crypto acceleration
+	  for kernel clients. To compile this driver as a module,
+	  choose M here: the module will be called qcrypto. Please
+	  select Y here to enable.
+
+config CRYPTO_DEV_QCEDEV
+	tristate "QCEDEV Interface to CE module"
+	depends on ARCH_QCOM
+	help
+	  This driver supports QTI QCEDEV Crypto Engine 5.0.
+	  This exposes the interface to the QCE hardware accelerator
+	  via IOCTLs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qcedev.
+
+config CRYPTO_DEV_OTA_CRYPTO
+	tristate "OTA Crypto module"
+	depends on ARCH_QCOM
+	help
+	  This driver supports QTI OTA Crypto in the FSM9xxx.
+	  To compile this driver as a module, choose M here: the
+	  module will be called ota_crypto. Please select Y here
+	  to enable.
 
 config CRYPTO_DEV_VMX
 	bool "Support for VMX cryptographic acceleration instructions"
diff --git a/drivers/crypto/msm/Kconfig b/drivers/crypto/msm/Kconfig
index 0f4568b..3011aa6 100644
--- a/drivers/crypto/msm/Kconfig
+++ b/drivers/crypto/msm/Kconfig
@@ -2,7 +2,7 @@
 config CRYPTO_DEV_QCOM_ICE
 	tristate "Inline Crypto Module"
 	default n
-	depends on PFK && BLK_DEV_DM
+	depends on BLK_DEV_DM
 	help
 	  This driver supports Inline Crypto Engine for QTI chipsets, MSM8994
 	  and later, to accelerate crypto operations for storage needs.
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index ba6825e..b411726 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -21,12 +21,31 @@
 #include <linux/cdev.h>
 #include <linux/regulator/consumer.h>
 #include <linux/msm-bus.h>
-#include <linux/pfk.h>
 #include <crypto/ice.h>
 #include <soc/qcom/scm.h>
 #include <soc/qcom/qseecomi.h>
 #include "iceregs.h"
 
+#ifdef CONFIG_PFK
+#include <linux/pfk.h>
+#else
+#include <linux/bio.h>
+static inline int pfk_load_key_start(const struct bio *bio,
+	struct ice_crypto_setting *ice_setting, bool *is_pfe, bool async)
+{
+	return 0;
+}
+
+static inline int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
+{
+	return 0;
+}
+
+static inline void pfk_clear_on_reset(void)
+{
+}
+#endif
+
 #define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
 	((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff)))
 
diff --git a/drivers/crypto/qce/Makefile b/drivers/crypto/qce/Makefile
index 348dc31..7f584ee 100644
--- a/drivers/crypto/qce/Makefile
+++ b/drivers/crypto/qce/Makefile
@@ -1,5 +1,5 @@
-obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypto.o
-qcrypto-objs := core.o \
+obj-$(CONFIG_CRYPTO_DEV_QCE) += qcrypt.o
+qcrypt-objs := core.o \
 		common.o \
 		dma.o \
 		sha.o \
diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig
index 3e2ab3b..9e95bf9 100644
--- a/drivers/dax/Kconfig
+++ b/drivers/dax/Kconfig
@@ -2,6 +2,7 @@
 	tristate "DAX: direct access to differentiated memory"
 	default m if NVDIMM_DAX
 	depends on TRANSPARENT_HUGEPAGE
+	select SRCU
 	help
 	  Support raw access to differentiated (persistence, bandwidth,
 	  latency...) memory via an mmap(2) capable character
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 152552d..1932248 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -24,6 +24,7 @@
 #include "dax.h"
 
 static dev_t dax_devt;
+DEFINE_STATIC_SRCU(dax_srcu);
 static struct class *dax_class;
 static DEFINE_IDA(dax_minor_ida);
 static int nr_dax = CONFIG_NR_DEV_DAX;
@@ -59,7 +60,7 @@
  * @region - parent region
  * @dev - device backing the character device
  * @cdev - core chardev data
- * @alive - !alive + rcu grace period == no new mappings can be established
+ * @alive - !alive + srcu grace period == no new mappings can be established
  * @id - child id in the region
  * @num_resources - number of physical address extents in this device
  * @res - array of physical address ranges
@@ -437,7 +438,7 @@
 static int dax_dev_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
 		pmd_t *pmd, unsigned int flags)
 {
-	int rc;
+	int rc, id;
 	struct file *filp = vma->vm_file;
 	struct dax_dev *dax_dev = filp->private_data;
 
@@ -445,9 +446,9 @@
 			current->comm, (flags & FAULT_FLAG_WRITE)
 			? "write" : "read", vma->vm_start, vma->vm_end);
 
-	rcu_read_lock();
+	id = srcu_read_lock(&dax_srcu);
 	rc = __dax_dev_pmd_fault(dax_dev, vma, addr, pmd, flags);
-	rcu_read_unlock();
+	srcu_read_unlock(&dax_srcu, id);
 
 	return rc;
 }
@@ -563,11 +564,11 @@
 	 * Note, rcu is not protecting the liveness of dax_dev, rcu is
 	 * ensuring that any fault handlers that might have seen
 	 * dax_dev->alive == true, have completed.  Any fault handlers
-	 * that start after synchronize_rcu() has started will abort
+	 * that start after synchronize_srcu() has started will abort
 	 * upon seeing dax_dev->alive == false.
 	 */
 	dax_dev->alive = false;
-	synchronize_rcu();
+	synchronize_srcu(&dax_srcu);
 	unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1);
 	cdev_del(cdev);
 	device_unregister(dev);
diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c
index cd4fdfb..d70104d 100644
--- a/drivers/devfreq/bimc-bwmon.c
+++ b/drivers/devfreq/bimc-bwmon.c
@@ -54,6 +54,11 @@
 #define MON2_ZONE_CNT(m)	((m)->base + 0x2D8)
 #define MON2_ZONE_MAX(m, zone)	((m)->base + 0x2E0 + 0x4 * zone)
 
+enum bwmon_type {
+	BWMON_1,
+	BWMON_2,
+};
+
 struct bwmon_spec {
 	bool wrap_on_thres;
 	bool overflow;
@@ -76,7 +81,6 @@
 };
 
 #define to_bwmon(ptr)		container_of(ptr, struct bwmon, hw)
-#define has_hw_sampling(m)		(m->spec->hw_sampling)
 
 #define ENABLE_MASK BIT(0)
 #define THROTTLE_MASK 0x1F
@@ -86,20 +90,29 @@
 #define INT_STATUS_MASK_HWS	0xF0
 
 static DEFINE_SPINLOCK(glb_lock);
-static void mon_enable(struct bwmon *m)
+
+static __always_inline void mon_enable(struct bwmon *m, enum bwmon_type type)
 {
-	if (has_hw_sampling(m))
-		writel_relaxed((ENABLE_MASK | m->throttle_adj), MON2_EN(m));
-	else
-		writel_relaxed((ENABLE_MASK | m->throttle_adj), MON_EN(m));
+	switch (type) {
+	case BWMON_1:
+		writel_relaxed(ENABLE_MASK | m->throttle_adj, MON_EN(m));
+		break;
+	case BWMON_2:
+		writel_relaxed(ENABLE_MASK | m->throttle_adj, MON2_EN(m));
+		break;
+	}
 }
 
-static void mon_disable(struct bwmon *m)
+static __always_inline void mon_disable(struct bwmon *m, enum bwmon_type type)
 {
-	if (has_hw_sampling(m))
-		writel_relaxed(m->throttle_adj, MON2_EN(m));
-	else
+	switch (type) {
+	case BWMON_1:
 		writel_relaxed(m->throttle_adj, MON_EN(m));
+		break;
+	case BWMON_2:
+		writel_relaxed(m->throttle_adj, MON2_EN(m));
+		break;
+	}
 	/*
 	 * mon_disable() and mon_irq_clear(),
 	 * If latter goes first and count happen to trigger irq, we would
@@ -110,24 +123,25 @@
 
 #define MON_CLEAR_BIT	0x1
 #define MON_CLEAR_ALL_BIT	0x2
-static void mon_clear(struct bwmon *m, bool clear_all)
+static __always_inline
+void mon_clear(struct bwmon *m, bool clear_all, enum bwmon_type type)
 {
-	if (!has_hw_sampling(m)) {
+	switch (type) {
+	case BWMON_1:
 		writel_relaxed(MON_CLEAR_BIT, MON_CLEAR(m));
-		goto out;
+		break;
+	case BWMON_2:
+		if (clear_all)
+			writel_relaxed(MON_CLEAR_ALL_BIT, MON2_CLEAR(m));
+		else
+			writel_relaxed(MON_CLEAR_BIT, MON2_CLEAR(m));
+		break;
 	}
-
-	if (clear_all)
-		writel_relaxed(MON_CLEAR_ALL_BIT, MON2_CLEAR(m));
-	else
-		writel_relaxed(MON_CLEAR_BIT, MON2_CLEAR(m));
-
 	/*
 	 * The counter clear and IRQ clear bits are not in the same 4KB
 	 * region. So, we need to make sure the counter clear is completed
 	 * before we try to clear the IRQ or do any other counter operations.
 	 */
-out:
 	mb();
 }
 
@@ -148,72 +162,141 @@
 	}
 }
 
-static void mon_irq_enable(struct bwmon *m)
+static void mon_glb_irq_enable(struct bwmon *m)
 {
 	u32 val;
 
-	spin_lock(&glb_lock);
 	val = readl_relaxed(GLB_INT_EN(m));
 	val |= 1 << m->mport;
 	writel_relaxed(val, GLB_INT_EN(m));
-
-	val = readl_relaxed(MON_INT_EN(m));
-	val |= has_hw_sampling(m) ? INT_STATUS_MASK_HWS : INT_ENABLE_V1;
-	writel_relaxed(val, MON_INT_EN(m));
-	spin_unlock(&glb_lock);
-	/*
-	 * make Sure irq enable complete for local and global
-	 * to avoid race with other monitor calls
-	 */
-	mb();
 }
 
-static void mon_irq_disable(struct bwmon *m)
+static __always_inline
+void mon_irq_enable(struct bwmon *m, enum bwmon_type type)
 {
 	u32 val;
 
 	spin_lock(&glb_lock);
-	val = readl_relaxed(GLB_INT_EN(m));
-	val &= ~(1 << m->mport);
-	writel_relaxed(val, GLB_INT_EN(m));
-
-	val = readl_relaxed(MON_INT_EN(m));
-	val &= has_hw_sampling(m) ? ~INT_STATUS_MASK_HWS : ~INT_ENABLE_V1;
-	writel_relaxed(val, MON_INT_EN(m));
+	switch (type) {
+	case BWMON_1:
+		mon_glb_irq_enable(m);
+		val = readl_relaxed(MON_INT_EN(m));
+		val |= INT_ENABLE_V1;
+		writel_relaxed(val, MON_INT_EN(m));
+		break;
+	case BWMON_2:
+		mon_glb_irq_enable(m);
+		val = readl_relaxed(MON_INT_EN(m));
+		val |= INT_STATUS_MASK_HWS;
+		writel_relaxed(val, MON_INT_EN(m));
+		break;
+	}
 	spin_unlock(&glb_lock);
 	/*
-	 * make Sure irq disable complete for local and global
+	 * make sure irq enable complete for local and global
 	 * to avoid race with other monitor calls
 	 */
 	mb();
 }
 
-static unsigned int mon_irq_status(struct bwmon *m)
+static void mon_glb_irq_disable(struct bwmon *m)
+{
+	u32 val;
+
+	val = readl_relaxed(GLB_INT_EN(m));
+	val &= ~(1 << m->mport);
+	writel_relaxed(val, GLB_INT_EN(m));
+}
+
+static __always_inline
+void mon_irq_disable(struct bwmon *m, enum bwmon_type type)
+{
+	u32 val;
+
+	spin_lock(&glb_lock);
+
+	switch (type) {
+	case BWMON_1:
+		mon_glb_irq_disable(m);
+		val = readl_relaxed(MON_INT_EN(m));
+		val &= ~INT_ENABLE_V1;
+		writel_relaxed(val, MON_INT_EN(m));
+		break;
+	case BWMON_2:
+		mon_glb_irq_disable(m);
+		val = readl_relaxed(MON_INT_EN(m));
+		val &= ~INT_STATUS_MASK_HWS;
+		writel_relaxed(val, MON_INT_EN(m));
+		break;
+	}
+	spin_unlock(&glb_lock);
+	/*
+	 * make sure irq disable complete for local and global
+	 * to avoid race with other monitor calls
+	 */
+	mb();
+}
+
+static __always_inline
+unsigned int mon_irq_status(struct bwmon *m, enum bwmon_type type)
 {
 	u32 mval;
 
-	mval = readl_relaxed(MON_INT_STATUS(m));
-
-	dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
-			readl_relaxed(GLB_INT_STATUS(m)));
-
-	mval &= has_hw_sampling(m) ? INT_STATUS_MASK_HWS : INT_STATUS_MASK;
+	switch (type) {
+	case BWMON_1:
+		mval = readl_relaxed(MON_INT_STATUS(m));
+		dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
+				readl_relaxed(GLB_INT_STATUS(m)));
+		mval &= INT_STATUS_MASK;
+		break;
+	case BWMON_2:
+		mval = readl_relaxed(MON_INT_STATUS(m));
+		dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
+				readl_relaxed(GLB_INT_STATUS(m)));
+		mval &= INT_STATUS_MASK_HWS;
+		break;
+	}
 
 	return mval;
 }
 
-static void mon_irq_clear(struct bwmon *m)
+
+static void mon_glb_irq_clear(struct bwmon *m)
 {
-	u32 intclr;
-
-	intclr = has_hw_sampling(m) ? INT_STATUS_MASK_HWS : INT_STATUS_MASK;
-
-	writel_relaxed(intclr, MON_INT_CLR(m));
+	/*
+	 * Synchronize the local interrupt clear in mon_irq_clear()
+	 * with the global interrupt clear here. Otherwise, the CPU
+	 * may reorder the two writes and clear the global interrupt
+	 * before the local interrupt, causing the global interrupt
+	 * to be retriggered by the local interrupt still being high.
+	 */
 	mb();
 	writel_relaxed(1 << m->mport, GLB_INT_CLR(m));
+	/*
+	 * Similarly, because the global registers are in a different
+	 * region than the local registers, we need to ensure any register
+	 * writes to enable the monitor after this call are ordered with the
+	 * clearing here so that local writes don't happen before the
+	 * interrupt is cleared.
+	 */
 	mb();
 }
 
+static __always_inline
+void mon_irq_clear(struct bwmon *m, enum bwmon_type type)
+{
+	switch (type) {
+	case BWMON_1:
+		writel_relaxed(INT_STATUS_MASK, MON_INT_CLR(m));
+		mon_glb_irq_clear(m);
+		break;
+	case BWMON_2:
+		writel_relaxed(INT_STATUS_MASK_HWS, MON_INT_CLR(m));
+		mon_glb_irq_clear(m);
+		break;
+	}
+}
+
 static int mon_set_throttle_adj(struct bw_hwmon *hw, uint adj)
 {
 	struct bwmon *m = to_bwmon(hw);
@@ -331,12 +414,12 @@
 
 #define THRES_HIT(status)	(status & BIT(0))
 #define OVERFLOW(status)	(status & BIT(1))
-static unsigned long mon_get_count(struct bwmon *m)
+static unsigned long mon_get_count1(struct bwmon *m)
 {
 	unsigned long count, status;
 
 	count = readl_relaxed(MON_CNT(m));
-	status = mon_irq_status(m);
+	status = mon_irq_status(m, BWMON_1);
 
 	dev_dbg(m->dev, "Counter: %08lx\n", count);
 
@@ -385,6 +468,23 @@
 	return count;
 }
 
+static __always_inline
+unsigned long mon_get_count(struct bwmon *m, enum bwmon_type type)
+{
+	unsigned long count;
+
+	switch (type) {
+	case BWMON_1:
+		count = mon_get_count1(m);
+		break;
+	case BWMON_2:
+		count = mon_get_zone_stats(m);
+		break;
+	}
+
+	return count;
+}
+
 /* ********** CPUBW specific code  ********** */
 
 /* Returns MBps of read/writes for the sampling window. */
@@ -398,30 +498,41 @@
 	return mbps;
 }
 
-static unsigned long get_bytes_and_clear(struct bw_hwmon *hw)
+static __always_inline
+unsigned long __get_bytes_and_clear(struct bw_hwmon *hw, enum bwmon_type type)
 {
 	struct bwmon *m = to_bwmon(hw);
 	unsigned long count;
 
-	mon_disable(m);
-	count = has_hw_sampling(m) ? mon_get_zone_stats(m) : mon_get_count(m);
-	mon_clear(m, false);
-	mon_irq_clear(m);
-	mon_enable(m);
+	mon_disable(m, type);
+	count = mon_get_count(m, type);
+	mon_clear(m, false, type);
+	mon_irq_clear(m, type);
+	mon_enable(m, type);
 
 	return count;
 }
 
+static unsigned long get_bytes_and_clear(struct bw_hwmon *hw)
+{
+	return __get_bytes_and_clear(hw, BWMON_1);
+}
+
+static unsigned long get_bytes_and_clear2(struct bw_hwmon *hw)
+{
+	return __get_bytes_and_clear(hw, BWMON_2);
+}
+
 static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes)
 {
 	unsigned long count;
 	u32 limit;
 	struct bwmon *m = to_bwmon(hw);
 
-	mon_disable(m);
-	count = mon_get_count(m);
-	mon_clear(m, false);
-	mon_irq_clear(m);
+	mon_disable(m, BWMON_1);
+	count = mon_get_count1(m);
+	mon_clear(m, false, BWMON_1);
+	mon_irq_clear(m, BWMON_1);
 
 	if (likely(!m->spec->wrap_on_thres))
 		limit = bytes;
@@ -429,7 +540,7 @@
 		limit = max(bytes, 500000UL);
 
 	mon_set_limit(m, limit);
-	mon_enable(m);
+	mon_enable(m, BWMON_1);
 
 	return count;
 }
@@ -438,21 +549,22 @@
 {
 	struct bwmon *m = to_bwmon(hw);
 
-	mon_disable(m);
-	mon_clear(m, false);
-	mon_irq_clear(m);
+	mon_disable(m, BWMON_2);
+	mon_clear(m, false, BWMON_2);
+	mon_irq_clear(m, BWMON_2);
 
 	mon_set_zones(m, sample_ms);
-	mon_enable(m);
+	mon_enable(m, BWMON_2);
 
 	return 0;
 }
 
-static irqreturn_t bwmon_intr_handler(int irq, void *dev)
+static irqreturn_t
+__bwmon_intr_handler(int irq, void *dev, enum bwmon_type type)
 {
 	struct bwmon *m = dev;
 
-	m->intr_status = mon_irq_status(m);
+	m->intr_status = mon_irq_status(m, type);
 	if (!m->intr_status)
 		return IRQ_NONE;
 
@@ -462,6 +574,16 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t bwmon_intr_handler(int irq, void *dev)
+{
+	return __bwmon_intr_handler(irq, dev, BWMON_1);
+}
+
+static irqreturn_t bwmon_intr_handler2(int irq, void *dev)
+{
+	return __bwmon_intr_handler(irq, dev, BWMON_2);
+}
+
 static irqreturn_t bwmon_intr_thread(int irq, void *dev)
 {
 	struct bwmon *m = dev;
@@ -470,98 +592,180 @@
 	return IRQ_HANDLED;
 }
 
-static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps)
+static __always_inline int
+__start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps, enum bwmon_type type)
 {
 	struct bwmon *m = to_bwmon(hw);
-	u32 limit;
-	u32 zone_actions = calc_zone_actions();
+	u32 limit, zone_actions;
 	int ret;
+	irq_handler_t handler;
 
-	ret = request_threaded_irq(m->irq, bwmon_intr_handler,
-				  bwmon_intr_thread,
+	switch (type) {
+	case BWMON_1:
+		handler = bwmon_intr_handler;
+		limit = mbps_to_bytes(mbps, hw->df->profile->polling_ms, 0);
+		break;
+	case BWMON_2:
+		zone_actions = calc_zone_actions();
+		handler = bwmon_intr_handler2;
+		break;
+	}
+
+	ret = request_threaded_irq(m->irq, handler, bwmon_intr_thread,
 				  IRQF_ONESHOT | IRQF_SHARED,
 				  dev_name(m->dev), m);
 	if (ret) {
 		dev_err(m->dev, "Unable to register interrupt handler! (%d)\n",
-				ret);
+			ret);
 		return ret;
 	}
 
-	mon_disable(m);
+	mon_disable(m, type);
 
-	mon_clear(m, true);
-	limit = mbps_to_bytes(mbps, hw->df->profile->polling_ms, 0);
-	if (has_hw_sampling(m)) {
+	mon_clear(m, false, type);
+
+	switch (type) {
+	case BWMON_1:
+		handler = bwmon_intr_handler;
+		mon_set_limit(m, limit);
+		break;
+	case BWMON_2:
 		mon_set_zones(m, hw->df->profile->polling_ms);
 		/* Set the zone actions to increment appropriate counters */
 		writel_relaxed(zone_actions, MON2_ZONE_ACTIONS(m));
-	} else {
-		mon_set_limit(m, limit);
+		break;
 	}
 
-	mon_irq_clear(m);
-	mon_irq_enable(m);
-	mon_enable(m);
+	mon_irq_clear(m, type);
+	mon_irq_enable(m, type);
+	mon_enable(m, type);
 
 	return 0;
 }
 
-static void stop_bw_hwmon(struct bw_hwmon *hw)
+static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps)
+{
+	return __start_bw_hwmon(hw, mbps, BWMON_1);
+}
+
+static int start_bw_hwmon2(struct bw_hwmon *hw, unsigned long mbps)
+{
+	return __start_bw_hwmon(hw, mbps, BWMON_2);
+}
+
+static __always_inline
+void __stop_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type)
 {
 	struct bwmon *m = to_bwmon(hw);
 
-	mon_irq_disable(m);
+	mon_irq_disable(m, type);
 	free_irq(m->irq, m);
-	mon_disable(m);
-	mon_clear(m, true);
-	mon_irq_clear(m);
+	mon_disable(m, type);
+	mon_clear(m, true, type);
+	mon_irq_clear(m, type);
+}
+
+static void stop_bw_hwmon(struct bw_hwmon *hw)
+{
+	return __stop_bw_hwmon(hw, BWMON_1);
+}
+
+static void stop_bw_hwmon2(struct bw_hwmon *hw)
+{
+	return __stop_bw_hwmon(hw, BWMON_2);
+}
+
+static __always_inline
+int __suspend_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type)
+{
+	struct bwmon *m = to_bwmon(hw);
+
+	mon_irq_disable(m, type);
+	free_irq(m->irq, m);
+	mon_disable(m, type);
+	mon_irq_clear(m, type);
+
+	return 0;
 }
 
 static int suspend_bw_hwmon(struct bw_hwmon *hw)
 {
-	struct bwmon *m = to_bwmon(hw);
+	return __suspend_bw_hwmon(hw, BWMON_1);
+}
 
-	mon_irq_disable(m);
-	free_irq(m->irq, m);
-	mon_disable(m);
-	mon_irq_clear(m);
+static int suspend_bw_hwmon2(struct bw_hwmon *hw)
+{
+	return __suspend_bw_hwmon(hw, BWMON_2);
+}
+
+static int __resume_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type)
+{
+	struct bwmon *m = to_bwmon(hw);
+	int ret;
+	irq_handler_t handler;
+
+	switch (type) {
+	case BWMON_1:
+		handler = bwmon_intr_handler;
+		break;
+	case BWMON_2:
+		handler = bwmon_intr_handler2;
+		break;
+	}
+
+	mon_clear(m, false, type);
+	ret = request_threaded_irq(m->irq, handler, bwmon_intr_thread,
+				  IRQF_ONESHOT | IRQF_SHARED,
+				  dev_name(m->dev), m);
+	if (ret) {
+		dev_err(m->dev, "Unable to register interrupt handler! (%d)\n",
+			ret);
+		return ret;
+	}
+
+	mon_irq_enable(m, type);
+	mon_enable(m, type);
 
 	return 0;
 }
 
 static int resume_bw_hwmon(struct bw_hwmon *hw)
 {
-	struct bwmon *m = to_bwmon(hw);
-	int ret;
+	return __resume_bw_hwmon(hw, BWMON_1);
+}
 
-	mon_clear(m, false);
-	ret = request_threaded_irq(m->irq, bwmon_intr_handler,
-				  bwmon_intr_thread,
-				  IRQF_ONESHOT | IRQF_SHARED,
-				  dev_name(m->dev), m);
-	if (ret) {
-		dev_err(m->dev, "Unable to register interrupt handler! (%d)\n",
-				ret);
-		return ret;
-	}
-
-	mon_irq_enable(m);
-	mon_enable(m);
-
-	return 0;
+static int resume_bw_hwmon2(struct bw_hwmon *hw)
+{
+	return __resume_bw_hwmon(hw, BWMON_2);
 }
 
 /*************************************************************************/
 
 static const struct bwmon_spec spec[] = {
-	{ .wrap_on_thres = true, .overflow = false, .throt_adj = false,
-		.hw_sampling = false},
-	{ .wrap_on_thres = false, .overflow = true, .throt_adj = false,
-		.hw_sampling = false},
-	{ .wrap_on_thres = false, .overflow = true, .throt_adj = true,
-		.hw_sampling = false},
-	{ .wrap_on_thres = false, .overflow = true, .throt_adj = true,
-		.hw_sampling = true},
+	[0] = {
+		.wrap_on_thres = true,
+		.overflow = false,
+		.throt_adj = false,
+		.hw_sampling = false
+	},
+	[1] = {
+		.wrap_on_thres = false,
+		.overflow = true,
+		.throt_adj = false,
+		.hw_sampling = false
+	},
+	[2] = {
+		.wrap_on_thres = false,
+		.overflow = true,
+		.throt_adj = true,
+		.hw_sampling = false
+	},
+	[3] = {
+		.wrap_on_thres = false,
+		.overflow = true,
+		.throt_adj = true,
+		.hw_sampling = true
+	},
 };
 
 static const struct of_device_id bimc_bwmon_match_table[] = {
@@ -577,7 +781,6 @@
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	struct bwmon *m;
-	const struct of_device_id *id;
 	int ret;
 	u32 data;
 
@@ -593,22 +796,11 @@
 	}
 	m->mport = data;
 
-	id = of_match_device(bimc_bwmon_match_table, dev);
-	if (!id) {
+	m->spec = of_device_get_match_data(dev);
+	if (!m->spec) {
 		dev_err(dev, "Unknown device type!\n");
 		return -ENODEV;
 	}
-	m->spec = id->data;
-
-	if (has_hw_sampling(m)) {
-		ret = of_property_read_u32(dev->of_node,
-				"qcom,hw-timer-hz", &data);
-		if (ret) {
-			dev_err(dev, "HW sampling rate not specified!\n");
-			return ret;
-		}
-		m->hw_timer_hz = data;
-	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
 	if (!res) {
@@ -641,17 +833,33 @@
 	m->hw.of_node = of_parse_phandle(dev->of_node, "qcom,target-dev", 0);
 	if (!m->hw.of_node)
 		return -EINVAL;
-	m->hw.start_hwmon = &start_bw_hwmon;
-	m->hw.stop_hwmon = &stop_bw_hwmon;
-	m->hw.suspend_hwmon = &suspend_bw_hwmon;
-	m->hw.resume_hwmon = &resume_bw_hwmon;
-	m->hw.get_bytes_and_clear = &get_bytes_and_clear;
-	m->hw.set_thres =  &set_thres;
-	if (has_hw_sampling(m))
-		m->hw.set_hw_events = &set_hw_events;
+
+	if (m->spec->hw_sampling) {
+		ret = of_property_read_u32(dev->of_node, "qcom,hw-timer-hz",
+					   &m->hw_timer_hz);
+		if (ret) {
+			dev_err(dev, "HW sampling rate not specified!\n");
+			return ret;
+		}
+
+		m->hw.start_hwmon = start_bw_hwmon2;
+		m->hw.stop_hwmon = stop_bw_hwmon2;
+		m->hw.suspend_hwmon = suspend_bw_hwmon2;
+		m->hw.resume_hwmon = resume_bw_hwmon2;
+		m->hw.get_bytes_and_clear = get_bytes_and_clear2;
+		m->hw.set_hw_events = set_hw_events;
+	} else {
+		m->hw.start_hwmon = start_bw_hwmon;
+		m->hw.stop_hwmon = stop_bw_hwmon;
+		m->hw.suspend_hwmon = suspend_bw_hwmon;
+		m->hw.resume_hwmon = resume_bw_hwmon;
+		m->hw.get_bytes_and_clear = get_bytes_and_clear;
+		m->hw.set_thres = set_thres;
+	}
+
 	if (m->spec->throt_adj) {
-		m->hw.set_throttle_adj = &mon_set_throttle_adj;
-		m->hw.get_throttle_adj = &mon_get_throttle_adj;
+		m->hw.set_throttle_adj = mon_set_throttle_adj;
+		m->hw.get_throttle_adj = mon_get_throttle_adj;
 	}
 
 	ret = register_bw_hwmon(dev, &m->hw);
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index d7cc425..53c0f8a 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-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
@@ -143,25 +143,27 @@
 {									\
 	struct devfreq *df = to_devfreq(dev);				\
 	struct hwmon_node *hw = df->data;				\
-	int ret;							\
+	int ret, numvals;						\
 	unsigned int i = 0, val;					\
+	char **strlist;							\
 									\
-	do {								\
-		ret = kstrtoint(buf, 10, &val);				\
+	strlist = argv_split(GFP_KERNEL, buf, &numvals);		\
+	if (!strlist)							\
+		return -ENOMEM;						\
+	numvals = min(numvals, n - 1);					\
+	for (i = 0; i < numvals; i++) {					\
+		ret = kstrtouint(strlist[i], 10, &val);			\
 		if (ret)						\
-			break;						\
-		buf = strnchr(buf, PAGE_SIZE, ' ');			\
-		if (buf)						\
-			buf++;						\
+			goto out;					\
 		val = max(val, _min);					\
 		val = min(val, _max);					\
 		hw->name[i] = val;					\
-		i++;							\
-	} while (buf && i < n - 1);					\
-	if (i < 1)							\
-		return -EINVAL;						\
+	}								\
+	ret = count;							\
+out:									\
+	argv_free(strlist);						\
 	hw->name[i] = 0;						\
-	return count;							\
+	return ret;							\
 }
 
 #define gov_list_attr(__attr, n, min, max)	\
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 1434eac..3625ed0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -181,6 +181,8 @@
 		dsi_phy_hw_v3_0_ulps_exit;
 	phy->ops.ulps_ops.get_lanes_in_ulps =
 		dsi_phy_hw_v3_0_get_lanes_in_ulps;
+	phy->ops.ulps_ops.is_lanes_in_ulps =
+		dsi_phy_hw_v3_0_is_lanes_in_ulps;
 	phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0;
 }
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 160cd32..5dcdf46 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -97,6 +97,7 @@
 void dsi_phy_hw_v3_0_ulps_exit(struct dsi_phy_hw *phy,
 			struct dsi_phy_cfg *cfg, u32 lanes);
 u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy);
+bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes);
 int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
 		u32 *timing_val, u32 size);
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index cc87775..560964e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -236,32 +236,52 @@
 	return rc;
 
 error_disable_mmss_clk:
-	clk_disable_unprepare(c_clks->clks.core_mmss_clk);
+	if (c_clks->clks.core_mmss_clk)
+		clk_disable_unprepare(c_clks->clks.core_mmss_clk);
 error_disable_bus_clk:
-	clk_disable_unprepare(c_clks->clks.bus_clk);
+	if (c_clks->clks.bus_clk)
+		clk_disable_unprepare(c_clks->clks.bus_clk);
 error_disable_iface_clk:
-	clk_disable_unprepare(c_clks->clks.iface_clk);
+	if (c_clks->clks.iface_clk)
+		clk_disable_unprepare(c_clks->clks.iface_clk);
 error_disable_mnoc_clk:
 	if (c_clks->clks.mnoc_clk)
 		clk_disable_unprepare(c_clks->clks.mnoc_clk);
 error_disable_core_clk:
-	clk_disable_unprepare(c_clks->clks.mdp_core_clk);
+	if (c_clks->clks.mdp_core_clk)
+		clk_disable_unprepare(c_clks->clks.mdp_core_clk);
 error:
 	return rc;
 }
 
 int dsi_core_clk_stop(struct dsi_core_clks *c_clks)
 {
-	if (msm_bus_scale_client_update_request(c_clks->bus_handle, 0))
-		pr_err("bus scale client disable failed\n");
-	clk_disable_unprepare(c_clks->clks.core_mmss_clk);
-	clk_disable_unprepare(c_clks->clks.bus_clk);
-	clk_disable_unprepare(c_clks->clks.iface_clk);
+	int rc = 0;
+
+	if (c_clks->bus_handle) {
+		rc = msm_bus_scale_client_update_request(c_clks->bus_handle, 0);
+		if (rc) {
+			pr_err("bus scale client disable failed, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	if (c_clks->clks.core_mmss_clk)
+		clk_disable_unprepare(c_clks->clks.core_mmss_clk);
+
+	if (c_clks->clks.bus_clk)
+		clk_disable_unprepare(c_clks->clks.bus_clk);
+
+	if (c_clks->clks.iface_clk)
+		clk_disable_unprepare(c_clks->clks.iface_clk);
+
 	if (c_clks->clks.mnoc_clk)
 		clk_disable_unprepare(c_clks->clks.mnoc_clk);
-	clk_disable_unprepare(c_clks->clks.mdp_core_clk);
 
-	return 0;
+	if (c_clks->clks.mdp_core_clk)
+		clk_disable_unprepare(c_clks->clks.mdp_core_clk);
+
+	return rc;
 }
 
 static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
index ee39ec7..563285d 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
@@ -408,6 +408,7 @@
 	u32 pixel_clk_khz;
 	enum dsi_op_mode panel_mode;
 	u32 dsi_mode_flags;
+	struct msm_mode_info *mode_info;
 };
 
 #endif /* _DSI_DEFS_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 2c5bd76..86db16e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -260,7 +260,8 @@
 		return rc;
 	}
 
-	rc = dsi_phy_set_ulps(m_ctrl->phy, &display->config, enable);
+	rc = dsi_phy_set_ulps(m_ctrl->phy, &display->config, enable,
+				display->clamp_enabled);
 	if (rc) {
 		pr_err("Ulps PHY state change(%d) failed\n", enable);
 		return rc;
@@ -278,7 +279,8 @@
 			return rc;
 		}
 
-		rc = dsi_phy_set_ulps(ctrl->phy, &display->config, enable);
+		rc = dsi_phy_set_ulps(ctrl->phy, &display->config, enable,
+					display->clamp_enabled);
 		if (rc) {
 			pr_err("Ulps PHY state change(%d) failed\n", enable);
 			return rc;
@@ -1365,13 +1367,17 @@
 		/*
 		 * Enable DSI clamps only if entering idle power collapse.
 		 */
-		if (dsi_panel_initialized(display->panel) &&
-			dsi_panel_ulps_feature_enabled(display->panel)) {
+		if (dsi_panel_initialized(display->panel)) {
 			dsi_display_phy_idle_off(display);
 			rc = dsi_display_set_clamp(display, true);
 			if (rc)
 				pr_err("%s: Failed to enable dsi clamps. rc=%d\n",
 					__func__, rc);
+
+			rc = dsi_display_phy_reset_config(display, false);
+			if (rc)
+				pr_err("%s: Failed to reset phy, rc=%d\n",
+						__func__, rc);
 		} else {
 			/* Make sure that controller is not in ULPS state when
 			 * the DSI link is not active.
@@ -1427,6 +1433,13 @@
 			}
 		}
 
+		rc = dsi_display_phy_reset_config(display, true);
+		if (rc) {
+			pr_err("%s: Failed to reset phy, rc=%d\n",
+						__func__, rc);
+			goto error;
+		}
+
 		rc = dsi_display_set_clamp(display, false);
 		if (rc) {
 			pr_err("%s: Failed to disable dsi clamps. rc=%d\n",
@@ -2972,18 +2985,11 @@
 		goto error_phy_disable;
 	}
 
-	rc = dsi_display_phy_reset_config(display, true);
-	if (rc) {
-		pr_err("[%s] failed to setup DSI controller, rc=%d\n",
-		       display->name, rc);
-		goto error_ctrl_deinit;
-	}
-
 	rc = dsi_display_set_clk_src(display);
 	if (rc) {
 		pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
 			display->name, rc);
-		goto error_phy_reset_off;
+		goto error_ctrl_deinit;
 	}
 
 	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
@@ -2991,7 +2997,7 @@
 	if (rc) {
 		pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
 		       display->name, rc);
-		goto error_phy_reset_off;
+		goto error_ctrl_deinit;
 	}
 
 	rc = dsi_display_ctrl_host_enable(display);
@@ -3014,8 +3020,6 @@
 error_ctrl_link_off:
 	(void)dsi_display_clk_ctrl(display->dsi_clk_handle,
 			DSI_LINK_CLK, DSI_CLK_OFF);
-error_phy_reset_off:
-	(void)dsi_display_phy_reset_config(display, false);
 error_ctrl_deinit:
 	(void)dsi_display_ctrl_deinit(display);
 error_phy_disable:
@@ -3232,11 +3236,6 @@
 		pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
 		       display->name, rc);
 
-	rc = dsi_display_phy_reset_config(display, false);
-	if (rc)
-		pr_err("[%s] failed to disable DSI PHY reset config, rc=%d\n",
-		       display->name, rc);
-
 	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
 			DSI_CORE_CLK, DSI_CLK_OFF);
 	if (rc)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index 556c0d8..3f4bb5a5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -50,6 +50,8 @@
 	dsi_mode->pixel_clk_khz = drm_mode->clock;
 	dsi_mode->panel_mode = 0; /* TODO: Panel Mode */
 
+	dsi_mode->mode_info = (struct msm_mode_info *)drm_mode->private;
+
 	if (msm_is_mode_seamless(drm_mode))
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_SEAMLESS;
 	if (msm_is_mode_dynamic_fps(drm_mode))
@@ -81,6 +83,8 @@
 	drm_mode->vrefresh = dsi_mode->timing.refresh_rate;
 	drm_mode->clock = dsi_mode->pixel_clk_khz;
 
+	drm_mode->private = (int *)dsi_mode->mode_info;
+
 	if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS)
 		drm_mode->flags |= DRM_MODE_FLAG_SEAMLESS;
 	if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS)
@@ -255,6 +259,26 @@
 	return ret;
 }
 
+int dsi_conn_get_topology(const struct drm_display_mode *drm_mode,
+	struct msm_display_topology *topology,
+	u32 max_mixer_width)
+{
+	struct dsi_display_mode dsi_mode;
+
+	if (!drm_mode || !topology)
+		return -EINVAL;
+
+	convert_to_dsi_mode(drm_mode, &dsi_mode);
+
+	if (!dsi_mode.mode_info)
+		return -EINVAL;
+
+	memcpy(topology, &dsi_mode.mode_info->topology,
+			sizeof(struct msm_display_topology));
+
+	return 0;
+}
+
 static const struct drm_bridge_funcs dsi_bridge_ops = {
 	.attach       = dsi_bridge_attach,
 	.mode_fixup   = dsi_bridge_mode_fixup,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index 4339a11..68520a8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -64,6 +64,17 @@
 		void *display);
 
 /**
+ * dsi_conn_get_topology - retrieve current topology for the mode selected
+ * @drm_mode: Display mode set for the display
+ * @topology: Out parameter. Topology for the mode.
+ * @max_mixer_width: max width supported by HW layer mixer
+ * Returns: Zero on success
+ */
+int dsi_conn_get_topology(const struct drm_display_mode *drm_mode,
+	struct msm_display_topology *topology,
+	u32 max_mixer_width);
+
+/**
  * dsi_conn_mode_valid - callback to determine if specified mode is valid
  * @connector: Pointer to drm connector structure
  * @mode: Pointer to drm mode structure
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
index 8250da3..174be9f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
@@ -37,7 +37,7 @@
 	readl_relaxed((dsi_hw)->disp_cc_base + (off))
 #define DSI_DISP_CC_W32(dsi_hw, off, val) \
 	do {\
-		pr_err("[DSI_%d][%s] - [0x%08x]\n", \
+		pr_debug("[DSI_%d][%s] - [0x%08x]\n", \
 			(dsi_hw)->index, #off, val); \
 		writel_relaxed((val), (dsi_hw)->disp_cc_base + (off)); \
 	} while (0)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index bda9c2d..cb4afe4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -20,6 +20,19 @@
 #include "dsi_panel.h"
 #include "dsi_ctrl_hw.h"
 
+#define MAX_CMDLINE_PARAM_LEN 256
+static char display_config[MAX_CMDLINE_PARAM_LEN];
+
+/**
+ * topology is currently defined by a set of following 3 values:
+ * 1. num of layer mixers
+ * 2. num of compression encoders
+ * 3. num of interfaces
+ */
+#define TOPOLOGY_SET_LEN 3
+#define INT_BASE_10 10
+#define MAX_TOPOLOGY 5
+
 #define DSI_PANEL_DEFAULT_LABEL  "Default dsi panel"
 
 #define DEFAULT_MDP_TRANSFER_TIME 14000
@@ -1512,6 +1525,17 @@
 	return rc;
 }
 
+static int dsi_panel_parse_features(struct dsi_panel *panel,
+				     struct device_node *of_node)
+{
+	panel->ulps_enabled =
+		of_property_read_bool(of_node, "qcom,ulps-enabled");
+
+	pr_debug("ulps_enabled:%d\n", panel->ulps_enabled);
+
+	return 0;
+}
+
 static int dsi_panel_parse_jitter_config(struct dsi_panel *panel,
 				     struct device_node *of_node)
 {
@@ -1901,25 +1925,18 @@
 	u32 data;
 	int rc = -EINVAL;
 	int intf_width;
-	struct device_node *dsc_np = NULL;
 
 	if (!panel->dsc_enabled)
 		return 0;
 
-	dsc_np = of_parse_phandle(of_node, "qcom,config-select", 0);
-	if (!dsc_np) {
-		pr_err("no dsc config found\n");
-		goto error;
-	}
-
-	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-slice-height", &data);
+	rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-height", &data);
 	if (rc) {
 		pr_err("failed to parse qcom,mdss-dsc-slice-height\n");
 		goto error;
 	}
 	panel->dsc.slice_height = data;
 
-	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-slice-width", &data);
+	rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-width", &data);
 	if (rc) {
 		pr_err("failed to parse qcom,mdss-dsc-slice-width\n");
 		goto error;
@@ -1935,14 +1952,15 @@
 	panel->dsc.pic_width = panel->mode.timing.h_active;
 	panel->dsc.pic_height = panel->mode.timing.v_active;
 
-	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-slice-per-pkt", &data);
+	rc = of_property_read_u32(of_node, "qcom,mdss-dsc-slice-per-pkt",
+			&data);
 	if (rc) {
 		pr_err("failed to parse qcom,mdss-dsc-slice-per-pkt\n");
 		goto error;
 	}
 	panel->dsc.slice_per_pkt = data;
 
-	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-bit-per-component",
+	rc = of_property_read_u32(of_node, "qcom,mdss-dsc-bit-per-component",
 		&data);
 	if (rc) {
 		pr_err("failed to parse qcom,mdss-dsc-bit-per-component\n");
@@ -1950,14 +1968,15 @@
 	}
 	panel->dsc.bpc = data;
 
-	rc = of_property_read_u32(dsc_np, "qcom,mdss-dsc-bit-per-pixel", &data);
+	rc = of_property_read_u32(of_node, "qcom,mdss-dsc-bit-per-pixel",
+			&data);
 	if (rc) {
 		pr_err("failed to parse qcom,mdss-dsc-bit-per-pixel\n");
 		goto error;
 	}
 	panel->dsc.bpp = data;
 
-	panel->dsc.block_pred_enable = of_property_read_bool(dsc_np,
+	panel->dsc.block_pred_enable = of_property_read_bool(of_node,
 		"qcom,mdss-dsc-block-prediction-enable");
 
 	panel->dsc.full_frame_slices = DIV_ROUND_UP(intf_width,
@@ -2016,6 +2035,112 @@
 	return 0;
 }
 
+static int dsi_get_cmdline_top_override(void)
+{
+	char *str = display_config;
+	int top_index = -1;
+
+	/*
+	 * This module need to be updated with needed cmd line argument parsing
+	 * for other dsi parameters.
+	 */
+	if (strlcat(str, "\0", sizeof(str)) > sizeof(str))
+		return -EINVAL;
+
+	str = strnstr(display_config, "config", strlen(display_config));
+	if (!str)
+		return -EINVAL;
+
+	if (kstrtol(str + strlen("config"), INT_BASE_10,
+				(unsigned long *)&top_index))
+		return -EINVAL;
+
+	return top_index;
+}
+
+static int dsi_panel_parse_topology(struct dsi_panel *panel,
+		struct device_node *of_node)
+{
+	struct msm_display_topology *topology;
+	u32 top_count, top_sel, *array = NULL;
+	int i, len = 0;
+	int rc = -EINVAL;
+
+	len = of_property_count_u32_elems(of_node, "qcom,display-topology");
+	if (len <= 0 || len % TOPOLOGY_SET_LEN ||
+			len > (TOPOLOGY_SET_LEN * MAX_TOPOLOGY)) {
+		pr_err("invalid topology list for the panel, rc = %d\n", rc);
+		return rc;
+	}
+
+	top_count = len / TOPOLOGY_SET_LEN;
+
+	array = kcalloc(len, sizeof(u32), GFP_KERNEL);
+	if (!array)
+		return -ENOMEM;
+
+	rc = of_property_read_u32_array(of_node,
+			"qcom,display-topology", array, len);
+	if (rc) {
+		pr_err("unable to read the display topologies, rc = %d\n", rc);
+		goto read_fail;
+	}
+
+	topology = kcalloc(top_count, sizeof(*topology), GFP_KERNEL);
+	if (!topology) {
+		rc = -ENOMEM;
+		goto read_fail;
+	}
+
+	for (i = 0; i < top_count; i++) {
+		struct msm_display_topology *top = &topology[i];
+
+		top->num_lm = array[i * TOPOLOGY_SET_LEN];
+		top->num_enc = array[i * TOPOLOGY_SET_LEN + 1];
+		top->num_intf = array[i * TOPOLOGY_SET_LEN + 2];
+	};
+
+	top_sel = dsi_get_cmdline_top_override();
+	if (top_sel >= 0 && top_sel < top_count) {
+		pr_info("overidden topology: lm: %d comp_enc:%d intf: %d\n",
+			topology[top_sel].num_lm,
+			topology[top_sel].num_enc,
+			topology[top_sel].num_intf);
+		goto parse_done;
+	}
+
+	rc = of_property_read_u32(of_node,
+			"qcom,default-topology-index", &top_sel);
+	if (rc) {
+		pr_err("no default topology selected, rc = %d\n", rc);
+		goto parse_fail;
+	}
+
+	if (top_sel >= top_count) {
+		rc = -EINVAL;
+		pr_err("default topology is specified is not valid, rc = %d\n",
+			rc);
+		goto parse_fail;
+	}
+
+	pr_info("default topology: lm: %d comp_enc:%d intf: %d\n",
+		topology[top_sel].num_lm,
+		topology[top_sel].num_enc,
+		topology[top_sel].num_intf);
+
+parse_done:
+	panel->mode.mode_info = kzalloc(sizeof(struct msm_mode_info),
+			GFP_KERNEL);
+	memcpy(&panel->mode.mode_info->topology, &topology[top_sel],
+		sizeof(struct msm_display_topology));
+parse_fail:
+	kfree(topology);
+read_fail:
+	kfree(array);
+
+	return rc;
+}
+
 struct dsi_panel *dsi_panel_get(struct device *parent,
 				struct device_node *of_node)
 {
@@ -2073,6 +2198,13 @@
 	panel->mode.pixel_clk_khz = (DSI_H_TOTAL(&panel->mode.timing) *
 				    DSI_V_TOTAL(&panel->mode.timing) *
 				    panel->mode.timing.refresh_rate) / 1000;
+
+	rc = dsi_panel_parse_topology(panel, of_node);
+	if (rc) {
+		pr_err("failed to parse panel topology, rc=%d\n", rc);
+		goto error;
+	}
+
 	rc = dsi_panel_parse_host_config(panel, of_node);
 	if (rc) {
 		pr_err("failed to parse host configuration, rc=%d\n", rc);
@@ -2117,6 +2249,10 @@
 	if (rc)
 		pr_err("failed to parse panel jitter config, rc=%d\n", rc);
 
+	rc = dsi_panel_parse_features(panel, of_node);
+	if (rc)
+		pr_err("failed to parse panel features, rc=%d\n", rc);
+
 	rc = dsi_panel_parse_hdr_config(panel, of_node);
 	if (rc)
 		pr_err("failed to parse hdr config, rc=%d\n", rc);
@@ -2138,6 +2274,8 @@
 	for (i = 0; i < DSI_CMD_SET_MAX; i++)
 		dsi_panel_destroy_cmd_packets(&panel->cmd_sets[i]);
 
+	kfree(panel->mode.mode_info);
+
 	/* TODO:  more free */
 	kfree(panel);
 }
@@ -2490,7 +2628,6 @@
 		       panel->name, rc);
 		goto error;
 	}
-	panel->panel_initialized = false;
 error:
 	mutex_unlock(&panel->panel_lock);
 	return rc;
@@ -2536,6 +2673,8 @@
 		       panel->name, rc);
 		goto error;
 	}
+	panel->panel_initialized = false;
+
 error:
 	mutex_unlock(&panel->panel_lock);
 	return rc;
@@ -2595,3 +2734,6 @@
 	mutex_unlock(&panel->panel_lock);
 	return rc;
 }
+
+module_param_string(display_param, display_config, MAX_CMDLINE_PARAM_LEN, 0600);
+MODULE_PARM_DESC(display_param, "format: configx - x indexes the selected topology from the display topology list. Index 0 corresponds to the first topology in the list");
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index cdc1ff6..ebfb40b8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -669,7 +669,7 @@
 }
 
 static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy,
-		struct dsi_host_config *config)
+		struct dsi_host_config *config, bool clamp_enabled)
 {
 	int rc = 0;
 	u32 lanes = 0;
@@ -679,17 +679,25 @@
 		lanes = config->common_config.data_lanes;
 	lanes |= DSI_CLOCK_LANE;
 
-	rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
-	if (rc) {
-		pr_err("lanes not entering idle, skip ULPS\n");
-		return rc;
+	/*
+	 * If DSI clamps are enabled, it means that the DSI lanes are
+	 * already in idle state. Checking for lanes to be in idle state
+	 * should be skipped during ULPS entry programming while coming
+	 * out of idle screen.
+	 */
+	if (!clamp_enabled) {
+		rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
+		if (rc) {
+			pr_err("lanes not entering idle, skip ULPS\n");
+			return rc;
+		}
 	}
 
 	phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
 
 	ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
 
-	if ((lanes & ulps_lanes) != lanes) {
+	if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
 		pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
 		       lanes, ulps_lanes);
 		rc = -EIO;
@@ -701,7 +709,6 @@
 static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
 		 struct dsi_host_config *config)
 {
-	int rc = 0;
 	u32 ulps_lanes, lanes = 0;
 
 	if (config->panel_mode == DSI_OP_CMD_MODE)
@@ -710,25 +717,27 @@
 
 	ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
 
-	if ((lanes & ulps_lanes) != lanes)
-		pr_err("Mismatch between lanes in ULPS\n");
-
-	lanes &= ulps_lanes;
+	if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
+		pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
+				lanes, ulps_lanes);
+		return -EIO;
+	}
 
 	phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
 
 	ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
-	if (ulps_lanes & lanes) {
+
+	if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
 		pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
-		rc = -EIO;
+		return -EIO;
 	}
 
-	return rc;
+	return 0;
 }
 
 
 int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
-		bool enable)
+		bool enable, bool clamp_enabled)
 {
 	int rc = 0;
 
@@ -738,7 +747,10 @@
 	}
 
 	if (!phy->hw.ops.ulps_ops.ulps_request ||
-			!phy->hw.ops.ulps_ops.ulps_exit) {
+			!phy->hw.ops.ulps_ops.ulps_exit ||
+			!phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
+			!phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
+			!phy->hw.ops.ulps_ops.wait_for_lane_idle) {
 		pr_debug("DSI PHY ULPS ops not present\n");
 		return 0;
 	}
@@ -746,7 +758,7 @@
 	mutex_lock(&phy->phy_lock);
 
 	if (enable)
-		rc = dsi_phy_enable_ulps(phy, config);
+		rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
 	else
 		rc = dsi_phy_disable_ulps(phy, config);
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
index 4a64855..e721486 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
@@ -182,11 +182,12 @@
  * @phy:          DSI PHY handle
  * @config:	  DSi host configuration information.
  * @enable:	  Enable/Disable
+ * @clamp_enabled: mmss_clamp enabled/disabled
  *
  * Return: error code.
  */
 int dsi_phy_set_ulps(struct msm_dsi_phy *phy,  struct dsi_host_config *config,
-		bool enable);
+		bool enable, bool clamp_enabled);
 
 /**
  * dsi_phy_clk_cb_register() - Register PHY clock control callback
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
index daaa78a..51c2f46 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
@@ -143,15 +143,22 @@
 	 * @phy:           Pointer to DSI PHY hardware instance.
 	 *
 	 * Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS
-	 * state. If 0 is returned, all the lanes are active.
+	 * state.
 	 *
 	 * Return: List of lanes in ULPS state.
 	 */
 	u32 (*get_lanes_in_ulps)(struct dsi_phy_hw *phy);
+
+	/**
+	 * is_lanes_in_ulps() - checks if the given lanes are in ulps
+	 * @lanes:           lanes to be checked.
+	 * @ulps_lanes:	   lanes in ulps currenly.
+	 *
+	 * Return: true if all the given lanes are in ulps; false otherwise.
+	 */
+	bool (*is_lanes_in_ulps)(u32 ulps, u32 ulps_lanes);
 };
 
-
-
 /**
  * struct dsi_phy_hw_ops - Operations for DSI PHY hardware.
  * @regulator_enable:          Enable PHY regulators.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
index 6a3dad8..371239d 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
@@ -423,6 +423,14 @@
 	return lanes;
 }
 
+bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes)
+{
+	if (lanes & ulps_lanes)
+		return false;
+
+	return true;
+}
+
 int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
 		u32 *timing_val, u32 size)
 {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 4471d0b..64e9544 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -164,6 +164,7 @@
 	/* enum/bitmask properties */
 	CONNECTOR_PROP_TOPOLOGY_NAME,
 	CONNECTOR_PROP_TOPOLOGY_CONTROL,
+	CONNECTOR_PROP_AUTOREFRESH,
 
 	/* total # of properties */
 	CONNECTOR_PROP_COUNT
@@ -353,6 +354,26 @@
 };
 
 /**
+ * struct msm_display_topology - defines a display topology pipeline
+ * @num_lm:       number of layer mixers used
+ * @num_enc:      number of compression encoder blocks used
+ * @num_intf:     number of interfaces the panel is mounted on
+ */
+struct msm_display_topology {
+	u32 num_lm;
+	u32 num_enc;
+	u32 num_intf;
+};
+
+/**
+ * struct msm_mode_info - defines all msm custom mode info
+ * @topology - supported topology for the mode
+ */
+struct msm_mode_info {
+	struct msm_display_topology topology;
+};
+
+/**
  * struct msm_display_info - defines display properties
  * @intf_type:          DRM_MODE_CONNECTOR_ display type
  * @capabilities:       Bitmask of display flags
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index e3f8261..9f8d7ee 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -21,6 +21,9 @@
 
 #define BL_NODE_NAME_SIZE 32
 
+/* Autorefresh will occur after FRAME_CNT frames. Large values are unlikely */
+#define AUTOREFRESH_MAX_FRAME_CNT 6
+
 #define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
 		(c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
 
@@ -990,6 +993,10 @@
 	msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
 			0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
 
+	msm_property_install_range(&c_conn->property_info, "autorefresh",
+			0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0,
+			CONNECTOR_PROP_AUTOREFRESH);
+
 	/* enum/bitmask properties */
 	msm_property_install_enum(&c_conn->property_info, "topology_name",
 			DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name,
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 601299e..c8c0eed 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -121,6 +121,17 @@
 	int (*get_info)(struct msm_display_info *info, void *display);
 
 	/**
+	 * get_topology - retrieve current topology for the mode selected
+	 * @drm_mode: Display mode set for the display
+	 * @topology: Out parameter. Topology for the mode.
+	 * @max_mixer_width: max width supported by HW layer mixer
+	 * Returns: Zero on success
+	 */
+	int (*get_topology)(const struct drm_display_mode *drm_mode,
+			struct msm_display_topology *topology,
+			u32 max_mixer_width);
+
+	/**
 	 * enable_event - notify display of event registration/unregistration
 	 * @connector: Pointer to drm connector structure
 	 * @event_idx: SDE connector event index
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 6bae083..f2d78cb 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -808,6 +808,44 @@
 	return 0;
 }
 
+static int _sde_crtc_check_autorefresh(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *crtc_state;
+	struct drm_connector *conn;
+	struct drm_connector_state *conn_state;
+	int i;
+
+	if (!crtc || !state)
+		return -EINVAL;
+
+	sde_crtc = to_sde_crtc(crtc);
+	crtc_state = to_sde_crtc_state(state);
+
+	if (sde_kms_rect_is_null(&crtc_state->crtc_roi))
+		return 0;
+
+	/* partial update active, check if autorefresh is also requested */
+	for_each_connector_in_state(state->state, conn, conn_state, i) {
+		uint64_t autorefresh;
+
+		if (!conn_state || conn_state->crtc != crtc)
+			continue;
+
+		autorefresh = sde_connector_get_property(conn_state,
+				CONNECTOR_PROP_AUTOREFRESH);
+		if (autorefresh) {
+			SDE_ERROR(
+				"%s: autorefresh & partial crtc roi incompatible %llu\n",
+					sde_crtc->name, autorefresh);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
 		struct drm_crtc_state *state, int lm_idx)
 {
@@ -953,6 +991,10 @@
 	if (rc)
 		return rc;
 
+	rc = _sde_crtc_check_autorefresh(crtc, state);
+	if (rc)
+		return rc;
+
 	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
 		rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
 		if (rc)
@@ -2074,6 +2116,33 @@
 	crtc->state = &cstate->base;
 }
 
+static int _sde_crtc_vblank_no_lock(struct sde_crtc *sde_crtc, bool en)
+{
+	if (!sde_crtc) {
+		SDE_ERROR("invalid crtc\n");
+		return -EINVAL;
+	} else if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) {
+		SDE_DEBUG("crtc%d vblank enable\n", sde_crtc->base.base.id);
+		if (!sde_crtc->suspend)
+			_sde_crtc_vblank_enable_nolock(sde_crtc, true);
+	} else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) {
+		SDE_ERROR("crtc%d invalid vblank disable\n",
+				sde_crtc->base.base.id);
+		return -EINVAL;
+	} else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) {
+		SDE_DEBUG("crtc%d vblank disable\n", sde_crtc->base.base.id);
+		if (!sde_crtc->suspend)
+			_sde_crtc_vblank_enable_nolock(sde_crtc, false);
+	} else {
+		SDE_DEBUG("crtc%d vblank %s refcount:%d\n",
+				sde_crtc->base.base.id,
+				en ? "enable" : "disable",
+				atomic_read(&sde_crtc->vblank_refcount));
+	}
+
+	return 0;
+}
+
 static void sde_crtc_disable(struct drm_crtc *crtc)
 {
 	struct sde_crtc *sde_crtc;
@@ -2103,13 +2172,9 @@
 				crtc->base.id);
 		SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->vblank_refcount),
 							SDE_EVTLOG_FUNC_CASE1);
-		drm_for_each_encoder(encoder, crtc->dev) {
-			if (encoder->crtc != crtc)
-				continue;
-			sde_encoder_register_vblank_callback(encoder, NULL,
-						NULL);
-		}
-		atomic_set(&sde_crtc->vblank_refcount, 0);
+		while (atomic_read(&sde_crtc->vblank_refcount))
+			if (_sde_crtc_vblank_no_lock(sde_crtc, false))
+				break;
 	}
 
 	if (atomic_read(&sde_crtc->frame_pending)) {
@@ -2463,7 +2528,7 @@
 int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
 {
 	struct sde_crtc *sde_crtc;
-	int rc = 0;
+	int rc;
 
 	if (!crtc) {
 		SDE_ERROR("invalid crtc\n");
@@ -2472,25 +2537,9 @@
 	sde_crtc = to_sde_crtc(crtc);
 
 	mutex_lock(&sde_crtc->crtc_lock);
-	if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) {
-		SDE_DEBUG("crtc%d vblank enable\n", crtc->base.id);
-		if (!sde_crtc->suspend)
-			_sde_crtc_vblank_enable_nolock(sde_crtc, true);
-	} else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) {
-		SDE_ERROR("crtc%d invalid vblank disable\n", crtc->base.id);
-		rc = -EINVAL;
-	} else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) {
-		SDE_DEBUG("crtc%d vblank disable\n", crtc->base.id);
-		if (!sde_crtc->suspend)
-			_sde_crtc_vblank_enable_nolock(sde_crtc, false);
-	} else {
-		SDE_DEBUG("crtc%d vblank %s refcount:%d\n",
-				crtc->base.id,
-				en ? "enable" : "disable",
-				atomic_read(&sde_crtc->vblank_refcount));
-	}
-
+	rc = _sde_crtc_vblank_no_lock(sde_crtc, en);
 	mutex_unlock(&sde_crtc->crtc_lock);
+
 	return rc;
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 7ad0955..98ba711 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -316,6 +316,21 @@
 }
 
 /**
+ * sde_crtc_frame_pending - retun the number of pending frames
+ * @crtc: Pointer to drm crtc object
+ */
+static inline int sde_crtc_frame_pending(struct drm_crtc *crtc)
+{
+	struct sde_crtc *sde_crtc;
+
+	if (!crtc)
+		return -EINVAL;
+
+	sde_crtc = to_sde_crtc(crtc);
+	return atomic_read(&sde_crtc->frame_pending);
+}
+
+/**
  * sde_crtc_vblank - enable or disable vblanks for this crtc
  * @crtc: Pointer to drm crtc object
  * @en: true to enable vblanks, false to disable
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 8c41b12..3357642 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -34,6 +34,7 @@
 #include "sde_encoder_phys.h"
 #include "sde_power_handle.h"
 #include "sde_hw_dsc.h"
+#include "sde_crtc.h"
 
 #define SDE_DEBUG_ENC(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\
 		(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
@@ -58,6 +59,56 @@
 
 #define MISR_BUFF_SIZE			256
 
+#define IDLE_TIMEOUT	64
+
+/**
+ * enum sde_enc_rc_events - events for resource control state machine
+ * @SDE_ENC_RC_EVENT_KICKOFF:
+ *	This event happens at NORMAL priority.
+ *	Event that signals the start of the transfer. When this event is
+ *	received, enable MDP/DSI core clocks and request RSC with CMD state.
+ *	Regardless of the previous state, the resource should be in ON state
+ *	at the end of this event.
+ * @SDE_ENC_RC_EVENT_FRAME_DONE:
+ *	This event happens at INTERRUPT level.
+ *	Event signals the end of the data transfer after the PP FRAME_DONE
+ *	event. At the end of this event, a delayed work is scheduled to go to
+ *	IDLE_PC state after IDLE_TIMEOUT time.
+ * @SDE_ENC_RC_EVENT_STOP:
+ *	This event happens at NORMAL priority.
+ *	When this event is received, disable all the MDP/DSI core clocks
+ *	and request RSC with IDLE state. Resource state should be in OFF
+ *	at the end of the event.
+ * @SDE_ENC_RC_EARLY_WAKEUP
+ *	This event happens at NORMAL priority from a work item.
+ *	Event signals that there will be frame update soon and the driver should
+ *	wake up early to update the frame with minimum latency.
+ * @SDE_ENC_RC_EVENT_ENTER_IDLE:
+ *	This event happens at NORMAL priority from a work item.
+ *	Event signals that there were no frame updates for IDLE_TIMEOUT time.
+ *	This would disable MDP/DSI core clocks and request RSC with IDLE state
+ *	and change the resource state to IDLE.
+ */
+enum sde_enc_rc_events {
+	SDE_ENC_RC_EVENT_KICKOFF = 1,
+	SDE_ENC_RC_EVENT_FRAME_DONE,
+	SDE_ENC_RC_EVENT_STOP,
+	SDE_ENC_RC_EVENT_EARLY_WAKE_UP,
+	SDE_ENC_RC_EVENT_ENTER_IDLE
+};
+
+/*
+ * enum sde_enc_rc_states - states that the resource control maintains
+ * @SDE_ENC_RC_STATE_OFF: Resource is in OFF state
+ * @SDE_ENC_RC_STATE_ON: Resource is in ON state
+ * @SDE_ENC_RC_STATE_IDLE: Resource is in IDLE state
+ */
+enum sde_enc_rc_states {
+	SDE_ENC_RC_STATE_OFF,
+	SDE_ENC_RC_STATE_ON,
+	SDE_ENC_RC_STATE_IDLE
+};
+
 /**
  * struct sde_encoder_virt - virtual encoder. Container of one or more physical
  *	encoders. Virtual encoder manages one "logical" display. Physical
@@ -91,7 +142,16 @@
  * @crtc_frame_event:		callback event
  * @frame_done_timeout:		frame done timeout in Hz
  * @frame_done_timer:		watchdog timer for frame done event
+ * @rsc_client:			rsc client pointer
+ * @rsc_state_init:		boolean to indicate rsc config init
+ * @disp_info:			local copy of msm_display_info struct
  * @misr_enable:		misr enable/disable status
+ * @idle_pc_supported:		indicate if idle power collaps is supported
+ * @rc_lock:			resource control mutex lock to protect
+ *				virt encoder over various state changes
+ * @rc_state:			resource controller state
+ * @delayed_off_work:		delayed worker to schedule disabling of
+ *				clks and resources after IDLE_TIMEOUT time.
  */
 struct sde_encoder_virt {
 	struct drm_encoder base;
@@ -120,9 +180,14 @@
 	struct timer_list frame_done_timer;
 
 	struct sde_rsc_client *rsc_client;
+	bool rsc_state_init;
 	struct msm_display_info disp_info;
-	bool rsc_state_update;
 	bool misr_enable;
+
+	bool idle_pc_supported;
+	struct mutex rc_lock;
+	enum sde_enc_rc_states rc_state;
+	struct delayed_work delayed_off_work;
 };
 
 #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -284,6 +349,24 @@
 	}
 }
 
+static void _sde_encoder_adjust_mode(struct drm_connector *connector,
+		struct drm_display_mode *adj_mode)
+{
+	struct drm_display_mode *cur_mode;
+
+	if (!connector || !adj_mode)
+		return;
+
+	list_for_each_entry(cur_mode, &connector->modes, head) {
+		if (cur_mode->vdisplay == adj_mode->vdisplay &&
+			cur_mode->hdisplay == adj_mode->hdisplay &&
+			cur_mode->vrefresh == adj_mode->vrefresh) {
+			adj_mode->private = cur_mode->private;
+			adj_mode->private_flags = cur_mode->private_flags;
+		}
+	}
+}
+
 static int sde_encoder_virt_atomic_check(
 		struct drm_encoder *drm_enc,
 		struct drm_crtc_state *crtc_state,
@@ -312,6 +395,15 @@
 	adj_mode = &crtc_state->adjusted_mode;
 	SDE_EVT32(DRMID(drm_enc));
 
+	/*
+	 * display drivers may populate private fields of the drm display mode
+	 * structure while registering possible modes of a connector with DRM.
+	 * These private fields are not populated back while DRM invokes
+	 * the mode_set callbacks. This module retrieves and populates the
+	 * private fields of the given mode.
+	 */
+	_sde_encoder_adjust_mode(conn_state->connector, adj_mode);
+
 	/* perform atomic check on the first physical encoder (master) */
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
@@ -673,6 +765,11 @@
 	sde_enc = to_sde_encoder_virt(drm_enc);
 	disp_info = &sde_enc->disp_info;
 
+	if (!sde_enc->rsc_client) {
+		SDE_DEBUG("rsc client not created\n");
+		return 0;
+	}
+
 	/**
 	 * only primary command mode panel can request CMD state.
 	 * all other panels/displays can request for VID state including
@@ -683,14 +780,14 @@
 		  disp_info->is_primary) ? SDE_RSC_CMD_STATE :
 		SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
 
-	if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_update
+	if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_init
 					&& disp_info->is_primary) {
 		rsc_config.fps = disp_info->frame_rate;
 		rsc_config.vtotal = disp_info->vtotal;
 		rsc_config.prefill_lines = disp_info->prefill_lines;
 		rsc_config.jitter = disp_info->jitter;
 		/* update it only once */
-		sde_enc->rsc_state_update = true;
+		sde_enc->rsc_state_init = true;
 
 		ret = sde_rsc_client_state_update(sde_enc->rsc_client,
 			rsc_state, &rsc_config,
@@ -721,6 +818,277 @@
 	return disp_info->is_primary ? sde_enc->rsc_client : NULL;
 }
 
+static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
+		bool enable)
+{
+	struct msm_drm_private *priv;
+	struct sde_kms *sde_kms;
+	struct sde_encoder_virt *sde_enc;
+	int i;
+
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	priv = drm_enc->dev->dev_private;
+	sde_kms = to_sde_kms(priv->kms);
+
+	SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable);
+	SDE_EVT32(DRMID(drm_enc), enable);
+
+	if (!sde_enc->cur_master) {
+		SDE_ERROR("encoder master not set\n");
+		return;
+	}
+
+	if (enable) {
+		/* enable SDE core clks */
+		sde_power_resource_enable(&priv->phandle,
+				sde_kms->core_client, true);
+
+		/* enable DSI clks */
+		sde_connector_clk_ctrl(sde_enc->cur_master->connector, true);
+
+		/* enable all the irq */
+		for (i = 0; i < sde_enc->num_phys_encs; i++) {
+			struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+			if (phys && phys->ops.irq_control)
+				phys->ops.irq_control(phys, true);
+		}
+
+		/* enable RSC */
+		sde_encoder_update_rsc_client(drm_enc, true);
+
+	} else {
+
+		/* disable RSC */
+		sde_encoder_update_rsc_client(drm_enc, false);
+
+		/* disable all the irq */
+		for (i = 0; i < sde_enc->num_phys_encs; i++) {
+			struct sde_encoder_phys *phys =
+						sde_enc->phys_encs[i];
+
+			if (phys && phys->ops.irq_control)
+				phys->ops.irq_control(phys, false);
+		}
+
+		/* disable DSI clks */
+		sde_connector_clk_ctrl(sde_enc->cur_master->connector, false);
+
+		/* disable SDE core clks */
+		sde_power_resource_enable(&priv->phandle,
+				sde_kms->core_client, false);
+	}
+
+}
+
+static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
+		u32 sw_event)
+{
+	bool schedule_off = false;
+	struct sde_encoder_virt *sde_enc;
+
+	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
+		SDE_ERROR("invalid parameters\n");
+		return -EINVAL;
+	}
+	sde_enc = to_sde_encoder_virt(drm_enc);
+
+	/*
+	 * when idle_pc is not supported, process only KICKOFF and STOP
+	 * event and return early for other events (ie video mode).
+	 */
+	if (!sde_enc->idle_pc_supported &&
+			(sw_event != SDE_ENC_RC_EVENT_KICKOFF &&
+				sw_event != SDE_ENC_RC_EVENT_STOP))
+		return 0;
+
+	SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc_supported:%d\n", sw_event,
+			sde_enc->idle_pc_supported);
+	SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported,
+			sde_enc->rc_state, SDE_EVTLOG_FUNC_ENTRY);
+
+	switch (sw_event) {
+	case SDE_ENC_RC_EVENT_KICKOFF:
+		/* cancel delayed off work, if any */
+		if (cancel_delayed_work_sync(&sde_enc->delayed_off_work))
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
+					sw_event);
+
+		mutex_lock(&sde_enc->rc_lock);
+
+		/* return if the resource control is already in ON state */
+		if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON) {
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in ON state\n",
+					sw_event);
+			mutex_unlock(&sde_enc->rc_lock);
+			return 0;
+		}
+
+		/* enable all the clks and resources */
+		_sde_encoder_resource_control_helper(drm_enc, true);
+
+		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+				SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1);
+		sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
+
+		mutex_unlock(&sde_enc->rc_lock);
+		break;
+
+	case SDE_ENC_RC_EVENT_FRAME_DONE:
+		/*
+		 * mutex lock is not used as this event happens at interrupt
+		 * context. And locking is not required as, the other events
+		 * like KICKOFF and STOP does a wait-for-idle before executing
+		 * the resource_control
+		 */
+		if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
+			SDE_ERROR_ENC(sde_enc, "sw_event:%d,rc:%d-unexpected\n",
+					sw_event, sde_enc->rc_state);
+			return -EINVAL;
+		}
+
+		/*
+		 * schedule off work item only when there are no
+		 * frames pending
+		 */
+		if (sde_crtc_frame_pending(drm_enc->crtc) > 1) {
+			SDE_DEBUG_ENC(sde_enc, "skip schedule work");
+			return 0;
+		}
+
+		/* schedule delayed off work */
+		schedule_delayed_work(&sde_enc->delayed_off_work,
+					msecs_to_jiffies(IDLE_TIMEOUT));
+		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+				SDE_EVTLOG_FUNC_CASE2);
+		SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
+				sw_event);
+		break;
+
+	case SDE_ENC_RC_EVENT_STOP:
+		/* cancel delayed off work, if any */
+		if (cancel_delayed_work_sync(&sde_enc->delayed_off_work))
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
+					sw_event);
+
+		mutex_lock(&sde_enc->rc_lock);
+
+		/* return if the resource control is already in OFF state */
+		if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
+					sw_event);
+			mutex_unlock(&sde_enc->rc_lock);
+			return 0;
+		}
+
+		/*
+		 * disable the clks and resources only if the resource control
+		 * is in ON state, otherwise the clks and resources would have
+		 * been disabled while going into IDLE state
+		 */
+		if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON)
+			_sde_encoder_resource_control_helper(drm_enc, false);
+
+		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+				SDE_ENC_RC_STATE_OFF, SDE_EVTLOG_FUNC_CASE3);
+		sde_enc->rc_state = SDE_ENC_RC_STATE_OFF;
+
+		mutex_unlock(&sde_enc->rc_lock);
+		break;
+
+	case SDE_ENC_RC_EVENT_EARLY_WAKE_UP:
+		/* cancel delayed off work, if any */
+		if (cancel_delayed_work_sync(&sde_enc->delayed_off_work)) {
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n",
+					sw_event);
+			schedule_off = true;
+		}
+
+		mutex_lock(&sde_enc->rc_lock);
+
+		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+				schedule_off, SDE_EVTLOG_FUNC_CASE4);
+
+		/* return if the resource control is in OFF state */
+		if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) {
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n",
+					sw_event);
+			mutex_unlock(&sde_enc->rc_lock);
+			return 0;
+		}
+
+		/*
+		 * enable all the clks and resources if resource control is
+		 * coming out of IDLE state
+		 */
+		if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
+			_sde_encoder_resource_control_helper(drm_enc, true);
+			sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
+			schedule_off = true;
+		}
+
+		/*
+		 * schedule off work when there are no frames pending and
+		 * 1. early wakeup cancelled off work
+		 * 2. early wakeup changed the rc_state to ON - this is to
+		 *	handle cases where early wakeup is called but no
+		 *	frame updates
+		 */
+		if (schedule_off && !sde_crtc_frame_pending(drm_enc->crtc)) {
+			/* schedule delayed off work */
+			schedule_delayed_work(&sde_enc->delayed_off_work,
+					msecs_to_jiffies(IDLE_TIMEOUT));
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n",
+					sw_event);
+		}
+
+		mutex_unlock(&sde_enc->rc_lock);
+		break;
+
+	case SDE_ENC_RC_EVENT_ENTER_IDLE:
+		mutex_lock(&sde_enc->rc_lock);
+
+		if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
+			SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
+					sw_event, sde_enc->rc_state);
+			mutex_unlock(&sde_enc->rc_lock);
+			return 0;
+		}
+
+		/* disable all the clks and resources */
+		_sde_encoder_resource_control_helper(drm_enc, false);
+		SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
+				SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE5);
+		sde_enc->rc_state = SDE_ENC_RC_STATE_IDLE;
+
+		mutex_unlock(&sde_enc->rc_lock);
+		break;
+
+	default:
+		SDE_ERROR("unexpected sw_event: %d\n", sw_event);
+		break;
+	}
+
+	SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported,
+			sde_enc->rc_state, SDE_EVTLOG_FUNC_EXIT);
+	return 0;
+}
+
+static void sde_encoder_off_work(struct work_struct *work)
+{
+	struct delayed_work *dw = to_delayed_work(work);
+	struct sde_encoder_virt *sde_enc = container_of(dw,
+			struct sde_encoder_virt, delayed_off_work);
+
+	if (!sde_enc) {
+		SDE_ERROR("invalid sde encoder\n");
+		return;
+	}
+
+	sde_encoder_resource_control(&sde_enc->base,
+			SDE_ENC_RC_EVENT_ENTER_IDLE);
+}
+
 static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
 				      struct drm_display_mode *mode,
 				      struct drm_display_mode *adj_mode)
@@ -804,6 +1172,8 @@
 static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
 {
 	struct sde_encoder_virt *sde_enc = NULL;
+	struct msm_drm_private *priv;
+	struct sde_kms *sde_kms;
 	int i = 0;
 	int ret = 0;
 
@@ -819,37 +1189,56 @@
 	}
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
+	priv = drm_enc->dev->dev_private;
+	sde_kms = to_sde_kms(priv->kms);
+
+	if (!sde_kms) {
+		SDE_ERROR("invalid sde_kms\n");
+		return;
+	}
 
 	SDE_DEBUG_ENC(sde_enc, "\n");
 	SDE_EVT32(DRMID(drm_enc));
 
-	ret = _sde_encoder_power_enable(sde_enc, true);
-	if (ret)
-		return;
-
 	sde_enc->cur_master = NULL;
+	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+		if (phys && phys->ops.is_master && phys->ops.is_master(phys)) {
+			SDE_DEBUG_ENC(sde_enc, "master is now idx %d\n", i);
+			sde_enc->cur_master = phys;
+			break;
+		}
+	}
+
+	if (!sde_enc->cur_master) {
+		SDE_ERROR("virt encoder has no master! num_phys %d\n", i);
+		return;
+	}
+
+	ret = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF);
+	if (ret) {
+		SDE_ERROR_ENC(sde_enc, "sde resource control failed: %d\n",
+				ret);
+		return;
+	}
 
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
-		if (phys) {
-			if (phys->ops.is_master && phys->ops.is_master(phys)) {
-				SDE_DEBUG_ENC(sde_enc,
-						"master is now idx %d\n", i);
-				sde_enc->cur_master = phys;
-			} else if (phys->ops.enable) {
-				phys->ops.enable(phys);
-			}
-		}
+		if (phys && (phys != sde_enc->cur_master) && phys->ops.enable)
+			phys->ops.enable(phys);
 	}
 
-	sde_encoder_update_rsc_client(drm_enc, true);
-
-	if (!sde_enc->cur_master)
-		SDE_ERROR("virt encoder has no master! num_phys %d\n", i);
-	else if (sde_enc->cur_master->ops.enable)
+	if (sde_enc->cur_master && sde_enc->cur_master->ops.enable)
 		sde_enc->cur_master->ops.enable(sde_enc->cur_master);
 
+	if (sde_enc->cur_master && sde_enc->cur_master->hw_mdptop &&
+			sde_enc->cur_master->hw_mdptop->ops.reset_ubwc)
+		sde_enc->cur_master->hw_mdptop->ops.reset_ubwc(
+				sde_enc->cur_master->hw_mdptop,
+				sde_kms->catalog);
+
 	if (_sde_is_dsc_enabled(sde_enc)) {
 		ret = _sde_encoder_dsc_setup(sde_enc);
 		if (ret)
@@ -887,9 +1276,8 @@
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
-		if (phys) {
-			if (phys->ops.disable && !phys->ops.is_master(phys))
-				phys->ops.disable(phys);
+		if (phys && phys->ops.disable && !phys->ops.is_master(phys)) {
+			phys->ops.disable(phys);
 			phys->connector = NULL;
 		}
 	}
@@ -900,17 +1288,19 @@
 		del_timer_sync(&sde_enc->frame_done_timer);
 	}
 
-	sde_encoder_update_rsc_client(drm_enc, false);
-
 	if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
 		sde_enc->cur_master->ops.disable(sde_enc->cur_master);
 
-	sde_enc->cur_master = NULL;
-	SDE_DEBUG_ENC(sde_enc, "cleared master\n");
+	sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_STOP);
+
+	if (sde_enc->cur_master) {
+		sde_enc->cur_master->connector = NULL;
+		sde_enc->cur_master = NULL;
+	}
+
+	SDE_DEBUG_ENC(sde_enc, "encoder disabled\n");
 
 	sde_rm_release(&sde_kms->rm, drm_enc);
-
-	_sde_encoder_power_enable(sde_enc, false);
 }
 
 static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
@@ -1039,6 +1429,9 @@
 		atomic_set(&sde_enc->frame_done_timeout, 0);
 		del_timer(&sde_enc->frame_done_timer);
 
+		sde_encoder_resource_control(drm_enc,
+				SDE_ENC_RC_EVENT_FRAME_DONE);
+
 		if (sde_enc->crtc_frame_event_cb)
 			sde_enc->crtc_frame_event_cb(
 					sde_enc->crtc_frame_event_cb_data,
@@ -1281,6 +1674,8 @@
 		}
 	}
 
+	sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF);
+
 	/* if any phys needs reset, reset all phys, in-order */
 	if (needs_hw_reset) {
 		for (i = 0; i < sde_enc->num_phys_encs; i++) {
@@ -1771,6 +2166,9 @@
 
 	phys_params.comp_type = disp_info->comp_info.comp_type;
 
+	if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
+		sde_enc->idle_pc_supported = sde_kms->catalog->has_idle_pc;
+
 	mutex_lock(&sde_enc->enc_lock);
 	for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) {
 		/*
@@ -1931,6 +2329,9 @@
 		sde_enc->rsc_client = NULL;
 	}
 
+	mutex_init(&sde_enc->rc_lock);
+	INIT_DELAYED_WORK(&sde_enc->delayed_off_work, sde_encoder_off_work);
+
 	memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info));
 
 	SDE_DEBUG_ENC(sde_enc, "created\n");
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index da155b0..6942292 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -117,6 +117,7 @@
  * @collect_misr:		Collects MISR data on frame update
  * @hw_reset:			Issue HW recovery such as CTL reset and clear
  *				SDE_ENC_ERR_NEEDS_HW_RESET state
+ * @irq_control:		Handler to enable/disable all the encoder IRQs
  */
 
 struct sde_encoder_phys_ops {
@@ -150,6 +151,7 @@
 				bool enable, u32 frame_count);
 	u32 (*collect_misr)(struct sde_encoder_phys *phys_enc);
 	void (*hw_reset)(struct sde_encoder_phys *phys_enc);
+	void (*irq_control)(struct sde_encoder_phys *phys, bool enable);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 5b59828..a4f40f2 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -363,6 +363,78 @@
 	return 0;
 }
 
+static int sde_encoder_phys_cmd_control_vblank_irq(
+		struct sde_encoder_phys *phys_enc,
+		bool enable)
+{
+	struct sde_encoder_phys_cmd *cmd_enc =
+		to_sde_encoder_phys_cmd(phys_enc);
+	int ret = 0;
+
+	if (!phys_enc) {
+		SDE_ERROR("invalid encoder\n");
+		return -EINVAL;
+	}
+
+	/* Slave encoders don't report vblank */
+	if (!sde_encoder_phys_cmd_is_master(phys_enc))
+		goto end;
+
+	SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n",
+			__builtin_return_address(0),
+			enable, atomic_read(&phys_enc->vblank_refcount));
+
+	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
+			enable, atomic_read(&phys_enc->vblank_refcount));
+
+	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
+		ret = sde_encoder_phys_cmd_register_irq(phys_enc,
+				SDE_IRQ_TYPE_PING_PONG_RD_PTR,
+				INTR_IDX_RDPTR,
+				sde_encoder_phys_cmd_pp_rd_ptr_irq,
+				"pp_rd_ptr");
+	else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
+		ret = sde_encoder_phys_cmd_unregister_irq(phys_enc,
+				INTR_IDX_RDPTR);
+
+end:
+	if (ret)
+		SDE_ERROR_CMDENC(cmd_enc,
+				"control vblank irq error %d, enable %d\n",
+				ret, enable);
+
+	return ret;
+}
+
+void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc,
+		bool enable)
+{
+	if (!phys_enc || _sde_encoder_phys_is_ppsplit_slave(phys_enc))
+		return;
+
+	if (enable) {
+		sde_encoder_phys_cmd_register_irq(phys_enc,
+				SDE_IRQ_TYPE_PING_PONG_COMP,
+				INTR_IDX_PINGPONG,
+				sde_encoder_phys_cmd_pp_tx_done_irq,
+				"pp_tx_done");
+
+		sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true);
+
+		sde_encoder_phys_cmd_register_irq(phys_enc,
+				SDE_IRQ_TYPE_INTF_UNDER_RUN,
+				INTR_IDX_UNDERRUN,
+				sde_encoder_phys_cmd_underrun_irq,
+				"underrun");
+	} else {
+		sde_encoder_phys_cmd_unregister_irq(
+				phys_enc, INTR_IDX_UNDERRUN);
+		sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
+		sde_encoder_phys_cmd_unregister_irq(
+				phys_enc, INTR_IDX_PINGPONG);
+	}
+}
+
 static void sde_encoder_phys_cmd_tearcheck_config(
 		struct sde_encoder_phys *phys_enc)
 {
@@ -477,56 +549,12 @@
 	return _sde_encoder_phys_is_ppsplit(phys_enc);
 }
 
-static int sde_encoder_phys_cmd_control_vblank_irq(
-		struct sde_encoder_phys *phys_enc,
-		bool enable)
-{
-	struct sde_encoder_phys_cmd *cmd_enc =
-		to_sde_encoder_phys_cmd(phys_enc);
-	int ret = 0;
-
-	if (!phys_enc) {
-		SDE_ERROR("invalid encoder\n");
-		return -EINVAL;
-	}
-
-	/* Slave encoders don't report vblank */
-	if (!sde_encoder_phys_cmd_is_master(phys_enc))
-		goto end;
-
-	SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n",
-			__builtin_return_address(0),
-			enable, atomic_read(&phys_enc->vblank_refcount));
-
-	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
-			enable, atomic_read(&phys_enc->vblank_refcount));
-
-	if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
-		ret = sde_encoder_phys_cmd_register_irq(phys_enc,
-				SDE_IRQ_TYPE_PING_PONG_RD_PTR,
-				INTR_IDX_RDPTR,
-				sde_encoder_phys_cmd_pp_rd_ptr_irq,
-				"pp_rd_ptr");
-	else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
-		ret = sde_encoder_phys_cmd_unregister_irq(phys_enc,
-				INTR_IDX_RDPTR);
-
-end:
-	if (ret)
-		SDE_ERROR_CMDENC(cmd_enc,
-				"control vblank irq error %d, enable %d\n",
-				ret, enable);
-
-	return ret;
-}
-
 static void sde_encoder_phys_cmd_enable(struct sde_encoder_phys *phys_enc)
 {
 	struct sde_encoder_phys_cmd *cmd_enc =
 		to_sde_encoder_phys_cmd(phys_enc);
 	struct sde_hw_ctl *ctl;
 	u32 flush_mask = 0;
-	int ret;
 
 	if (!phys_enc || !phys_enc->hw_ctl) {
 		SDE_ERROR("invalid arg(s), encoder %d\n", phys_enc != 0);
@@ -543,38 +571,6 @@
 
 	sde_encoder_phys_cmd_pingpong_config(phys_enc);
 
-	if (_sde_encoder_phys_is_ppsplit_slave(phys_enc))
-		goto update_flush;
-
-	/* Both master and slave need to register for pp_tx_done */
-	ret = sde_encoder_phys_cmd_register_irq(phys_enc,
-			SDE_IRQ_TYPE_PING_PONG_COMP,
-			INTR_IDX_PINGPONG,
-			sde_encoder_phys_cmd_pp_tx_done_irq,
-			"pp_tx_done");
-	if (ret)
-		return;
-
-	ret = sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true);
-	if (ret) {
-		sde_encoder_phys_cmd_unregister_irq(phys_enc,
-				INTR_IDX_PINGPONG);
-		return;
-	}
-
-	ret = sde_encoder_phys_cmd_register_irq(phys_enc,
-			SDE_IRQ_TYPE_INTF_UNDER_RUN,
-			INTR_IDX_UNDERRUN,
-			sde_encoder_phys_cmd_underrun_irq,
-			"underrun");
-	if (ret) {
-		sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
-		sde_encoder_phys_cmd_unregister_irq(phys_enc,
-				INTR_IDX_PINGPONG);
-		return;
-	}
-
-update_flush:
 	ctl = phys_enc->hw_ctl;
 	ctl->ops.get_bitmask_intf(ctl, &flush_mask, cmd_enc->intf_idx);
 	ctl->ops.update_pending_flush(ctl, flush_mask);
@@ -613,21 +609,9 @@
 			SDE_EVT32(DRMID(phys_enc->parent),
 					phys_enc->hw_pp->idx - PINGPONG_0, ret);
 		}
-
-		sde_encoder_phys_cmd_unregister_irq(
-				phys_enc, INTR_IDX_UNDERRUN);
-		sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false);
-		sde_encoder_phys_cmd_unregister_irq(
-				phys_enc, INTR_IDX_PINGPONG);
 	}
 
 	phys_enc->enable_state = SDE_ENC_DISABLED;
-
-	if (atomic_read(&phys_enc->vblank_refcount))
-		SDE_ERROR("enc:%d role:%d invalid vblank refcount %d\n",
-				phys_enc->parent->base.id,
-				phys_enc->split_role,
-				atomic_read(&phys_enc->vblank_refcount));
 }
 
 static void sde_encoder_phys_cmd_destroy(struct sde_encoder_phys *phys_enc)
@@ -723,6 +707,7 @@
 	ops->trigger_start = sde_encoder_helper_trigger_start;
 	ops->needs_single_flush = sde_encoder_phys_cmd_needs_single_flush;
 	ops->hw_reset = sde_encoder_helper_hw_reset;
+	ops->irq_control = sde_encoder_phys_cmd_irq_control;
 }
 
 struct sde_encoder_phys *sde_encoder_phys_cmd_init(
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 29f00f7..df099d3 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -227,16 +227,18 @@
 	struct sde_encoder_phys_vid *vid_enc =
 		to_sde_encoder_phys_vid(phys_enc);
 	struct intf_prog_fetch f = { 0 };
-	struct intf_timing_params *timing = &vid_enc->timing_params;
+	struct intf_timing_params *timing;
 	u32 vfp_fetch_lines = 0;
 	u32 horiz_total = 0;
 	u32 vert_total = 0;
 	u32 rot_fetch_start_vsync_counter = 0;
 	unsigned long lock_flags;
 
-	if (WARN_ON_ONCE(!vid_enc->hw_intf->ops.setup_rot_start))
+	if (!phys_enc || !vid_enc->hw_intf ||
+			!vid_enc->hw_intf->ops.setup_rot_start)
 		return;
 
+	timing = &vid_enc->timing_params;
 	vfp_fetch_lines = programmable_fetch_get_num_lines(vid_enc, timing);
 	if (vfp_fetch_lines && rot_fetch_lines) {
 		vert_total = get_vertical_total(timing);
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index e7f3df7..c3477b5 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -1072,7 +1072,8 @@
 			DRM_ERROR("invalid handle for plane %d\n", i);
 			return -EINVAL;
 		}
-		bos_total_size += bos[i]->size;
+		if ((i == 0) || (bos[i] != bos[0]))
+			bos_total_size += bos[i]->size;
 	}
 
 	if (bos_total_size < layout.total_size) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index cfa3b5e..b8ab066 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -120,6 +120,7 @@
 	SRC_SPLIT,
 	DIM_LAYER,
 	SMART_DMA_REV,
+	IDLE_PC,
 	SDE_PROP_MAX,
 };
 
@@ -313,6 +314,7 @@
 	{SRC_SPLIT, "qcom,sde-has-src-split", false, PROP_TYPE_BOOL},
 	{DIM_LAYER, "qcom,sde-has-dim-layer", false, PROP_TYPE_BOOL},
 	{SMART_DMA_REV, "qcom,sde-smart-dma-rev", false, PROP_TYPE_STRING},
+	{IDLE_PC, "qcom,sde-has-idle-pc", false, PROP_TYPE_BOOL},
 };
 
 static struct sde_prop_type sde_perf_prop[] = {
@@ -2214,6 +2216,7 @@
 
 	cfg->has_src_split = PROP_VALUE_ACCESS(prop_value, SRC_SPLIT, 0);
 	cfg->has_dim_layer = PROP_VALUE_ACCESS(prop_value, DIM_LAYER, 0);
+	cfg->has_idle_pc = PROP_VALUE_ACCESS(prop_value, IDLE_PC, 0);
 end:
 	kfree(prop_value);
 	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 97da08f..b5f83ad 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -713,6 +713,7 @@
  * @ubwc_version       UBWC feature version (0x0 for not supported)
  * @has_sbuf           indicate if stream buffer is available
  * @sbuf_headroom      stream buffer headroom in lines
+ * @has_idle_pc        indicate if idle power collapse feature is supported
  * @dma_formats        Supported formats for dma pipe
  * @cursor_formats     Supported formats for cursor pipe
  * @vig_formats        Supported formats for vig pipe
@@ -735,6 +736,7 @@
 	u32 ubwc_version;
 	bool has_sbuf;
 	u32 sbuf_headroom;
+	bool has_idle_pc;
 
 	u32 mdss_count;
 	struct sde_mdss_base_cfg mdss[MAX_BLOCKS];
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index f1b9c32..8df4de2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -25,6 +25,9 @@
 {
 	int i;
 
+	if (!m || !addr || !b)
+		return ERR_PTR(-EINVAL);
+
 	for (i = 0; i < m->dspp_count; i++) {
 		if (dspp == m->dspp[i].id) {
 			b->base_off = addr;
@@ -43,6 +46,9 @@
 {
 	int i = 0, ret;
 
+	if (!c || !c->cap || !c->cap->sblk)
+		return;
+
 	for (i = 0; i < SDE_DSPP_MAX; i++) {
 		if (!test_bit(i, &features))
 			continue;
@@ -119,6 +125,9 @@
 	struct sde_hw_dspp *c;
 	struct sde_dspp_cfg *cfg;
 
+	if (!addr || !m)
+		return ERR_PTR(-EINVAL);
+
 	c = kzalloc(sizeof(*c), GFP_KERNEL);
 	if (!c)
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
index 6020476..70b3e56 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.h
@@ -192,6 +192,7 @@
  * should be called once before accessing every dspp.
  * @idx:  DSPP index for which driver object is required
  * @addr: Mapped register io address of MDP
+ * @Return: pointer to structure or ERR_PTR
  */
 struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
 			void __iomem *addr,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
index d5289c0..24f16c6 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.c
@@ -31,9 +31,9 @@
 #define MDP_INTF_4_OFF			0x6D000
 #define MDP_AD4_0_OFF			0x7D000
 #define MDP_AD4_1_OFF			0x7E000
-#define MDP_AD4_INTR_EN_OFF 0x41c
-#define MDP_AD4_INTR_CLEAR_OFF 0x424
-#define MDP_AD4_INTR_STATUS_OFF 0x420
+#define MDP_AD4_INTR_EN_OFF		0x41c
+#define MDP_AD4_INTR_CLEAR_OFF		0x424
+#define MDP_AD4_INTR_STATUS_OFF		0x420
 
 /**
  * WB interrupt status bit definitions
@@ -87,7 +87,7 @@
  * Pingpong Secondary interrupt status bit definitions
  */
 #define SDE_INTR_PING_PONG_S0_AUTOREFRESH_DONE BIT(0)
-#define	SDE_INTR_PING_PONG_S0_WR_PTR BIT(4)
+#define SDE_INTR_PING_PONG_S0_WR_PTR BIT(4)
 #define SDE_INTR_PING_PONG_S0_RD_PTR BIT(8)
 #define SDE_INTR_PING_PONG_S0_TEAR_DETECTED BIT(22)
 #define SDE_INTR_PING_PONG_S0_TE_DETECTED BIT(28)
@@ -109,6 +109,15 @@
 #define SDE_INTR_PING_PONG_3_TE_DETECTED BIT(27)
 
 /**
+ * Ctl start interrupt status bit definitions
+ */
+#define SDE_INTR_CTL_0_START BIT(9)
+#define SDE_INTR_CTL_1_START BIT(10)
+#define SDE_INTR_CTL_2_START BIT(11)
+#define SDE_INTR_CTL_3_START BIT(12)
+#define SDE_INTR_CTL_4_START BIT(13)
+
+/**
  * Concurrent WB overflow interrupt status bit definitions
  */
 #define SDE_INTR_CWB_2_OVERFLOW BIT(14)
@@ -325,15 +334,21 @@
 	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
 	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
 	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
-	/* irq_idx: 40-43 */
+	/* irq_idx: 40 */
 	{ SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_S0,
 		SDE_INTR_PING_PONG_S0_RD_PTR, 1},
-	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
-	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
-	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
-	/* irq_idx: 44-47 */
-	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
-	{ SDE_IRQ_TYPE_RESERVED, 0, 0, 1},
+	/* irq_idx: 41-45 */
+	{ SDE_IRQ_TYPE_CTL_START, CTL_0,
+		SDE_INTR_CTL_0_START, 1},
+	{ SDE_IRQ_TYPE_CTL_START, CTL_1,
+		SDE_INTR_CTL_1_START, 1},
+	{ SDE_IRQ_TYPE_CTL_START, CTL_2,
+		SDE_INTR_CTL_2_START, 1},
+	{ SDE_IRQ_TYPE_CTL_START, CTL_3,
+		SDE_INTR_CTL_3_START, 1},
+	{ SDE_IRQ_TYPE_CTL_START, CTL_4,
+		SDE_INTR_CTL_4_START, 1},
+	/* irq_idx: 46-47 */
 	{ SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_2, SDE_INTR_CWB_2_OVERFLOW, 1},
 	{ SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_3, SDE_INTR_CWB_3_OVERFLOW, 1},
 	/* irq_idx: 48-51 */
@@ -696,6 +711,9 @@
 static void sde_hw_intr_set_mask(struct sde_hw_intr *intr, uint32_t reg_off,
 		uint32_t mask)
 {
+	if (!intr)
+		return;
+
 	SDE_REG_WRITE(&intr->hw, reg_off, mask);
 }
 
@@ -710,6 +728,9 @@
 	u32 irq_status;
 	unsigned long irq_flags;
 
+	if (!intr)
+		return;
+
 	/*
 	 * The dispatcher will save the IRQ status before calling here.
 	 * Now need to go through each IRQ status and find matching
@@ -726,6 +747,10 @@
 		start_idx = reg_idx * 32;
 		end_idx = start_idx + 32;
 
+		if (start_idx >= ARRAY_SIZE(sde_irq_map) ||
+				end_idx > ARRAY_SIZE(sde_irq_map))
+			continue;
+
 		/*
 		 * Search through matching intr status from irq map.
 		 * start_idx and end_idx defined the search range in
@@ -769,6 +794,9 @@
 	const char *dbgstr = NULL;
 	uint32_t cache_irq_mask;
 
+	if (!intr)
+		return -EINVAL;
+
 	if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) {
 		pr_err("invalid IRQ index: [%d]\n", irq_idx);
 		return -EINVAL;
@@ -810,6 +838,9 @@
 	const char *dbgstr = NULL;
 	uint32_t cache_irq_mask;
 
+	if (!intr)
+		return -EINVAL;
+
 	if (irq_idx < 0 || irq_idx >= ARRAY_SIZE(sde_irq_map)) {
 		pr_err("invalid IRQ index: [%d]\n", irq_idx);
 		return -EINVAL;
@@ -846,6 +877,9 @@
 {
 	int i;
 
+	if (!intr)
+		return -EINVAL;
+
 	for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++)
 		SDE_REG_WRITE(&intr->hw, sde_intr_set[i].clr_off, 0xffffffff);
 
@@ -856,6 +890,9 @@
 {
 	int i;
 
+	if (!intr)
+		return -EINVAL;
+
 	for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++)
 		SDE_REG_WRITE(&intr->hw, sde_intr_set[i].en_off, 0x00000000);
 
@@ -865,15 +902,23 @@
 static int sde_hw_intr_get_valid_interrupts(struct sde_hw_intr *intr,
 		uint32_t *mask)
 {
+	if (!intr || !mask)
+		return -EINVAL;
+
 	*mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1
 		| IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP;
+
 	return 0;
 }
 
 static int sde_hw_intr_get_interrupt_sources(struct sde_hw_intr *intr,
 		uint32_t *sources)
 {
+	if (!intr || !sources)
+		return -EINVAL;
+
 	*sources = SDE_REG_READ(&intr->hw, HW_INTR_STATUS);
+
 	return 0;
 }
 
@@ -883,6 +928,9 @@
 	u32 enable_mask;
 	unsigned long irq_flags;
 
+	if (!intr)
+		return;
+
 	spin_lock_irqsave(&intr->status_lock, irq_flags);
 	for (i = 0; i < ARRAY_SIZE(sde_intr_set); i++) {
 		/* Read interrupt status */
@@ -909,6 +957,9 @@
 	int reg_idx;
 	unsigned long irq_flags;
 
+	if (!intr)
+		return;
+
 	spin_lock_irqsave(&intr->mask_lock, irq_flags);
 
 	reg_idx = sde_irq_map[irq_idx].reg_idx;
@@ -925,6 +976,9 @@
 	unsigned long irq_flags;
 	u32 intr_status;
 
+	if (!intr)
+		return 0;
+
 	spin_lock_irqsave(&intr->mask_lock, irq_flags);
 
 	reg_idx = sde_irq_map[irq_idx].reg_idx;
@@ -959,7 +1013,7 @@
 static struct sde_mdss_base_cfg *__intr_offset(struct sde_mdss_cfg *m,
 		void __iomem *addr, struct sde_hw_blk_reg_map *hw)
 {
-	if (m->mdp_count == 0)
+	if (!m || !addr || !hw || m->mdp_count == 0)
 		return NULL;
 
 	hw->base_off = addr;
@@ -971,9 +1025,13 @@
 struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr,
 		struct sde_mdss_cfg *m)
 {
-	struct sde_hw_intr *intr = kzalloc(sizeof(*intr), GFP_KERNEL);
+	struct sde_hw_intr *intr;
 	struct sde_mdss_base_cfg *cfg;
 
+	if (!addr || !m)
+		return ERR_PTR(-EINVAL);
+
+	intr = kzalloc(sizeof(*intr), GFP_KERNEL);
 	if (!intr)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
index 7805df1..aaba1be 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_interrupts.h
@@ -25,7 +25,7 @@
 #define IRQ_SOURCE_DSI1		BIT(5)
 #define IRQ_SOURCE_HDMI		BIT(8)
 #define IRQ_SOURCE_EDP		BIT(12)
-#define	IRQ_SOURCE_MHL		BIT(16)
+#define IRQ_SOURCE_MHL		BIT(16)
 
 /**
  * sde_intr_type - HW Interrupt Type
@@ -55,6 +55,7 @@
  * @SDE_IRQ_TYPE_SFI_CMD_2_OUT:		DSI CMD2 static frame INTR out-of static
  * @SDE_IRQ_TYPE_PROG_LINE:		Programmable Line interrupt
  * @SDE_IRQ_TYPE_AD4_BL_DONE:		AD4 backlight
+ * @SDE_IRQ_TYPE_CTL_START:		Control start
  * @SDE_IRQ_TYPE_RESERVED:		Reserved for expansion
  */
 enum sde_intr_type {
@@ -84,6 +85,7 @@
 	SDE_IRQ_TYPE_SFI_CMD_2_OUT,
 	SDE_IRQ_TYPE_PROG_LINE,
 	SDE_IRQ_TYPE_AD4_BL_DONE,
+	SDE_IRQ_TYPE_CTL_START,
 	SDE_IRQ_TYPE_RESERVED,
 };
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index 01fe3c8..d15b804 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -574,9 +574,16 @@
 
 	rot_cmd.video_mode = data->video_mode;
 	rot_cmd.fps = data->fps;
+
+	/*
+	 * DRM rotation property is specified in counter clockwise direction
+	 * whereas rotator h/w rotates in clockwise direction.
+	 * Convert rotation property to clockwise 90 by toggling h/v flip
+	 */
 	rot_cmd.rot90 = data->rot90;
-	rot_cmd.hflip = data->hflip;
-	rot_cmd.vflip = data->vflip;
+	rot_cmd.hflip = data->rot90 ? !data->hflip : data->hflip;
+	rot_cmd.vflip = data->rot90 ? !data->vflip : data->vflip;
+
 	rot_cmd.secure = data->secure;
 	rot_cmd.clkrate = data->clkrate;
 	rot_cmd.data_bw = 0;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index b20b3bc..cf54611 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -39,13 +39,15 @@
 static void sde_hw_setup_split_pipe(struct sde_hw_mdp *mdp,
 		struct split_pipe_cfg *cfg)
 {
-	struct sde_hw_blk_reg_map *c = &mdp->hw;
+	struct sde_hw_blk_reg_map *c;
 	u32 upper_pipe = 0;
 	u32 lower_pipe = 0;
 
 	if (!mdp || !cfg)
 		return;
 
+	c = &mdp->hw;
+
 	if (cfg->en) {
 		if (cfg->mode == INTF_MODE_CMD) {
 			lower_pipe = FLD_SPLIT_DISPLAY_CMD;
@@ -107,9 +109,14 @@
 static void sde_hw_setup_cdm_output(struct sde_hw_mdp *mdp,
 		struct cdm_output_cfg *cfg)
 {
-	struct sde_hw_blk_reg_map *c = &mdp->hw;
+	struct sde_hw_blk_reg_map *c;
 	u32 out_ctl = 0;
 
+	if (!mdp || !cfg)
+		return;
+
+	c = &mdp->hw;
+
 	if (cfg->wb_en)
 		out_ctl |= BIT(24);
 	else if (cfg->intf_en)
@@ -121,11 +128,16 @@
 static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp,
 		enum sde_clk_ctrl_type clk_ctrl, bool enable)
 {
-	struct sde_hw_blk_reg_map *c = &mdp->hw;
+	struct sde_hw_blk_reg_map *c;
 	u32 reg_off, bit_off;
 	u32 reg_val, new_val;
 	bool clk_forced_on;
 
+	if (!mdp)
+		return false;
+
+	c = &mdp->hw;
+
 	if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX)
 		return false;
 
@@ -150,9 +162,14 @@
 static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp,
 		struct sde_danger_safe_status *status)
 {
-	struct sde_hw_blk_reg_map *c = &mdp->hw;
+	struct sde_hw_blk_reg_map *c;
 	u32 value;
 
+	if (!mdp || !status)
+		return;
+
+	c = &mdp->hw;
+
 	value = SDE_REG_READ(c, DANGER_STATUS);
 	status->mdp = (value >> 0) & 0x3;
 	status->sspp[SSPP_VIG0] = (value >> 4) & 0x3;
@@ -178,9 +195,14 @@
 static void sde_hw_get_safe_status(struct sde_hw_mdp *mdp,
 		struct sde_danger_safe_status *status)
 {
-	struct sde_hw_blk_reg_map *c = &mdp->hw;
+	struct sde_hw_blk_reg_map *c;
 	u32 value;
 
+	if (!mdp || !status)
+		return;
+
+	c = &mdp->hw;
+
 	value = SDE_REG_READ(c, SAFE_STATUS);
 	status->mdp = (value >> 0) & 0x1;
 	status->sspp[SSPP_VIG0] = (value >> 4) & 0x1;
@@ -205,11 +227,32 @@
 
 static void sde_hw_setup_dce(struct sde_hw_mdp *mdp, u32 dce_sel)
 {
-	struct sde_hw_blk_reg_map *c = &mdp->hw;
+	struct sde_hw_blk_reg_map *c;
+
+	if (!mdp)
+		return;
+
+	c = &mdp->hw;
 
 	SDE_REG_WRITE(c, DCE_SEL, dce_sel);
 }
 
+void sde_hw_reset_ubwc(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m)
+{
+	struct sde_hw_blk_reg_map c;
+
+	if (!mdp || !m)
+		return;
+
+	if (!IS_UBWC_20_SUPPORTED(m->ubwc_version))
+		return;
+
+	/* force blk offset to zero to access beginning of register region */
+	c = mdp->hw;
+	c.blk_off = 0x0;
+	SDE_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static);
+}
+
 static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
 		unsigned long cap)
 {
@@ -220,6 +263,7 @@
 	ops->get_danger_status = sde_hw_get_danger_status;
 	ops->get_safe_status = sde_hw_get_safe_status;
 	ops->setup_dce = sde_hw_setup_dce;
+	ops->reset_ubwc = sde_hw_reset_ubwc;
 }
 
 static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
@@ -229,6 +273,9 @@
 {
 	int i;
 
+	if (!m || !addr || !b)
+		return ERR_PTR(-EINVAL);
+
 	for (i = 0; i < m->mdp_count; i++) {
 		if (mdp == m->mdp[i].id) {
 			b->base_off = addr;
@@ -243,25 +290,6 @@
 	return ERR_PTR(-EINVAL);
 }
 
-static inline void _sde_hw_mdptop_init_ubwc(void __iomem *addr,
-		const struct sde_mdss_cfg *m)
-{
-	struct sde_hw_blk_reg_map hw;
-
-	if (!addr || !m)
-		return;
-
-	if (!IS_UBWC_20_SUPPORTED(m->ubwc_version))
-		return;
-
-	memset(&hw, 0, sizeof(hw));
-	hw.base_off = addr;
-	hw.blk_off = 0x0;
-	hw.hwversion = m->hwversion;
-	hw.log_mask = SDE_DBG_MASK_TOP;
-	SDE_REG_WRITE(&hw, UBWC_STATIC, m->mdp[0].ubwc_static);
-}
-
 struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
 		void __iomem *addr,
 		const struct sde_mdss_cfg *m)
@@ -294,8 +322,6 @@
 			mdp->hw.xin_id);
 	sde_dbg_set_sde_top_offset(mdp->hw.blk_off);
 
-	_sde_hw_mdptop_init_ubwc(addr, m);
-
 	return mdp;
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index 9cb0c55..7511358 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -148,6 +148,13 @@
 	 */
 	void (*get_safe_status)(struct sde_hw_mdp *mdp,
 			struct sde_danger_safe_status *status);
+
+	/**
+	 * reset_ubwc - reset top level UBWC configuration
+	 * @mdp: mdp top context driver
+	 * @m: pointer to mdss catalog data
+	 */
+	void (*reset_ubwc)(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m);
 };
 
 struct sde_hw_mdp {
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 8662207..93268be 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -1961,21 +1961,29 @@
 		ret = sde_plane_rot_submit_command(plane, state,
 				SDE_HW_ROT_CMD_VALIDATE);
 
-	} else if (sde_plane_enabled(state)) {
+	} else {
 
 		SDE_DEBUG("plane%d.%d bypass rotator\n", plane->base.id,
 				rstate->sequence_id);
 
 		/* bypass rotator - initialize output setting as input */
+		for (i = 0; i < ARRAY_SIZE(rstate->out_fb_modifier); i++)
+			rstate->out_fb_modifier[i] = state->fb ?
+				state->fb->modifier[i] : 0x0;
+
+		if (state->fb) {
+			rstate->out_fb_pixel_format = state->fb->pixel_format;
+			rstate->out_fb_flags = state->fb->flags;
+			rstate->out_fb_width = state->fb->width;
+			rstate->out_fb_height = state->fb->height;
+		} else {
+			rstate->out_fb_pixel_format = 0x0;
+			rstate->out_fb_flags = 0x0;
+			rstate->out_fb_width = 0;
+			rstate->out_fb_height = 0;
+		}
+
 		rstate->out_rotation = rstate->in_rotation;
-		rstate->out_fb_pixel_format = state->fb->pixel_format;
-
-		for (i = 0.; i < ARRAY_SIZE(rstate->out_fb_modifier); i++)
-			rstate->out_fb_modifier[i] = state->fb->modifier[i];
-
-		rstate->out_fb_flags = state->fb->flags;
-		rstate->out_fb_width = state->fb->width;
-		rstate->out_fb_height = state->fb->height;
 		rstate->out_src_x = state->src_x;
 		rstate->out_src_y = state->src_y;
 		rstate->out_src_w = state->src_w;
diff --git a/drivers/gpu/drm/msm/sde/sde_wb.c b/drivers/gpu/drm/msm/sde/sde_wb.c
index 2220925..b2665be 100644
--- a/drivers/gpu/drm/msm/sde/sde_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_wb.c
@@ -286,6 +286,27 @@
 	return 0;
 }
 
+int sde_wb_get_topology(const struct drm_display_mode *drm_mode,
+	struct msm_display_topology *topology, u32 max_mixer_width)
+{
+	const u32 dual_lm = 2;
+	const u32 single_lm = 1;
+	const u32 single_intf = 1;
+	const u32 no_enc = 0;
+
+	if (!drm_mode || !topology || !max_mixer_width) {
+		pr_err("invalid params\n");
+		return -EINVAL;
+	}
+
+	topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ?
+							dual_lm : single_lm;
+	topology->num_enc = no_enc;
+	topology->num_intf = single_intf;
+
+	return 0;
+}
+
 int sde_wb_connector_post_init(struct drm_connector *connector,
 		void *info,
 		void *display)
diff --git a/drivers/gpu/drm/msm/sde/sde_wb.h b/drivers/gpu/drm/msm/sde/sde_wb.h
index 4e33595..205ff24 100644
--- a/drivers/gpu/drm/msm/sde/sde_wb.h
+++ b/drivers/gpu/drm/msm/sde/sde_wb.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -31,6 +31,7 @@
  * @wb_lock		Serialization lock for writeback context structure
  * @connector:		Connector associated with writeback device
  * @encoder:		Encoder associated with writeback device
+ * @max_mixer_width:    Max width supported by SDE LM HW block
  * @count_modes:	Length of writeback connector modes array
  * @modes:		Writeback connector modes array
  */
@@ -49,6 +50,8 @@
 	struct drm_encoder *encoder;
 
 	enum drm_connector_status detect_status;
+	u32 max_mixer_width;
+
 	u32 count_modes;
 	struct drm_mode_modeinfo *modes;
 };
@@ -183,6 +186,17 @@
 int sde_wb_get_info(struct msm_display_info *info, void *display);
 
 /**
+ * sde_wb_get_topology - retrieve current topology for the mode selected
+ * @drm_mode: Display mode set for the display
+ * @topology: Out parameter. Topology for the mode.
+ * @max_mixer_width: max width supported by HW layer mixer
+ * Returns: zero on success
+ */
+int sde_wb_get_topology(const struct drm_display_mode *drm_mode,
+		struct msm_display_topology *topology,
+		u32 max_mixer_width);
+
+/**
  * sde_wb_connector_get_wb - retrieve writeback device of the given connector
  * @connector: Pointer to drm connector
  * Returns: Pointer to writeback device on success; NULL otherwise
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 9a68dbe..1e4f6b1 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -44,6 +44,7 @@
 static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable)
 {
 	u32 rsc_state;
+	int ret = 0;
 
 	/* creates the rsc client on the first enable */
 	if (!phandle->rsc_client_init) {
@@ -59,8 +60,11 @@
 
 	rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
 
-	return sde_rsc_client_state_update(phandle->rsc_client,
+	if (phandle->rsc_client)
+		ret = sde_rsc_client_state_update(phandle->rsc_client,
 			rsc_state, NULL, -1);
+
+	return ret;
 }
 
 struct sde_power_client *sde_power_client_create(
@@ -837,7 +841,15 @@
 			goto data_bus_hdl_err;
 		}
 
-		if (!phandle->rsc_client_init) {
+		/*
+		 * - When the target is RSCC enabled, regulator should
+		 *   be enabled by the s/w only for the first time during
+		 *   bootup. After that, RSCC hardware takes care of enabling/
+		 *   disabling it.
+		 * - When the target is not RSCC enabled, regulator should
+		 *   be totally handled by the software.
+		 */
+		if (!phandle->rsc_client) {
 			rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
 									enable);
 			if (rc) {
@@ -879,7 +891,7 @@
 		sde_power_reg_bus_update(phandle->reg_bus_hdl,
 							max_usecase_ndx);
 
-		if (!phandle->rsc_client_init)
+		if (!phandle->rsc_client)
 			msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
 									enable);
 		sde_power_data_bus_update(&phandle->data_bus_handle, enable);
@@ -897,7 +909,7 @@
 rsc_err:
 	sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
 reg_bus_hdl_err:
-	if (!phandle->rsc_client_init)
+	if (!phandle->rsc_client)
 		msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
 vreg_err:
 	sde_power_data_bus_update(&phandle->data_bus_handle, 0);
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index b26ef9f..d753f0a 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -16,9 +16,9 @@
 
 #define MAX_CLIENT_NAME_LEN 128
 
-#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA	64000
+#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA	2000000000
 #define SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA	0
-#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA	64000
+#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA	2000000000
 #define SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA	0
 
 #include <linux/sde_io_util.h>
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index c1b812a..f35d77b 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -28,16 +28,19 @@
 #include <drm/drmP.h>
 #include <drm/drm_irq.h>
 #include "sde_rsc_priv.h"
+#include "sde_dbg.h"
 
-/* this time is ~0.02ms */
-#define RSC_BACKOFF_TIME_NS		 20000
+/* worst case time to execute the one tcs vote(sleep/wake) - ~1ms */
+#define TCS_CASE_EXECUTION_TIME				1064000
 
-/* next two values should be same based on doc */
+/* this time is ~1ms - only wake tcs in any mode */
+#define RSC_BACKOFF_TIME_NS		 (TCS_CASE_EXECUTION_TIME + 100)
 
-/* this time is ~0.2ms */
-#define RSC_MODE_THRESHOLD_TIME_IN_NS	200000
-/* this time is ~0.2ms */
-#define RSC_TIME_SLOT_0_NS		200000
+/* this time is ~1ms - only wake TCS in mode-0 */
+#define RSC_MODE_THRESHOLD_TIME_IN_NS	((TCS_CASE_EXECUTION_TIME >> 1) + 100)
+
+/* this time is ~2ms - sleep+ wake TCS in mode-1 */
+#define RSC_TIME_SLOT_0_NS		((TCS_CASE_EXECUTION_TIME * 2) + 100)
 
 #define DEFAULT_PANEL_FPS		60
 #define DEFAULT_PANEL_JITTER		5
@@ -74,6 +77,7 @@
 {
 	struct sde_rsc_client *client;
 	struct sde_rsc_priv *rsc;
+	static int id;
 
 	if (!client_name) {
 		pr_err("client name is null- not supported\n");
@@ -83,7 +87,7 @@
 		return ERR_PTR(-EINVAL);
 	} else if (!rsc_prv_list[rsc_index]) {
 		pr_err("rsc not probed yet or not available\n");
-		return ERR_PTR(-EINVAL);
+		return NULL;
 	}
 
 	rsc = rsc_prv_list[rsc_index];
@@ -95,12 +99,14 @@
 	strlcpy(client->name, client_name, MAX_RSC_CLIENT_NAME_LEN);
 	client->current_state = SDE_RSC_IDLE_STATE;
 	client->rsc_index = rsc_index;
+	client->id = id;
 	if (is_primary_client)
 		rsc->primary_client = client;
 	pr_debug("client %s rsc index:%d primary:%d\n", client_name,
 						rsc_index, is_primary_client);
 
 	list_add(&client->list, &rsc->client_list);
+	id++;
 	mutex_unlock(&rsc->client_lock);
 
 	return client;
@@ -388,7 +394,7 @@
 
 static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
 	struct sde_rsc_cmd_config *config,
-	struct sde_rsc_client *caller_client, bool wait_req)
+	struct sde_rsc_client *caller_client)
 {
 	struct sde_rsc_client *client;
 	int rc = STATE_UPDATE_NOT_ALLOWED;
@@ -416,8 +422,8 @@
 	if (rsc->hw_ops.state_update)
 		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE);
 
-	/* wait for vsync */
-	if (!rc && wait_req)
+	/* wait for vsync for vid to cmd state switch */
+	if (!rc && (rsc->current_state == SDE_RSC_VID_STATE))
 		drm_wait_one_vblank(rsc->master_drm,
 						rsc->primary_client->crtc_id);
 end:
@@ -436,13 +442,19 @@
 
 	if (rsc->hw_ops.state_update)
 		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CLK_STATE);
+
+	/* wait for vsync for cmd to clk state switch */
+	if (!rc && rsc->primary_client &&
+				(rsc->current_state == SDE_RSC_CMD_STATE))
+		drm_wait_one_vblank(rsc->master_drm,
+						rsc->primary_client->crtc_id);
 end:
 	return rc;
 }
 
 static bool sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
 	struct sde_rsc_cmd_config *config,
-	struct sde_rsc_client *caller_client, bool wait_req)
+	struct sde_rsc_client *caller_client)
 {
 	int rc = 0;
 
@@ -454,8 +466,9 @@
 	if (rsc->hw_ops.state_update)
 		rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE);
 
-	/* wait for vsync */
-	if (!rc && rsc->primary_client && wait_req)
+	/* wait for vsync for cmd to vid state switch */
+	if (!rc && rsc->primary_client &&
+			(rsc->current_state == SDE_RSC_CMD_STATE))
 		drm_wait_one_vblank(rsc->master_drm,
 						rsc->primary_client->crtc_id);
 	return rc;
@@ -481,7 +494,6 @@
 {
 	int rc = 0;
 	struct sde_rsc_priv *rsc;
-	bool wait_requested = false;
 
 	if (!caller_client) {
 		pr_err("invalid client for rsc state update\n");
@@ -496,6 +508,8 @@
 		return -EINVAL;
 
 	mutex_lock(&rsc->client_lock);
+	SDE_EVT32(caller_client->id, caller_client->current_state,
+			state, rsc->current_state, SDE_EVTLOG_FUNC_ENTRY);
 	caller_client->crtc_id = crtc_id;
 	caller_client->current_state = state;
 
@@ -512,11 +526,7 @@
 		__builtin_return_address(0), rsc->current_state,
 		caller_client->name, state);
 
-	/* only switch state needs vsync wait */
-	wait_requested = (rsc->current_state == SDE_RSC_VID_STATE) ||
-			(rsc->current_state == SDE_RSC_CMD_STATE);
-
-	if (rsc->power_collapse)
+	if (rsc->current_state == SDE_RSC_IDLE_STATE)
 		sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
 
 	switch (state) {
@@ -526,7 +536,7 @@
 		/* video state client might be exiting; try cmd state switch */
 		if (rc == TRY_CMD_MODE_SWITCH) {
 			rc = sde_rsc_switch_to_cmd(rsc, NULL,
-					rsc->primary_client, wait_requested);
+							rsc->primary_client);
 			if (!rc)
 				state = SDE_RSC_CMD_STATE;
 
@@ -539,13 +549,11 @@
 		break;
 
 	case SDE_RSC_CMD_STATE:
-		rc = sde_rsc_switch_to_cmd(rsc, config, caller_client,
-								wait_requested);
+		rc = sde_rsc_switch_to_cmd(rsc, config, caller_client);
 		break;
 
 	case SDE_RSC_VID_STATE:
-		rc = sde_rsc_switch_to_vid(rsc, config, caller_client,
-								wait_requested);
+		rc = sde_rsc_switch_to_vid(rsc, config, caller_client);
 		break;
 
 	case SDE_RSC_CLK_STATE:
@@ -559,17 +567,23 @@
 
 	if (rc == STATE_UPDATE_NOT_ALLOWED) {
 		rc = 0;
+		SDE_EVT32(caller_client->id, caller_client->current_state,
+			state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE1);
 		goto clk_disable;
 	} else if (rc) {
-		pr_err("state update failed rc:%d\n", rc);
+		pr_debug("state:%d update failed rc:%d\n", state, rc);
+		SDE_EVT32(caller_client->id, caller_client->current_state,
+			state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE2);
 		goto clk_disable;
 	}
 
 	pr_debug("state switch successfully complete: %d\n", state);
 	rsc->current_state = state;
+	SDE_EVT32(caller_client->id, caller_client->current_state,
+			state, rsc->current_state, SDE_EVTLOG_FUNC_EXIT);
 
 clk_disable:
-	if (rsc->power_collapse)
+	if (rsc->current_state == SDE_RSC_IDLE_STATE)
 		sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
 end:
 	mutex_unlock(&rsc->client_lock);
@@ -615,14 +629,9 @@
 			caller_client->name, ab_vote, ib_vote);
 
 	mutex_lock(&rsc->client_lock);
-	if ((caller_client->current_state == SDE_RSC_IDLE_STATE) ||
-		(rsc->current_state == SDE_RSC_IDLE_STATE)) {
-
-		pr_err("invalid state: client state:%d rsc state:%d\n",
-			caller_client->current_state, rsc->current_state);
-		rc = -EINVAL;
-		goto end;
-	}
+	rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	if (rc)
+		goto clk_enable_fail;
 
 	if (rsc->hw_ops.is_amc_mode)
 		amc_mode = rsc->hw_ops.is_amc_mode(rsc);
@@ -644,14 +653,19 @@
 		}
 	}
 
+	rpmh_invalidate(rsc->disp_rsc);
 	sde_power_data_bus_set_quota(&rsc->phandle, rsc->pclient,
 		SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, ab_vote, ib_vote);
+	rpmh_flush(rsc->disp_rsc);
 
 	if (rsc->hw_ops.tcs_use_ok)
 		rsc->hw_ops.tcs_use_ok(rsc);
 
 end:
+	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
+clk_enable_fail:
 	mutex_unlock(&rsc->client_lock);
+
 	return rc;
 }
 EXPORT_SYMBOL(sde_rsc_client_vote);
@@ -668,6 +682,10 @@
 	rsc = s->private;
 
 	mutex_lock(&rsc->client_lock);
+	ret = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	if (ret)
+		goto end;
+
 	seq_printf(s, "rsc current state:%d\n", rsc->current_state);
 	seq_printf(s, "wraper backoff time(ns):%d\n",
 				rsc->timer_config.static_wakeup_time_ns);
@@ -691,17 +709,15 @@
 		seq_printf(s, "\t client:%s state:%d\n",
 				client->name, client->current_state);
 
-	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
-
 	if (rsc->hw_ops.debug_show) {
 		ret = rsc->hw_ops.debug_show(s, rsc);
 		if (ret)
 			pr_err("sde rsc: hw debug failed ret:%d\n", ret);
 	}
-
 	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
-	mutex_unlock(&rsc->client_lock);
 
+end:
+	mutex_unlock(&rsc->client_lock);
 	return 0;
 }
 
@@ -722,20 +738,23 @@
 {
 	struct sde_rsc_priv *rsc = file->private_data;
 	char buffer[MAX_BUFFER_SIZE];
-	int blen = 0;
+	int blen = 0, rc;
 
 	if (*ppos || !rsc || !rsc->hw_ops.mode_ctrl)
 		return 0;
 
 	mutex_lock(&rsc->client_lock);
-	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	if (rc)
+		goto end;
 
 	blen = rsc->hw_ops.mode_ctrl(rsc, MODE_READ, buffer,
 							MAX_BUFFER_SIZE, 0);
 
 	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
-	mutex_unlock(&rsc->client_lock);
 
+end:
+	mutex_unlock(&rsc->client_lock);
 	if (blen < 0)
 		return 0;
 
@@ -752,6 +771,7 @@
 	struct sde_rsc_priv *rsc = file->private_data;
 	char *input, *mode;
 	u32 mode0_state = 0, mode1_state = 0, mode2_state = 0;
+	int rc;
 
 	if (!rsc || !rsc->hw_ops.mode_ctrl)
 		return 0;
@@ -767,7 +787,9 @@
 	input[count - 1] = '\0';
 
 	mutex_lock(&rsc->client_lock);
-	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	if (rc)
+		goto clk_enable_fail;
 
 	mode = strnstr(input, "mode0=", strlen("mode0="));
 	if (mode) {
@@ -794,9 +816,10 @@
 
 end:
 	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
+clk_enable_fail:
 	mutex_unlock(&rsc->client_lock);
 
-	pr_err("req: mode0:%d mode1:%d mode2:%d\n", mode0_state, mode1_state,
+	pr_info("req: mode0:%d mode1:%d mode2:%d\n", mode0_state, mode1_state,
 								mode2_state);
 	kfree(input);
 	return count;
@@ -814,20 +837,23 @@
 {
 	struct sde_rsc_priv *rsc = file->private_data;
 	char buffer[MAX_BUFFER_SIZE];
-	int blen = 0;
+	int blen = 0, rc;
 
 	if (*ppos || !rsc || !rsc->hw_ops.hw_vsync)
 		return 0;
 
 	mutex_lock(&rsc->client_lock);
-	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	if (rc)
+		goto end;
 
 	blen = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ, buffer,
 						MAX_BUFFER_SIZE, 0);
 
 	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
-	mutex_unlock(&rsc->client_lock);
 
+end:
+	mutex_unlock(&rsc->client_lock);
 	if (blen < 0)
 		return 0;
 
@@ -844,6 +870,7 @@
 	struct sde_rsc_priv *rsc = file->private_data;
 	char *input, *vsync_mode;
 	u32 vsync_state = 0;
+	int rc;
 
 	if (!rsc || !rsc->hw_ops.hw_vsync)
 		return 0;
@@ -865,7 +892,9 @@
 	}
 
 	mutex_lock(&rsc->client_lock);
-	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+	if (rc)
+		goto end;
 
 	if (vsync_state)
 		rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL,
@@ -874,8 +903,9 @@
 		rsc->hw_ops.hw_vsync(rsc, VSYNC_DISABLE, NULL, 0, 0);
 
 	sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
-	mutex_unlock(&rsc->client_lock);
 
+end:
+	mutex_unlock(&rsc->client_lock);
 	kfree(input);
 	return count;
 }
@@ -930,6 +960,8 @@
 		msm_dss_iounmap(&rsc->wrapper_io);
 	if (rsc->drv_io.base)
 		msm_dss_iounmap(&rsc->drv_io);
+	if (rsc->disp_rsc)
+		rpmh_release(rsc->disp_rsc);
 	if (rsc->pclient)
 		sde_power_client_destroy(&rsc->phandle, rsc->pclient);
 
@@ -1038,6 +1070,14 @@
 		goto sde_rsc_fail;
 	}
 
+	rsc->disp_rsc = rpmh_get_byname(pdev, "disp_rsc");
+	if (IS_ERR_OR_NULL(rsc->disp_rsc)) {
+		ret = PTR_ERR(rsc->disp_rsc);
+		rsc->disp_rsc = NULL;
+		pr_err("sde rsc:get display rsc failed ret:%d\n", ret);
+		goto sde_rsc_fail;
+	}
+
 	ret = msm_dss_ioremap_byname(pdev, &rsc->wrapper_io, "wrapper");
 	if (ret) {
 		pr_err("sde rsc: wrapper io data mapping failed ret=%d\n", ret);
@@ -1084,7 +1124,6 @@
 	snprintf(name, MAX_RSC_CLIENT_NAME_LEN, "%s%d", "sde_rsc", counter);
 	_sde_rsc_init_debugfs(rsc, name);
 	counter++;
-	rsc->power_collapse = true;
 
 	ret = component_add(&pdev->dev, &sde_rsc_comp_ops);
 	if (ret)
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index de579c1..c87dac4 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -36,6 +36,7 @@
 #define SDE_RSCC_AMC_TCS_MODE_IRQ_STATUS_DRV0		0x1c00
 
 #define SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0		0xc04
+#define SDE_RSCC_SOFT_WAKEUP_TIME_HI_DRV0		0xc08
 #define SDE_RSCC_MAX_IDLE_DURATION_DRV0			0xc0c
 #define SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0		0x1000
 #define SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0		0x1004
@@ -94,6 +95,7 @@
 #define SDE_RSCC_F1_QTMR_V1_CNTP_CTL			0x302C
 
 #define MAX_CHECK_LOOPS			500
+#define POWER_CTRL_BIT_12		12
 
 static void rsc_event_trigger(struct sde_rsc_priv *rsc, uint32_t event_type)
 {
@@ -190,27 +192,27 @@
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x18,
 						0xa138ebaa, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x1c,
-						0xe0a581e1, rsc->debug_mode);
+						0xaca581e1, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x20,
-						0x82e2a2ed, rsc->debug_mode);
+						0xe2a2ede0, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x24,
-						0x88ea8a39, rsc->debug_mode);
+						0xea8a3982, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x28,
-						0xa6e9a920, rsc->debug_mode);
+						0xa920888c, rsc->debug_mode);
 
 	/* tcs sleep sequence */
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x2c,
-						0xa92089e6, rsc->debug_mode);
+						0x89e6a6e9, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x30,
-						0x89e7a7e9, rsc->debug_mode);
+						0xa7e9a920, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x34,
-						0x00000020, rsc->debug_mode);
+						0x002079e7, rsc->debug_mode);
 
 	/* branch address */
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0,
-						0x29, rsc->debug_mode);
+						0x2b, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0,
-						0x2f, rsc->debug_mode);
+						0x31, rsc->debug_mode);
 
 	return 0;
 }
@@ -224,7 +226,9 @@
 	pr_debug("rsc solver init\n");
 
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0,
-					0x7FFFFFFF, rsc->debug_mode);
+					0xFFFFFFFF, rsc->debug_mode);
+	dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_HI_DRV0,
+					0xFFFFFFFF, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSCC_MAX_IDLE_DURATION_DRV0,
 					0xEFFFFFFF, rsc->debug_mode);
 
@@ -263,7 +267,7 @@
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0,
 					mode_0_start_addr, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE0,
-					0x80000010, rsc->debug_mode);
+					0x80000000, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0,
 			rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0,
@@ -272,7 +276,7 @@
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1,
 					mode_1_start_addr, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE1,
-					0x80000010, rsc->debug_mode);
+					0x80000000, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1,
 			rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1,
@@ -281,9 +285,9 @@
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2,
 					mode_2_start_addr, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE2,
-					0x80000010, rsc->debug_mode);
+					0x80000000, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE2,
-			rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode);
+					0x0, rsc->debug_mode);
 	dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2,
 			rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode);
 
@@ -294,6 +298,7 @@
 {
 	int rc;
 	int count, wrapper_status;
+	unsigned long reg;
 
 	if (rsc->power_collapse_block)
 		return -EINVAL;
@@ -308,6 +313,15 @@
 
 	rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_PC);
 
+	/* update qtimers to high during clk & video mode state */
+	if ((rsc->current_state == SDE_RSC_VID_STATE) ||
+			(rsc->current_state == SDE_RSC_CLK_STATE)) {
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI,
+						0xffffffff, rsc->debug_mode);
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO,
+						0xffffffff, rsc->debug_mode);
+	}
+
 	wrapper_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
 				rsc->debug_mode);
 	wrapper_status |= BIT(3);
@@ -343,6 +357,18 @@
 	if (rc) {
 		pr_err("vdd fs is still enabled\n");
 		goto end;
+	} else {
+		rc = -EINVAL;
+		/* this wait is required to turn off the rscc clocks */
+		for (count = MAX_CHECK_LOOPS; count > 0; count--) {
+			reg = dss_reg_r(&rsc->wrapper_io,
+				SDE_RSCC_PWR_CTRL, rsc->debug_mode);
+			if (test_bit(POWER_CTRL_BIT_12, &reg)) {
+				rc = 0;
+				break;
+			}
+			usleep_range(1, 2);
+		}
 	}
 
 	if ((rsc->current_state == SDE_RSC_VID_STATE) ||
@@ -357,8 +383,6 @@
 	return 0;
 
 end:
-	regulator_set_mode(rsc->fs, REGULATOR_MODE_NORMAL);
-
 	rsc_event_trigger(rsc, SDE_RSC_EVENT_POST_CORE_RESTORE);
 
 	return rc;
@@ -378,8 +402,7 @@
 	if ((state == SDE_RSC_VID_STATE) || (state == SDE_RSC_CLK_STATE)) {
 		reg = dss_reg_r(&rsc->wrapper_io,
 			SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
-		reg |= BIT(8);
-		reg &= ~(BIT(1) | BIT(0));
+		reg &= ~(BIT(8) | BIT(0));
 		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
 							reg, rsc->debug_mode);
 	}
@@ -411,7 +434,7 @@
 			rc = 0;
 			break;
 		}
-		usleep_range(1, 2);
+		usleep_range(10, 100);
 	}
 
 	reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT,
@@ -419,14 +442,9 @@
 	reg &= ~BIT(13);
 	dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT,
 							reg, rsc->debug_mode);
-
 	if (rc)
 		pr_err("vdd reg is not enabled yet\n");
 
-	rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_NORMAL);
-	if (rc)
-		pr_err("vdd reg normal mode set failed rc:%d\n", rc);
-
 	rsc_event_trigger(rsc, SDE_RSC_EVENT_POST_CORE_RESTORE);
 
 	return rc;
@@ -477,8 +495,6 @@
 		reg &= ~(BIT(1) | BIT(0));
 		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
 							reg, rsc->debug_mode);
-		dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
-							0x1, rsc->debug_mode);
 		/* make sure that solver mode is override */
 		wmb();
 
@@ -487,6 +503,14 @@
 
 	case SDE_RSC_CLK_STATE:
 		pr_debug("clk state handling\n");
+
+		reg = dss_reg_r(&rsc->wrapper_io,
+			SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
+		reg &= ~(BIT(8) | BIT(0));
+		dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
+							reg, rsc->debug_mode);
+		/* make sure that solver mode is disabled */
+		wmb();
 		break;
 
 	case SDE_RSC_IDLE_STATE:
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
index 30810fe..b83a866 100644
--- a/drivers/gpu/drm/msm/sde_rsc_priv.h
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -111,6 +111,7 @@
  * @pclient:		module power client of phandle
  * @fs:			"MDSS GDSC" handle
  *
+ * @disp_rsc:		display rsc handle
  * @drv_io:		sde drv io data mapping
  * @wrapper_io:		wrapper io data mapping
  *
@@ -141,6 +142,7 @@
 	struct sde_power_client *pclient;
 	struct regulator *fs;
 
+	struct rpmh_client *disp_rsc;
 	struct dss_io_data drv_io;
 	struct dss_io_data wrapper_io;
 
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index 28d93a9..69b639a 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -678,6 +678,7 @@
 #define A6XX_GMU_DCVS_RETURN			0x1CBFF
 #define A6XX_GMU_CM3_SYSRESET			0x1F800
 #define A6XX_GMU_CM3_BOOT_CONFIG		0x1F801
+#define A6XX_GMU_CM3_FW_BUSY			0x1F81A
 #define A6XX_GMU_CM3_FW_INIT_RESULT		0x1F81C
 #define A6XX_GMU_PWR_COL_INTER_FRAME_CTRL	0x1F8C0
 #define A6XX_GMU_PWR_COL_INTER_FRAME_HYST	0x1F8C1
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 6609357..fb41f95 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -125,7 +125,7 @@
 	unsigned int mmu_base = 0, mmu_range = 0, cur_range;
 
 	/* enable access protection to privileged registers */
-	kgsl_regwrite(device, A6XX_CP_PROTECT_CNTL, 0x00000007);
+	kgsl_regwrite(device, A6XX_CP_PROTECT_CNTL, 0x00000003);
 
 	if (mmu_prot) {
 		mmu_base = mmu_prot->base;
@@ -235,6 +235,9 @@
 	/* Set the AHB default slave response to "ERROR" */
 	kgsl_regwrite(device, A6XX_CP_AHB_CNTL, 0x1);
 
+	/* Turn on performance counters */
+	kgsl_regwrite(device, A6XX_RBBM_PERFCTR_CNTL, 0x1);
+
 	if (of_property_read_u32(device->pdev->dev.of_node,
 		"qcom,highest-bank-bit", &bit))
 		bit = MIN_HBB;
@@ -282,8 +285,9 @@
 	kgsl_regwrite(device, A6XX_UCHE_MODE_CNTL, (glbl_inv << 29) |
 						(mal << 23) | (bit << 21));
 
+	/* Set hang detection threshold to 4 million cycles (0x3FFFF*16) */
 	kgsl_regwrite(device, A6XX_RBBM_INTERFACE_HANG_INT_CNTL,
-					  (1 << 30) | 0x4000);
+					  (1 << 30) | 0x3ffff);
 
 	kgsl_regwrite(device, A6XX_UCHE_CLIENT_PF, 1);
 
@@ -857,13 +861,14 @@
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	struct gmu_device *gmu = &device->gmu;
 
-	if (!IS_ERR_OR_NULL(gmu->gx_gdsc)) {
-		ret = regulator_enable(gmu->gx_gdsc);
-		if (ret) {
-			dev_err(&gmu->pdev->dev,
-					"Failed to turn on GPU HM HS\n");
-			return ret;
-		}
+	if (regulator_is_enabled(gmu->gx_gdsc))
+		return 0;
+
+	ret = regulator_enable(gmu->gx_gdsc);
+	if (ret) {
+		dev_err(&gmu->pdev->dev,
+				"Failed to turn on GPU HM HS\n");
+		return ret;
 	}
 
 	ret = clk_set_rate(pwr->grp_clks[0],
@@ -885,15 +890,15 @@
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	struct gmu_device *gmu = &device->gmu;
 
+	if (!regulator_is_enabled(gmu->gx_gdsc))
+		return 0;
+
 	clk_disable_unprepare(pwr->grp_clks[0]);
 
 	clk_set_rate(pwr->grp_clks[0],
 			pwr->pwrlevels[pwr->num_pwrlevels - 1].
 			gpu_freq);
 
-	if (IS_ERR_OR_NULL(gmu->gx_gdsc))
-		return 0;
-
 	return regulator_disable(gmu->gx_gdsc);
 }
 
@@ -1302,16 +1307,11 @@
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
 	struct gmu_device *gmu = &device->gmu;
 
-	if (timed_poll_check(device, A6XX_GMU_RPMH_POWER_STATE,
-		gmu->idle_level, GMU_START_TIMEOUT, 0xf)) {
-		dev_err(&gmu->pdev->dev,
-			"GMU is not going to powerstate %d\n",
-			gmu->idle_level);
-		return -ETIMEDOUT;
-	}
+	/* TODO: Remove this register write when firmware is updated */
+	kgsl_gmu_regwrite(device, A6XX_GMU_CM3_FW_BUSY, 0);
 
 	if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS,
-		0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) {
+			0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) {
 		dev_err(&gmu->pdev->dev, "GMU is not idling\n");
 		return -ETIMEDOUT;
 	}
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index b1f832f..2a1d352 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -137,11 +137,8 @@
 		break;
 	}
 	case KGSL_CMD_SYNCPOINT_TYPE_FENCE: {
-		char fence_str[128];
-
-		kgsl_dump_fence(sync_event->handle,
-				fence_str, sizeof(fence_str));
-		seq_printf(s, "sync: [%pK] %s", sync_event->handle, fence_str);
+		seq_printf(s, "sync: [%pK] %s", sync_event->handle,
+				sync_event->fence_name);
 		break;
 	}
 	default:
@@ -241,6 +238,9 @@
 static void drawobj_print(struct seq_file *s,
 			struct kgsl_drawobj *drawobj)
 {
+	if (!kref_get_unless_zero(&drawobj->refcount))
+		return;
+
 	if (drawobj->type == SYNCOBJ_TYPE)
 		syncobj_print(s, SYNCOBJ(drawobj));
 	else if ((drawobj->type == CMDOBJ_TYPE) ||
@@ -251,6 +251,7 @@
 	print_flags(s, drawobj_flags, ARRAY_SIZE(drawobj_flags),
 		    drawobj->flags);
 
+	kgsl_drawobj_put(drawobj);
 	seq_puts(s, "\n");
 }
 
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index ed5b714..1cb0259 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1045,6 +1045,13 @@
 	 */
 	if (drawctxt->base.flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
 		set_bit(KGSL_FT_DISABLE, &cmdobj->fault_policy);
+	/*
+	 *  Set the fault tolerance policy to FT_REPLAY - As context wants
+	 *  to invalidate it after a replay attempt fails. This doesn't
+	 *  require to execute the default FT policy.
+	 */
+	else if (drawctxt->base.flags & KGSL_CONTEXT_INVALIDATE_ON_FAULT)
+		set_bit(KGSL_FT_REPLAY, &cmdobj->fault_policy);
 	else
 		cmdobj->fault_policy = adreno_dev->ft_policy;
 }
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 9f4e185..f217822 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -95,6 +95,9 @@
 			goto stats;
 		}
 
+		if (!kref_get_unless_zero(&drawobj->refcount))
+			goto stats;
+
 		if (drawobj->type == SYNCOBJ_TYPE) {
 			struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
 
@@ -106,6 +109,8 @@
 				kgsl_dump_syncpoints(device, syncobj);
 			}
 		}
+
+		kgsl_drawobj_put(drawobj);
 	}
 
 stats:
@@ -337,13 +342,14 @@
 	struct kgsl_device *device = dev_priv->device;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int ret;
-	unsigned long local;
+	unsigned int local;
 
 	local = *flags & (KGSL_CONTEXT_PREAMBLE |
 		KGSL_CONTEXT_NO_GMEM_ALLOC |
 		KGSL_CONTEXT_PER_CONTEXT_TS |
 		KGSL_CONTEXT_USER_GENERATED_TS |
 		KGSL_CONTEXT_NO_FAULT_TOLERANCE |
+		KGSL_CONTEXT_INVALIDATE_ON_FAULT |
 		KGSL_CONTEXT_CTX_SWITCH |
 		KGSL_CONTEXT_PRIORITY_MASK |
 		KGSL_CONTEXT_TYPE_MASK |
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 32175f5..fbff535 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -54,10 +54,21 @@
 
 	/* Read always on registers */
 	if (!adreno_is_a3xx(adreno_dev)) {
-		adreno_readreg64(adreno_dev,
-			ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
-			ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
-			&time->ticks);
+		if (kgsl_gmu_isenabled(KGSL_DEVICE(adreno_dev))) {
+			uint32_t val_lo, val_hi;
+
+			adreno_read_gmureg(adreno_dev,
+				ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO, &val_lo);
+			adreno_read_gmureg(adreno_dev,
+				ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI, &val_hi);
+
+			time->ticks = (val_lo | ((uint64_t)val_hi << 32));
+		} else {
+			adreno_readreg64(adreno_dev,
+				ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
+				ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
+				&time->ticks);
+		}
 
 		/* Mask hi bits as they may be incorrect on some targets */
 		if (ADRENO_GPUREV(adreno_dev) >= 400 &&
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2283096..8f49bc7 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1627,7 +1627,8 @@
 
 		/* If no profiling buffer was specified, clear the flag */
 		if (cmdobj->profiling_buf_entry == NULL)
-			DRAWOBJ(cmdobj)->flags &= ~KGSL_DRAWOBJ_PROFILING;
+			DRAWOBJ(cmdobj)->flags &=
+				~(unsigned long)KGSL_DRAWOBJ_PROFILING;
 	}
 
 	result = device->ftbl->queue_cmds(dev_priv, context, drawobj,
@@ -1716,7 +1717,8 @@
 
 		/* If no profiling buffer was specified, clear the flag */
 		if (cmdobj->profiling_buf_entry == NULL)
-			DRAWOBJ(cmdobj)->flags &= ~KGSL_DRAWOBJ_PROFILING;
+			DRAWOBJ(cmdobj)->flags &=
+				~(unsigned long)KGSL_DRAWOBJ_PROFILING;
 	}
 
 	result = device->ftbl->queue_cmds(dev_priv, context, drawobj,
@@ -1955,7 +1957,7 @@
 	}
 
 	handle = kgsl_sync_fence_async_wait(event.fd,
-		gpuobj_free_fence_func, entry);
+		gpuobj_free_fence_func, entry, NULL, 0);
 
 	/* if handle is NULL the fence has already signaled */
 	if (handle == NULL)
@@ -2041,7 +2043,7 @@
 	unsigned long flags_requested = (VM_READ | VM_WRITE);
 
 	if (flags & KGSL_MEMFLAGS_GPUREADONLY)
-		flags_requested &= ~VM_WRITE;
+		flags_requested &= ~(unsigned long)VM_WRITE;
 
 	if ((vma->vm_flags & flags_requested) == flags_requested)
 		return 0;
@@ -2135,7 +2137,7 @@
 	entry->memdesc.pagetable = pagetable;
 	entry->memdesc.size = (uint64_t) size;
 	entry->memdesc.useraddr = hostptr;
-	entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ADDR;
+	entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ADDR;
 
 	if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
 		int ret;
@@ -2166,7 +2168,7 @@
 static void _setup_cache_mode(struct kgsl_mem_entry *entry,
 		struct vm_area_struct *vma)
 {
-	unsigned int mode;
+	uint64_t mode;
 	pgprot_t pgprot = vma->vm_page_prot;
 
 	if (pgprot_val(pgprot) == pgprot_val(pgprot_noncached(pgprot)))
@@ -2525,7 +2527,7 @@
 	entry->memdesc.size = 0;
 	/* USE_CPU_MAP is not impemented for ION. */
 	entry->memdesc.flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);
-	entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ION;
+	entry->memdesc.flags |= (uint64_t)KGSL_MEMFLAGS_USERMEM_ION;
 
 	sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
 
@@ -3028,8 +3030,9 @@
 	if ((flags & KGSL_CACHEMODE_MASK) >> KGSL_CACHEMODE_SHIFT ==
 					KGSL_CACHEMODE_WRITETHROUGH) {
 		flags &= ~((uint64_t) KGSL_CACHEMODE_MASK);
-		flags |= (KGSL_CACHEMODE_WRITEBACK << KGSL_CACHEMODE_SHIFT) &
-							KGSL_CACHEMODE_MASK;
+		flags |= (uint64_t)((KGSL_CACHEMODE_WRITEBACK <<
+						KGSL_CACHEMODE_SHIFT) &
+					KGSL_CACHEMODE_MASK);
 	}
 	return flags;
 }
@@ -3083,8 +3086,9 @@
 			KGSL_MAX_ALIGN >> 10);
 
 		flags &= ~((uint64_t) KGSL_MEMALIGN_MASK);
-		flags |= (ilog2(KGSL_MAX_ALIGN) << KGSL_MEMALIGN_SHIFT) &
-			KGSL_MEMALIGN_MASK;
+		flags |= (uint64_t)((ilog2(KGSL_MAX_ALIGN) <<
+						KGSL_MEMALIGN_SHIFT) &
+					KGSL_MEMALIGN_MASK);
 	}
 
 	/* For now only allow allocations up to 4G */
@@ -3975,7 +3979,8 @@
 
 	if (param->flags & KGSL_GPUOBJ_SET_INFO_TYPE) {
 		entry->memdesc.flags &= ~((uint64_t) KGSL_MEMTYPE_MASK);
-		entry->memdesc.flags |= param->type << KGSL_MEMTYPE_SHIFT;
+		entry->memdesc.flags |= (uint64_t)(param->type <<
+						KGSL_MEMTYPE_SHIFT);
 	}
 
 	kgsl_mem_entry_put(entry);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index d955aa0..db105c5 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -80,6 +80,7 @@
 	{ KGSL_CONTEXT_PER_CONTEXT_TS, "PER_CONTEXT_TS" }, \
 	{ KGSL_CONTEXT_USER_GENERATED_TS, "USER_TS" }, \
 	{ KGSL_CONTEXT_NO_FAULT_TOLERANCE, "NO_FT" }, \
+	{ KGSL_CONTEXT_INVALIDATE_ON_FAULT, "INVALIDATE_ON_FAULT" }, \
 	{ KGSL_CONTEXT_PWR_CONSTRAINT, "PWR" }, \
 	{ KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" }
 
diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c
index 3a87e6e..bca3d57 100644
--- a/drivers/gpu/msm/kgsl_drawobj.c
+++ b/drivers/gpu/msm/kgsl_drawobj.c
@@ -44,7 +44,7 @@
 static struct kmem_cache *sparseobjs_cache;
 
 
-static void drawobj_destroy_object(struct kref *kref)
+void kgsl_drawobj_destroy_object(struct kref *kref)
 {
 	struct kgsl_drawobj *drawobj = container_of(kref,
 		struct kgsl_drawobj, refcount);
@@ -68,12 +68,6 @@
 	}
 }
 
-static inline void drawobj_put(struct kgsl_drawobj *drawobj)
-{
-	if (drawobj)
-		kref_put(&drawobj->refcount, drawobj_destroy_object);
-}
-
 void kgsl_dump_syncpoints(struct kgsl_device *device,
 	struct kgsl_drawobj_sync *syncobj)
 {
@@ -100,16 +94,11 @@
 				retired);
 			break;
 		}
-		case KGSL_CMD_SYNCPOINT_TYPE_FENCE: {
-			char fence_str[128];
-
-			kgsl_dump_fence(event->handle,
-					fence_str, sizeof(fence_str));
-			dev_err(device->dev,
-				"  fence: %s\n", fence_str);
+		case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
+			dev_err(device->dev, "  fence: %s\n",
+					event->fence_name);
 			break;
 		}
-		}
 	}
 }
 
@@ -117,13 +106,23 @@
 {
 	struct kgsl_device *device;
 	struct kgsl_drawobj_sync *syncobj = (struct kgsl_drawobj_sync *) data;
-	struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj);
+	struct kgsl_drawobj *drawobj;
 	struct kgsl_drawobj_sync_event *event;
 	unsigned int i;
 
-	if (syncobj == NULL || drawobj->context == NULL)
+	if (syncobj == NULL)
 		return;
 
+	drawobj = DRAWOBJ(syncobj);
+
+	if (!kref_get_unless_zero(&drawobj->refcount))
+		return;
+
+	if (drawobj->context == NULL) {
+		kgsl_drawobj_put(drawobj);
+		return;
+	}
+
 	device = drawobj->context->device;
 
 	dev_err(device->dev,
@@ -147,18 +146,14 @@
 			dev_err(device->dev, "       [%d] TIMESTAMP %d:%d\n",
 				i, event->context->id, event->timestamp);
 			break;
-		case KGSL_CMD_SYNCPOINT_TYPE_FENCE: {
-			char fence_str[128];
-
-			kgsl_dump_fence(event->handle,
-					fence_str, sizeof(fence_str));
+		case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
 			dev_err(device->dev, "       [%d] FENCE %s\n",
-				i, fence_str);
+					i, event->fence_name);
 			break;
 		}
-		}
 	}
 
+	kgsl_drawobj_put(drawobj);
 	dev_err(device->dev, "--gpu syncpoint deadlock print end--\n");
 }
 
@@ -204,7 +199,7 @@
 
 	drawobj_sync_expire(device, event);
 	kgsl_context_put(event->context);
-	drawobj_put(&event->syncobj->base);
+	kgsl_drawobj_put(&event->syncobj->base);
 }
 
 static inline void memobj_list_free(struct list_head *list)
@@ -265,7 +260,7 @@
 			break;
 		case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
 			if (kgsl_sync_fence_async_cancel(event->handle))
-				drawobj_put(drawobj);
+				kgsl_drawobj_put(drawobj);
 			break;
 		}
 	}
@@ -321,21 +316,19 @@
 	else
 		return;
 
-	drawobj_put(drawobj);
+	kgsl_drawobj_put(drawobj);
 }
 EXPORT_SYMBOL(kgsl_drawobj_destroy);
 
 static void drawobj_sync_fence_func(void *priv)
 {
 	struct kgsl_drawobj_sync_event *event = priv;
-	char fence_str[128];
 
-	kgsl_dump_fence(event->handle, fence_str, sizeof(fence_str));
-	trace_syncpoint_fence_expire(event->syncobj, fence_str);
+	trace_syncpoint_fence_expire(event->syncobj, event->fence_name);
 
 	drawobj_sync_expire(event->device, event);
 
-	drawobj_put(&event->syncobj->base);
+	kgsl_drawobj_put(&event->syncobj->base);
 }
 
 /* drawobj_add_sync_fence() - Add a new sync fence syncpoint
@@ -352,7 +345,6 @@
 	struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj);
 	struct kgsl_drawobj_sync_event *event;
 	unsigned int id;
-	char fence_str[128];
 
 	kref_get(&drawobj->refcount);
 
@@ -369,7 +361,8 @@
 	set_bit(event->id, &syncobj->pending);
 
 	event->handle = kgsl_sync_fence_async_wait(sync->fd,
-		drawobj_sync_fence_func, event);
+				drawobj_sync_fence_func, event,
+				event->fence_name, sizeof(event->fence_name));
 
 	if (IS_ERR_OR_NULL(event->handle)) {
 		int ret = PTR_ERR(event->handle);
@@ -377,7 +370,7 @@
 		clear_bit(event->id, &syncobj->pending);
 		event->handle = NULL;
 
-		drawobj_put(drawobj);
+		kgsl_drawobj_put(drawobj);
 
 		/*
 		 * If ret == 0 the fence was already signaled - print a trace
@@ -389,8 +382,7 @@
 		return ret;
 	}
 
-	kgsl_dump_fence(event->handle, fence_str, sizeof(fence_str));
-	trace_syncpoint_fence(syncobj, fence_str);
+	trace_syncpoint_fence(syncobj, event->fence_name);
 
 	return 0;
 }
@@ -457,7 +449,7 @@
 
 	if (ret) {
 		clear_bit(event->id, &syncobj->pending);
-		drawobj_put(drawobj);
+		kgsl_drawobj_put(drawobj);
 	} else {
 		trace_syncpoint_timestamp(syncobj, context, sync->timestamp);
 	}
diff --git a/drivers/gpu/msm/kgsl_drawobj.h b/drivers/gpu/msm/kgsl_drawobj.h
index 5ec98ed..06eef7f 100644
--- a/drivers/gpu/msm/kgsl_drawobj.h
+++ b/drivers/gpu/msm/kgsl_drawobj.h
@@ -105,6 +105,8 @@
 	unsigned long timeout_jiffies;
 };
 
+#define KGSL_FENCE_NAME_LEN 74
+
 /**
  * struct kgsl_drawobj_sync_event
  * @id: identifer (positiion within the pending bitmap)
@@ -114,6 +116,7 @@
  *           register this event
  * @timestamp: Pending timestamp for the event
  * @handle: Pointer to a sync fence handle
+ * @fence_name: A fence name string to describe the fence
  * @device: Pointer to the KGSL device
  */
 struct kgsl_drawobj_sync_event {
@@ -123,6 +126,7 @@
 	struct kgsl_context *context;
 	unsigned int timestamp;
 	struct kgsl_sync_fence_cb *handle;
+	char fence_name[KGSL_FENCE_NAME_LEN];
 	struct kgsl_device *device;
 };
 
@@ -206,6 +210,8 @@
 
 void kgsl_drawobj_destroy(struct kgsl_drawobj *drawobj);
 
+void kgsl_drawobj_destroy_object(struct kref *kref);
+
 static inline bool kgsl_drawobj_events_pending(
 		struct kgsl_drawobj_sync *syncobj)
 {
@@ -220,4 +226,11 @@
 
 	return test_bit(bit, &syncobj->pending);
 }
+
+static inline void kgsl_drawobj_put(struct kgsl_drawobj *drawobj)
+{
+	if (drawobj)
+		kref_put(&drawobj->refcount, kgsl_drawobj_destroy_object);
+}
+
 #endif /* __KGSL_DRAWOBJ_H */
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 416085f..0c821cd 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1369,24 +1369,39 @@
 	return ret;
 }
 
+#define GMU_IDLE_TIMEOUT	10 /* ms */
+
 /* Caller shall ensure GPU is ready for SLUMBER */
 void gmu_stop(struct kgsl_device *device)
 {
 	struct gmu_device *gmu = &device->gmu;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+	unsigned long t;
+	bool idle = false;
 
 	if (!test_bit(GMU_CLK_ON, &gmu->flags))
 		return;
 
-	if (gpudev->wait_for_gmu_idle &&
-		!gpudev->wait_for_gmu_idle(adreno_dev)) {
-		dev_err(&gmu->pdev->dev, "Failure to stop gmu");
-		return;
+	if (gpudev->hw_isidle) {
+		t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT);
+		while (!time_after(jiffies, t)) {
+			if (gpudev->hw_isidle(adreno_dev)) {
+				idle = true;
+				break;
+			}
+			cpu_relax();
+		}
 	}
 
 	gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_NOTIFY_SLUMBER, 0, 0);
 
+	if (!idle || (gpudev->wait_for_gmu_idle &&
+			gpudev->wait_for_gmu_idle(adreno_dev))) {
+		dev_err(&gmu->pdev->dev, "Failure to stop GMU");
+		return;
+	}
+
 	/* Pending message in all queues are abandoned */
 	hfi_stop(gmu);
 	clear_bit(GMU_HFI_ON, &gmu->flags);
diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h
index a2ca67c..7055eb7 100644
--- a/drivers/gpu/msm/kgsl_gmu.h
+++ b/drivers/gpu/msm/kgsl_gmu.h
@@ -146,7 +146,7 @@
 	GPU_HW_NAP = 0x4,
 	GPU_HW_MIN_VOLT = 0x5,
 	GPU_HW_MIN_DDR = 0x6,
-	GPU_HW_SLUMBER = 0xF
+	GPU_HW_SLUMBER = 0x7
 };
 
 /**
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 86d4d61..938c96d 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1608,6 +1608,8 @@
 			ret = PTR_ERR(mmu->defaultpagetable);
 			mmu->defaultpagetable = NULL;
 			return ret;
+		} else if (mmu->defaultpagetable == NULL) {
+			return -ENOMEM;
 		}
 	}
 
@@ -2598,7 +2600,7 @@
 
 static const struct {
 	char *feature;
-	int bit;
+	unsigned long bit;
 } kgsl_iommu_features[] = {
 	{ "qcom,retention", KGSL_MMU_RETENTION },
 	{ "qcom,global_pt", KGSL_MMU_GLOBAL_PAGETABLE },
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index b3e2b6a..a9a3c94 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -67,7 +67,9 @@
 	"isense_clk",
 	"rbcpr_clk",
 	"iref_clk",
-	"gmu_clk"
+	"gmu_clk",
+	"ahb_clk",
+	"cxo_clk"
 };
 
 static unsigned int ib_votes[KGSL_MAX_BUSLEVELS];
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 62ee597..6b22fd4 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -25,7 +25,7 @@
 
 #define KGSL_PWR_ON	0xFFFF
 
-#define KGSL_MAX_CLKS 15
+#define KGSL_MAX_CLKS 17
 #define KGSL_MAX_REGULATORS 2
 
 #define KGSL_MAX_PWRLEVELS 10
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index 07a54d9..7636a42 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -927,8 +927,7 @@
 				&data->bin.ctxt_aware_target_pwrlevel))
 			data->bin.ctxt_aware_target_pwrlevel = 1;
 
-		if ((data->bin.ctxt_aware_target_pwrlevel < 0) ||
-			(data->bin.ctxt_aware_target_pwrlevel >
+		if ((data->bin.ctxt_aware_target_pwrlevel >
 						pwr->num_pwrlevels))
 			data->bin.ctxt_aware_target_pwrlevel = 1;
 
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 10b37ae..dd41e4e 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -131,8 +131,9 @@
 	if (align > 32)
 		align = 32;
 
-	memdesc->flags &= ~KGSL_MEMALIGN_MASK;
-	memdesc->flags |= (align << KGSL_MEMALIGN_SHIFT) & KGSL_MEMALIGN_MASK;
+	memdesc->flags &= ~(uint64_t)KGSL_MEMALIGN_MASK;
+	memdesc->flags |= (uint64_t)((align << KGSL_MEMALIGN_SHIFT) &
+					KGSL_MEMALIGN_MASK);
 	return 0;
 }
 
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 9c078b6..973a2ff 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -431,8 +431,27 @@
 	kfree(kcb);
 }
 
+static void kgsl_get_fence_name(struct fence *fence,
+	char *fence_name, int name_len)
+{
+	char *ptr = fence_name;
+	char *last = fence_name + name_len;
+
+	ptr +=  snprintf(ptr, last - ptr, "%s %s",
+			fence->ops->get_driver_name(fence),
+			fence->ops->get_timeline_name(fence));
+
+	if ((ptr + 2) >= last)
+		return;
+
+	if (fence->ops->fence_value_str) {
+		ptr += snprintf(ptr, last - ptr, ": ");
+		fence->ops->fence_value_str(fence, ptr, last - ptr);
+	}
+}
+
 struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
-	void (*func)(void *priv), void *priv)
+	void (*func)(void *priv), void *priv, char *fence_name, int name_len)
 {
 	struct kgsl_sync_fence_cb *kcb;
 	struct fence *fence;
@@ -453,6 +472,9 @@
 	kcb->priv = priv;
 	kcb->func = func;
 
+	if (fence_name)
+		kgsl_get_fence_name(fence, fence_name, name_len);
+
 	/* if status then error or signaled */
 	status = fence_add_callback(fence, &kcb->fence_cb,
 				kgsl_sync_fence_callback);
@@ -789,43 +811,3 @@
 	.release = kgsl_syncsource_fence_release,
 };
 
-void kgsl_dump_fence(struct kgsl_sync_fence_cb *handle,
-				char *fence_str, int len)
-{
-	struct fence *fence;
-	char *ptr = fence_str;
-	char *last = fence_str + len;
-
-	if (!handle || !handle->fence) {
-		snprintf(fence_str, len, "NULL");
-		return;
-	}
-
-	fence = handle->fence;
-
-	ptr += snprintf(ptr, last - ptr, "%s %s",
-			fence->ops->get_timeline_name(fence),
-			fence->ops->get_driver_name(fence));
-	if (ptr >= last)
-		return;
-
-	if (fence->ops->timeline_value_str &&
-		fence->ops->fence_value_str) {
-		char value[64];
-		bool success;
-
-		fence->ops->fence_value_str(fence, value, sizeof(value));
-		success = !!strlen(value);
-
-		if (success) {
-			ptr += snprintf(ptr, last - ptr, ": %s", value);
-			if (ptr >= last)
-				return;
-
-			fence->ops->timeline_value_str(fence, value,
-							sizeof(value));
-			ptr += snprintf(ptr, last - ptr, " / %s", value);
-		}
-	}
-}
-
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index dc84c54..99fe0e1 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -91,7 +91,8 @@
 void kgsl_sync_timeline_put(struct kgsl_sync_timeline *ktimeline);
 
 struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
-					void (*func)(void *priv), void *priv);
+					void (*func)(void *priv), void *priv,
+					char *fence_name, int name_len);
 
 int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb);
 
@@ -109,8 +110,8 @@
 void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
 					struct kgsl_syncsource *syncsource);
 
-void kgsl_dump_fence(struct kgsl_sync_fence_cb *handle,
-				char *fence_str, int len);
+void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
+					char *fence_str, int len);
 
 #else
 static inline int kgsl_add_fence_event(struct kgsl_device *device,
@@ -134,8 +135,10 @@
 {
 }
 
-static inline struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
-					void (*func)(void *priv), void *priv)
+
+struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
+					void (*func)(void *priv), void *priv,
+					char *fence_name, int name_len)
 {
 	return NULL;
 }
@@ -185,8 +188,8 @@
 
 }
 
-void kgsl_dump_fence(struct kgsl_sync_fence_cb *handle,
-				char *fence_str, int len)
+void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
+					char *fence_str, int len)
 {
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c
index a2ce81a..8a57ed2 100644
--- a/drivers/hwtracing/coresight/coresight-cti.c
+++ b/drivers/hwtracing/coresight/coresight-cti.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -19,7 +19,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
-#include <linux/clk.h>
+#include <linux/amba/bus.h>
 #include <linux/cpu_pm.h>
 #include <linux/topology.h>
 #include <linux/of.h>
@@ -379,7 +379,7 @@
 	 * within the mutex lock region in addition to within the spinlock.
 	 */
 	if (drvdata->refcnt == 0) {
-		ret = clk_prepare_enable(drvdata->clk);
+		ret = pm_runtime_get_sync(drvdata->dev);
 		if (ret)
 			goto err1;
 	}
@@ -402,7 +402,7 @@
 	 * adjusting its value.
 	 */
 	if (drvdata->refcnt == 0)
-		clk_disable_unprepare(drvdata->clk);
+		pm_runtime_put(drvdata->dev);
 err1:
 	cti_trigin_gpio_disable(drvdata);
 err0:
@@ -463,7 +463,7 @@
 	 * within the mutex lock region in addition to within the spinlock.
 	 */
 	if (drvdata->refcnt == 0) {
-		ret = clk_prepare_enable(drvdata->clk);
+		ret = pm_runtime_get_sync(drvdata->dev);
 		if (ret)
 			goto err1;
 	}
@@ -485,7 +485,7 @@
 	 * __cti_map_trigout so it is safe to check it against 0.
 	 */
 	if (drvdata->refcnt == 0)
-		clk_disable_unprepare(drvdata->clk);
+		pm_runtime_put(drvdata->dev);
 err1:
 	cti_trigout_gpio_disable(drvdata);
 err0:
@@ -563,7 +563,7 @@
 	 * within the mutex lock region in addition to within the spinlock.
 	 */
 	if (drvdata->refcnt == 0)
-		clk_disable_unprepare(drvdata->clk);
+		pm_runtime_put(drvdata->dev);
 
 	if (drvdata->gpio_trigin->trig == trig)
 		cti_trigin_gpio_disable(drvdata);
@@ -632,7 +632,7 @@
 	 * within the mutex lock region in addition to within the spinlock.
 	 */
 	if (drvdata->refcnt == 0)
-		clk_disable_unprepare(drvdata->clk);
+		pm_runtime_put(drvdata->dev);
 
 	if (drvdata->gpio_trigout->trig == trig)
 		cti_trigout_gpio_disable(drvdata);
@@ -1388,34 +1388,29 @@
 	.notifier_call = cti_cpu_pm_callback,
 };
 
-static int cti_probe(struct platform_device *pdev)
+static int cti_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	int ret;
 	int trig;
-	struct device *dev = &pdev->dev;
+	struct device *dev = &adev->dev;
 	struct coresight_platform_data *pdata;
 	struct cti_drvdata *drvdata;
-	struct resource *res;
 	struct coresight_desc *desc;
 	struct device_node *cpu_node;
 
-	pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+	pdata = of_get_coresight_platform_data(dev, adev->dev.of_node);
 	if (IS_ERR(pdata))
 		return PTR_ERR(pdata);
-	pdev->dev.platform_data = pdata;
+	adev->dev.platform_data = pdata;
 
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 		return -ENOMEM;
 	/* Store the driver data pointer for use in exported functions */
-	drvdata->dev = &pdev->dev;
-	platform_set_drvdata(pdev, drvdata);
+	drvdata->dev = &adev->dev;
+	dev_set_drvdata(dev, drvdata);
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cti-base");
-	if (!res)
-		return -ENODEV;
-
-	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	drvdata->base = devm_ioremap_resource(dev, &adev->res);
 	if (!drvdata->base)
 		return -ENOMEM;
 
@@ -1423,21 +1418,13 @@
 
 	mutex_init(&drvdata->mutex);
 
-	drvdata->clk = devm_clk_get(dev, "core_clk");
-	if (IS_ERR(drvdata->clk))
-		return PTR_ERR(drvdata->clk);
-
-	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
-	if (ret)
-		return ret;
-
 	drvdata->gpio_trigin = devm_kzalloc(dev, sizeof(struct cti_pctrl),
 					    GFP_KERNEL);
 	if (!drvdata->gpio_trigin)
 		return -ENOMEM;
 
 	drvdata->gpio_trigin->trig = -1;
-	ret = of_property_read_u32(pdev->dev.of_node,
+	ret = of_property_read_u32(adev->dev.of_node,
 				   "qcom,cti-gpio-trigin", &trig);
 	if (!ret)
 		drvdata->gpio_trigin->trig = trig;
@@ -1450,7 +1437,7 @@
 		return -ENOMEM;
 
 	drvdata->gpio_trigout->trig = -1;
-	ret = of_property_read_u32(pdev->dev.of_node,
+	ret = of_property_read_u32(adev->dev.of_node,
 				   "qcom,cti-gpio-trigout", &trig);
 	if (!ret)
 		drvdata->gpio_trigout->trig = trig;
@@ -1458,7 +1445,7 @@
 		return ret;
 
 	drvdata->cpu = -1;
-	cpu_node = of_parse_phandle(pdev->dev.of_node, "cpu", 0);
+	cpu_node = of_parse_phandle(adev->dev.of_node, "cpu", 0);
 	if (cpu_node) {
 		drvdata->cpu = pdata ? pdata->cpu : -1;
 		if (drvdata->cpu == -1) {
@@ -1468,7 +1455,7 @@
 	}
 
 	if (!cti_save_disable)
-		drvdata->cti_save = of_property_read_bool(pdev->dev.of_node,
+		drvdata->cti_save = of_property_read_bool(adev->dev.of_node,
 							  "qcom,cti-save");
 	if (drvdata->cti_save) {
 		drvdata->state = devm_kzalloc(dev, sizeof(struct cti_state),
@@ -1476,18 +1463,18 @@
 		if (!drvdata->state)
 			return -ENOMEM;
 
-		drvdata->cti_hwclk = of_property_read_bool(pdev->dev.of_node,
+		drvdata->cti_hwclk = of_property_read_bool(adev->dev.of_node,
 							   "qcom,cti-hwclk");
 	}
 	if (drvdata->cti_save && !drvdata->cti_hwclk) {
-		ret = clk_prepare_enable(drvdata->clk);
+		ret = pm_runtime_get_sync(drvdata->dev);
 		if (ret)
 			return ret;
 	}
 
 	mutex_lock(&cti_lock);
 	drvdata->cti.name = ((struct coresight_platform_data *)
-			     (pdev->dev.platform_data))->name;
+			     (adev->dev.platform_data))->name;
 	list_add_tail(&drvdata->cti.link, &cti_list);
 	mutex_unlock(&cti_lock);
 
@@ -1497,8 +1484,8 @@
 		goto err;
 	}
 	desc->type = CORESIGHT_DEV_TYPE_NONE;
-	desc->pdata = pdev->dev.platform_data;
-	desc->dev = &pdev->dev;
+	desc->pdata = adev->dev.platform_data;
+	desc->dev = &adev->dev;
 	desc->groups = cti_attr_grps;
 	drvdata->csdev = coresight_register(desc);
 	if (IS_ERR(drvdata->csdev)) {
@@ -1511,56 +1498,35 @@
 			cpu_pm_register_notifier(&cti_cpu_pm_notifier);
 		registered++;
 	}
-
+	pm_runtime_put(&adev->dev);
 	dev_dbg(dev, "CTI initialized\n");
 	return 0;
 err:
 	if (drvdata->cti_save && !drvdata->cti_hwclk)
-		clk_disable_unprepare(drvdata->clk);
+		pm_runtime_put(&adev->dev);
 	return ret;
 }
 
-static int cti_remove(struct platform_device *pdev)
-{
-	struct cti_drvdata *drvdata = platform_get_drvdata(pdev);
-
-	if (drvdata->cti_save) {
-		registered--;
-		if (!registered)
-			cpu_pm_unregister_notifier(&cti_cpu_pm_notifier);
-	}
-	coresight_unregister(drvdata->csdev);
-	if (drvdata->cti_save && !drvdata->cti_hwclk)
-		clk_disable_unprepare(drvdata->clk);
-	return 0;
-}
-
-static const struct of_device_id cti_match[] = {
-	{.compatible = "arm,coresight-cti"},
-	{}
+static struct amba_id cti_ids[] = {
+	{
+		.id     = 0x0003b966,
+		.mask   = 0x0003ffff,
+		.data	= "CTI",
+	},
+	{ 0, 0},
 };
 
-static struct platform_driver cti_driver = {
-	.probe          = cti_probe,
-	.remove         = cti_remove,
-	.driver         = {
+static struct amba_driver cti_driver = {
+	.drv = {
 		.name   = "coresight-cti",
 		.owner	= THIS_MODULE,
-		.of_match_table = cti_match,
+		.suppress_bind_attrs = true,
 	},
+	.probe          = cti_probe,
+	.id_table	= cti_ids,
 };
 
-static int __init cti_init(void)
-{
-	return platform_driver_register(&cti_driver);
-}
-module_init(cti_init);
-
-static void __exit cti_exit(void)
-{
-	platform_driver_unregister(&cti_driver);
-}
-module_exit(cti_exit);
+builtin_amba_driver(cti_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("CoreSight CTI driver");
diff --git a/drivers/hwtracing/coresight/coresight-replicator-qcom.c b/drivers/hwtracing/coresight/coresight-replicator-qcom.c
index 0bd8b78..98547a9 100644
--- a/drivers/hwtracing/coresight/coresight-replicator-qcom.c
+++ b/drivers/hwtracing/coresight/coresight-replicator-qcom.c
@@ -47,8 +47,6 @@
 {
 	struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent);
 
-	pm_runtime_get_sync(drvdata->dev);
-
 	CS_UNLOCK(drvdata->base);
 
 	/*
@@ -85,7 +83,6 @@
 
 	CS_LOCK(drvdata->base);
 
-	pm_runtime_put(drvdata->dev);
 	dev_info(drvdata->dev, "REPLICATOR disabled\n");
 }
 
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index f5018fc..10e8da4 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -436,8 +436,11 @@
 		if (ret)
 			drvdata->size = SZ_1M;
 
+		if (of_property_read_bool(np, "arm,sg-enable"))
+			drvdata->memtype  = TMC_ETR_MEM_TYPE_SG;
+		else
+			drvdata->memtype  = TMC_ETR_MEM_TYPE_CONTIG;
 		drvdata->mem_size = drvdata->size;
-		drvdata->memtype  = TMC_ETR_MEM_TYPE_CONTIG;
 		drvdata->mem_type = drvdata->memtype;
 	} else {
 		drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index c96087d..5d2d087 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,10 +14,10 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/amba/bus.h>
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/fs.h>
-#include <linux/clk.h>
 #include <linux/bitmap.h>
 #include <linux/of.h>
 #include <linux/coresight.h>
@@ -53,7 +53,6 @@
 	void __iomem		*base;
 	struct device		*dev;
 	struct coresight_device	*csdev;
-	struct clk		*clk;
 	struct mutex		lock;
 	bool			enable;
 	uint32_t		atid;
@@ -183,11 +182,6 @@
 static int tpda_enable(struct coresight_device *csdev, int inport, int outport)
 {
 	struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-	int ret;
-
-	ret = clk_prepare_enable(drvdata->clk);
-	if (ret)
-		return ret;
 
 	mutex_lock(&drvdata->lock);
 	__tpda_enable(drvdata, inport);
@@ -221,8 +215,6 @@
 	drvdata->enable = false;
 	mutex_unlock(&drvdata->lock);
 
-	clk_disable_unprepare(drvdata->clk);
-
 	dev_info(drvdata->dev, "TPDA inport %d disabled\n", inport);
 }
 
@@ -653,31 +645,27 @@
 	drvdata->freq_ts = true;
 }
 
-static int tpda_probe(struct platform_device *pdev)
+static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	int ret;
-	struct device *dev = &pdev->dev;
+	struct device *dev = &adev->dev;
 	struct coresight_platform_data *pdata;
 	struct tpda_drvdata *drvdata;
-	struct resource *res;
 	struct coresight_desc *desc;
 
-	pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+	pdata = of_get_coresight_platform_data(dev, adev->dev.of_node);
 	if (IS_ERR(pdata))
 		return PTR_ERR(pdata);
-	pdev->dev.platform_data = pdata;
+	adev->dev.platform_data = pdata;
 
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 		return -ENOMEM;
-	drvdata->dev = &pdev->dev;
-	platform_set_drvdata(pdev, drvdata);
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tpda-base");
-	if (!res)
-		return -ENODEV;
+	drvdata->dev = &adev->dev;
+	dev_set_drvdata(dev, drvdata);
 
-	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	drvdata->base = devm_ioremap_resource(dev, &adev->res);
 	if (!drvdata->base)
 		return -ENOMEM;
 
@@ -687,22 +675,10 @@
 	if (ret)
 		return ret;
 
-	drvdata->clk = devm_clk_get(dev, "core_clk");
-	if (IS_ERR(drvdata->clk))
-		return PTR_ERR(drvdata->clk);
-
-	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
-	if (ret)
-		return ret;
-
-	ret = clk_prepare_enable(drvdata->clk);
-	if (ret)
-		return ret;
-
 	if (!coresight_authstatus_enabled(drvdata->base))
 		goto err;
 
-	clk_disable_unprepare(drvdata->clk);
+	pm_runtime_put(&adev->dev);
 
 	tpda_init_default_data(drvdata);
 
@@ -712,8 +688,8 @@
 	desc->type = CORESIGHT_DEV_TYPE_LINK;
 	desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
 	desc->ops = &tpda_cs_ops;
-	desc->pdata = pdev->dev.platform_data;
-	desc->dev = &pdev->dev;
+	desc->pdata = adev->dev.platform_data;
+	desc->dev = &adev->dev;
 	desc->groups = tpda_attr_grps;
 	drvdata->csdev = coresight_register(desc);
 	if (IS_ERR(drvdata->csdev))
@@ -722,44 +698,29 @@
 	dev_dbg(drvdata->dev, "TPDA initialized\n");
 	return 0;
 err:
-	clk_disable_unprepare(drvdata->clk);
 	return -EPERM;
 }
 
-static int tpda_remove(struct platform_device *pdev)
-{
-	struct tpda_drvdata *drvdata = platform_get_drvdata(pdev);
-
-	coresight_unregister(drvdata->csdev);
-	return 0;
-}
-
-static const struct of_device_id tpda_match[] = {
-	{.compatible = "qcom,coresight-tpda"},
-	{}
+static struct amba_id tpda_ids[] = {
+	{
+		.id     = 0x0003b969,
+		.mask   = 0x0003ffff,
+		.data	= "TPDA",
+	},
+	{ 0, 0},
 };
 
-static struct platform_driver tpda_driver = {
-	.probe          = tpda_probe,
-	.remove         = tpda_remove,
-	.driver         = {
+static struct amba_driver tpda_driver = {
+	.drv = {
 		.name   = "coresight-tpda",
 		.owner	= THIS_MODULE,
-		.of_match_table = tpda_match,
+		.suppress_bind_attrs = true,
 	},
+	.probe          = tpda_probe,
+	.id_table	= tpda_ids,
 };
 
-static int __init tpda_init(void)
-{
-	return platform_driver_register(&tpda_driver);
-}
-module_init(tpda_init);
-
-static void __exit tpda_exit(void)
-{
-	platform_driver_unregister(&tpda_driver);
-}
-module_exit(tpda_exit);
+builtin_amba_driver(tpda_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Aggregator driver");
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 69511cd..36e3db2 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -13,11 +13,10 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/fs.h>
-#include <linux/clk.h>
 #include <linux/bitmap.h>
 #include <linux/of.h>
 #include <linux/coresight.h>
@@ -246,7 +245,6 @@
 	void __iomem		*base;
 	struct device		*dev;
 	struct coresight_device	*csdev;
-	struct clk		*clk;
 	struct mutex		lock;
 	bool			enable;
 	bool			clk_enable;
@@ -648,11 +646,6 @@
 		       struct perf_event *event, u32 mode)
 {
 	struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-	int ret;
-
-	ret = clk_prepare_enable(drvdata->clk);
-	if (ret)
-		return ret;
 
 	mutex_lock(&drvdata->lock);
 	__tpdm_enable(drvdata);
@@ -732,8 +725,6 @@
 	drvdata->enable = false;
 	mutex_unlock(&drvdata->lock);
 
-	clk_disable_unprepare(drvdata->clk);
-
 	dev_info(drvdata->dev, "TPDM tracing disabled\n");
 }
 
@@ -3939,57 +3930,40 @@
 		drvdata->cmb->trig_ts = true;
 }
 
-static int tpdm_probe(struct platform_device *pdev)
+static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	int ret, i;
 	uint32_t pidr, devid;
-	struct device *dev = &pdev->dev;
+	struct device *dev = &adev->dev;
 	struct coresight_platform_data *pdata;
 	struct tpdm_drvdata *drvdata;
-	struct resource *res;
 	struct coresight_desc *desc;
 	static int traceid = TPDM_TRACE_ID_START;
 	uint32_t version;
 
-	pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+	pdata = of_get_coresight_platform_data(dev, adev->dev.of_node);
 	if (IS_ERR(pdata))
 		return PTR_ERR(pdata);
-	pdev->dev.platform_data = pdata;
+	adev->dev.platform_data = pdata;
 
 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 		return -ENOMEM;
-	drvdata->dev = &pdev->dev;
-	platform_set_drvdata(pdev, drvdata);
+	drvdata->dev = &adev->dev;
+	dev_set_drvdata(dev, drvdata);
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tpdm-base");
-	if (!res)
-		return -ENODEV;
-
-	drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+	drvdata->base = devm_ioremap_resource(dev, &adev->res);
 	if (!drvdata->base)
 		return -ENOMEM;
 
-	drvdata->clk_enable = of_property_read_bool(pdev->dev.of_node,
+	drvdata->clk_enable = of_property_read_bool(adev->dev.of_node,
 						    "qcom,clk-enable");
 
-	drvdata->msr_fix_req = of_property_read_bool(pdev->dev.of_node,
+	drvdata->msr_fix_req = of_property_read_bool(adev->dev.of_node,
 						     "qcom,msr-fix-req");
 
 	mutex_init(&drvdata->lock);
 
-	drvdata->clk = devm_clk_get(dev, "core_clk");
-	if (IS_ERR(drvdata->clk))
-		return PTR_ERR(drvdata->clk);
-
-	ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
-	if (ret)
-		return ret;
-
-	ret = clk_prepare_enable(drvdata->clk);
-	if (ret)
-		return ret;
-
 	version = tpdm_readl(drvdata, CORESIGHT_PERIPHIDR2);
 	drvdata->version = BMVAL(version, 4, 7);
 
@@ -4017,7 +3991,7 @@
 	drvdata->bc_counters_avail = BMVAL(devid, 6, 10) + 1;
 	drvdata->tc_counters_avail = BMVAL(devid, 4, 5) + 1;
 
-	clk_disable_unprepare(drvdata->clk);
+	pm_runtime_put(&adev->dev);
 
 	drvdata->traceid = traceid++;
 
@@ -4027,8 +4001,8 @@
 	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
 	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
 	desc->ops = &tpdm_cs_ops;
-	desc->pdata = pdev->dev.platform_data;
-	desc->dev = &pdev->dev;
+	desc->pdata = adev->dev.platform_data;
+	desc->dev = &adev->dev;
 	desc->groups = tpdm_attr_grps;
 	drvdata->csdev = coresight_register(desc);
 	if (IS_ERR(drvdata->csdev))
@@ -4042,40 +4016,26 @@
 	return 0;
 }
 
-static int tpdm_remove(struct platform_device *pdev)
-{
-	struct tpdm_drvdata *drvdata = platform_get_drvdata(pdev);
-
-	coresight_unregister(drvdata->csdev);
-	return 0;
-}
-
-static const struct of_device_id tpdm_match[] = {
-	{.compatible = "qcom,coresight-tpdm"},
-	{}
+static struct amba_id tpdm_ids[] = {
+	{
+		.id     = 0x0003b968,
+		.mask   = 0x0003ffff,
+		.data	= "TPDM",
+	},
+	{ 0, 0},
 };
 
-static struct platform_driver tpdm_driver = {
-	.probe          = tpdm_probe,
-	.remove         = tpdm_remove,
-	.driver         = {
+static struct amba_driver tpdm_driver = {
+	.drv = {
 		.name   = "coresight-tpdm",
 		.owner	= THIS_MODULE,
-		.of_match_table = tpdm_match,
+		.suppress_bind_attrs = true,
 	},
+	.probe          = tpdm_probe,
+	.id_table	= tpdm_ids,
 };
 
-static int __init tpdm_init(void)
-{
-	return platform_driver_register(&tpdm_driver);
-}
-module_init(tpdm_init);
-
-static void __exit tpdm_exit(void)
-{
-	platform_driver_unregister(&tpdm_driver);
-}
-module_exit(tpdm_exit);
+builtin_amba_driver(tpdm_driver);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Monitor driver");
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 94b2e2f9..e233e76 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -20,6 +20,7 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/clk.h>
+#include <dt-bindings/clock/qcom,aop-qmp.h>
 #include <linux/coresight.h>
 #include <linux/of_platform.h>
 #include <linux/delay.h>
@@ -940,6 +941,14 @@
 	atomic_t *refcnts = NULL;
 	struct coresight_device *csdev;
 	struct coresight_connection *conns = NULL;
+	struct clk *pclk;
+
+	pclk = clk_get(desc->dev, "apb_pclk");
+	if (!IS_ERR(pclk)) {
+		ret = clk_set_rate(pclk, QDSS_CLK_LEVEL_DYNAMIC);
+		if (ret)
+			dev_err(desc->dev, "clk set rate failed\n");
+	}
 
 	csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
 	if (!csdev) {
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index db7d1d6..7826994 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1118,6 +1118,7 @@
  * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
  * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
+ * Fujitsu LIFEBOOK E547   0x470f00        50, 12, 09      2 hw buttons
  * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
  * Fujitsu T725            0x470f01        05, 12, 09      2 hw buttons
  * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
@@ -1524,6 +1525,13 @@
 		},
 	},
 	{
+		/* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E547"),
+		},
+	},
+	{
 		/* Fujitsu LIFEBOOK E554  does not work with crc_enabled == 0 */
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 1864e76..dd96670 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -4375,7 +4375,7 @@
 	/* Attempt to register child devices */
 	ret = device_for_each_child(dev, smmu, qsmmuv500_tbu_register);
 	if (ret)
-		return -EINVAL;
+		return -EPROBE_DEFER;
 
 	return 0;
 }
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index c90fbf0..261c125 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1750,3 +1750,23 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
+
+/*
+ * Return the id asoociated with a pci device.
+ */
+int iommu_fwspec_get_id(struct device *dev, u32 *id)
+{
+	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+
+	if (!fwspec)
+		return -EINVAL;
+
+	if (!dev_is_pci(dev))
+		return -EINVAL;
+
+	if (fwspec->num_ids != 1)
+		return -EINVAL;
+
+	*id = fwspec->ids[0];
+	return 0;
+}
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index 96b4472..dfed3cd 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -85,7 +85,6 @@
 #define TCS_HIDDEN_CMD_SHIFT		0x08
 
 #define TCS_TYPE_NR			4
-#define TCS_MBOX_TOUT_MS		2000
 #define MAX_POOL_SIZE			(MAX_TCS_PER_TYPE * TCS_TYPE_NR)
 #define TCS_M_INIT			0xFFFF
 
@@ -97,7 +96,6 @@
 	struct tcs_mbox_msg *msg;
 	u32 m; /* m-th TCS */
 	struct tasklet_struct tasklet;
-	struct delayed_work dwork;
 	int err;
 	int idx;
 	bool in_use;
@@ -135,11 +133,12 @@
 	int num_tcs;
 	struct workqueue_struct *wq;
 	struct tcs_response_pool *resp_pool;
-	atomic_t tcs_in_use[TCS_TYPE_NR * MAX_TCS_PER_TYPE];
+	atomic_t tcs_in_use[MAX_POOL_SIZE];
+	atomic_t tcs_send_count[MAX_POOL_SIZE];
+	atomic_t tcs_irq_count[MAX_POOL_SIZE];
 };
 
 static void tcs_notify_tx_done(unsigned long data);
-static void tcs_notify_timeout(struct work_struct *work);
 
 static int tcs_response_pool_init(struct tcs_drv *drv)
 {
@@ -153,7 +152,6 @@
 	for (i = 0; i < MAX_POOL_SIZE; i++) {
 		tasklet_init(&pool->resp[i].tasklet, tcs_notify_tx_done,
 						(unsigned long) &pool->resp[i]);
-		INIT_DELAYED_WORK(&pool->resp[i].dwork, tcs_notify_timeout);
 		pool->resp[i].drv = drv;
 		pool->resp[i].idx = i;
 		pool->resp[i].m = TCS_M_INIT;
@@ -335,11 +333,6 @@
 	tasklet_schedule(&resp->tasklet);
 }
 
-static inline void schedule_tcs_err_response(struct tcs_response *resp)
-{
-	schedule_delayed_work(&resp->dwork, msecs_to_jiffies(TCS_MBOX_TOUT_MS));
-}
-
 /**
  * tcs_irq_handler: TX Done / Recv data handler
  */
@@ -361,14 +354,14 @@
 		if (!(irq_status & BIT(m)))
 			continue;
 
+		atomic_inc(&drv->tcs_irq_count[m]);
+
 		resp = get_response(drv, m);
 		if (!resp) {
 			pr_err("No resp request for TCS-%d\n", m);
 			continue;
 		}
 
-		cancel_delayed_work(&resp->dwork);
-
 		tcs = get_tcs_from_index(drv, m);
 		if (!tcs) {
 			pr_err("TCS-%d doesn't exist in DRV\n", m);
@@ -444,52 +437,6 @@
 	free_response(resp);
 }
 
-/**
- * tcs_notify_timeout: TX Done for requests that do trigger TCS, but
- * we do not get a response IRQ back.
- */
-static void tcs_notify_timeout(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct tcs_response *resp = container_of(dwork,
-					struct tcs_response, dwork);
-	struct mbox_chan *chan = resp->chan;
-	struct tcs_mbox_msg *msg = resp->msg;
-	struct tcs_drv *drv = resp->drv;
-	int m = resp->m;
-
-	/*
-	 * In case the RPMH resource fails to respond to the completion
-	 * request, the TCS would be blocked forever waiting on the response.
-	 * There is no way to recover from this case.
-	 */
-	if (!tcs_is_free(drv, m)) {
-		bool pending = false;
-		struct tcs_cmd *cmd;
-		int i;
-		u32 addr;
-
-		for (i = 0; i < msg->num_payload; i++) {
-			cmd = &msg->payload[i];
-			addr = read_tcs_reg(drv->reg_base, TCS_DRV_CMD_ADDR,
-						m, i);
-			pending |= (cmd->addr == addr);
-		}
-		if (pending) {
-			pr_err("TCS-%d blocked waiting for RPMH to respond.\n",
-				m);
-			for (i = 0; i < msg->num_payload; i++)
-				pr_err("Addr: 0x%x Data: 0x%x\n",
-						msg->payload[i].addr,
-						msg->payload[i].data);
-			BUG();
-		}
-	}
-
-	mbox_notify_tx_done(chan, msg, -1, -ETIMEDOUT);
-	free_response(resp);
-}
-
 static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n,
 			struct tcs_mbox_msg *msg, bool trigger)
 {
@@ -563,60 +510,45 @@
 	return true;
 }
 
-static void wait_for_req_inflight(struct tcs_drv *drv, struct tcs_mbox *tcs,
+static int check_for_req_inflight(struct tcs_drv *drv, struct tcs_mbox *tcs,
 						struct tcs_mbox_msg *msg)
 {
-	u32 curr_enabled;
+	u32 curr_enabled, addr;
 	int i, j, k;
-	bool is_free;
+	void __iomem *base = drv->reg_base;
+	int m = tcs->tcs_offset;
 
-	do  {
-		is_free = true;
-		for (i = 1; i > tcs->tcs_mask; i = i << 1) {
-			if (!(tcs->tcs_mask & i))
+	for (i = 0; i < tcs->num_tcs; i++, m++) {
+		if (tcs_is_free(drv, m))
+			continue;
+
+		curr_enabled = read_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0);
+		for (j = 0; j < curr_enabled; j++) {
+			if (!(curr_enabled & BIT(j)))
 				continue;
-			if (tcs_is_free(drv, i))
-				continue;
-			curr_enabled = read_tcs_reg(drv->reg_base,
-						TCS_DRV_CMD_ENABLE, i, 0);
-			for (j = 0; j < msg->num_payload; j++) {
-				for (k = 0; k < curr_enabled; k++) {
-					if (!(curr_enabled & BIT(k)))
-						continue;
-					if (tcs->cmd_addr[k] ==
-						msg->payload[j].addr) {
-						is_free = false;
-						goto retry;
-					}
-				}
+			addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, j);
+			for (k = 0; k < msg->num_payload; k++) {
+				if (addr == msg->payload[k].addr)
+					return -EBUSY;
 			}
 		}
-retry:
-		if (!is_free)
-			udelay(1);
-	} while (!is_free);
+	}
+
+	return 0;
 }
 
 static int find_free_tcs(struct tcs_mbox *tcs)
 {
-	int slot, m = 0;
-	u32 irq_status;
+	int slot = -EBUSY;
+	int m = 0;
 
 	/* Loop until we find a free AMC */
-	do {
+	for (m = 0; m < tcs->num_tcs; m++) {
 		if (tcs_is_free(tcs->drv, tcs->tcs_offset + m)) {
 			slot = m * tcs->ncpt;
 			break;
 		}
-		if (++m >= tcs->num_tcs) {
-			m = 0;
-			irq_status = read_tcs_reg(tcs->drv->reg_base,
-						TCS_DRV_IRQ_STATUS, 0, 0);
-			WARN((irq_status & tcs->tcs_mask && in_irq()),
-				"TCS busy. Request should not be made from hard IRQ context.");
-			udelay(10);
-		}
-	} while (1);
+	}
 
 	return slot;
 }
@@ -679,8 +611,9 @@
 	struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
 	int d = drv->drv_id;
 	struct tcs_mbox *tcs;
-	int i, slot, offset, m, n;
+	int i, slot, offset, m, n, ret;
 	struct tcs_response *resp = NULL;
+	unsigned long flags;
 
 	tcs = get_tcs_for_msg(drv, msg);
 	if (IS_ERR(tcs))
@@ -690,16 +623,24 @@
 		resp = setup_response(drv, msg, chan, TCS_M_INIT, 0);
 
 	/* Identify the sequential slots that we can write to */
-	spin_lock(&tcs->tcs_lock);
+	spin_lock_irqsave(&tcs->tcs_lock, flags);
 	slot = find_slots(tcs, msg);
 	if (slot < 0) {
 		dev_err(dev, "No TCS slot found.\n");
-		spin_unlock(&tcs->tcs_lock);
+		spin_unlock_irqrestore(&tcs->tcs_lock, flags);
 		if (resp)
 			free_response(resp);
 		return slot;
 	}
 
+	if (trigger) {
+		ret = check_for_req_inflight(drv, tcs, msg);
+		if (ret) {
+			spin_unlock_irqrestore(&tcs->tcs_lock, flags);
+			return ret;
+		}
+	}
+
 	/* Mark the slots as in-use, before we unlock */
 	if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
 		bitmap_set(tcs->slots, slot, msg->num_payload);
@@ -717,17 +658,13 @@
 		resp->m = m;
 		/* Mark the TCS as busy */
 		atomic_set(&drv->tcs_in_use[m], 1);
-		wait_for_req_inflight(drv, tcs, msg);
+		atomic_inc(&drv->tcs_send_count[m]);
 	}
 
 	/* Write to the TCS or AMC */
 	__tcs_buffer_write(drv, d, m, n, msg, trigger);
 
-	/* Schedule a timeout response, incase there is no actual response */
-	if (trigger)
-		schedule_tcs_err_response(resp);
-
-	spin_unlock(&tcs->tcs_lock);
+	spin_unlock_irqrestore(&tcs->tcs_lock, flags);
 
 	return 0;
 }
@@ -744,22 +681,21 @@
 	int m, i;
 	int inv_types[] = { WAKE_TCS, SLEEP_TCS };
 	int type = 0;
+	unsigned long flags;
 
 	do {
 		tcs = get_tcs_of_type(drv, inv_types[type]);
 		if (IS_ERR(tcs))
 			return PTR_ERR(tcs);
 
-		spin_lock(&tcs->tcs_lock);
+		spin_lock_irqsave(&tcs->tcs_lock, flags);
 		for (i = 0; i < tcs->num_tcs; i++) {
 			m = i + tcs->tcs_offset;
-			while (!tcs_is_free(drv, m))
-				udelay(1);
 			__tcs_buffer_invalidate(drv->reg_base, m);
 		}
 		/* Mark the TCS as free */
 		bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
-		spin_unlock(&tcs->tcs_lock);
+		spin_unlock_irqrestore(&tcs->tcs_lock, flags);
 	} while (++type < ARRAY_SIZE(inv_types));
 
 	return 0;
@@ -781,6 +717,7 @@
 	struct tcs_mbox_msg *msg = data;
 	const struct device *dev = chan->cl->dev;
 	int ret = -EINVAL;
+	int count = 0;
 
 	if (!msg) {
 		dev_err(dev, "Payload error.\n");
@@ -817,7 +754,14 @@
 		tcs_mbox_invalidate(chan);
 
 	/* Post the message to the TCS and trigger */
-	ret = tcs_mbox_write(chan, msg, true);
+	do {
+		ret = tcs_mbox_write(chan, msg, true);
+		if (ret == -EBUSY) {
+			ret = -EIO;
+			udelay(10);
+		} else
+			break;
+	} while (++count < 10);
 
 tx_fail:
 	if (ret) {
@@ -852,6 +796,7 @@
 	const struct device *dev = chan->cl->dev;
 	struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
 	struct tcs_mbox *tcs;
+	unsigned long flags;
 
 	tcs = get_tcs_of_type(drv, CONTROL_TCS);
 	if (IS_ERR(tcs))
@@ -862,9 +807,9 @@
 		return -EINVAL;
 	}
 
-	spin_lock(&tcs->tcs_lock);
+	spin_lock_irqsave(&tcs->tcs_lock, flags);
 	__tcs_write_hidden(tcs->drv, drv->drv_id, msg);
-	spin_unlock(&tcs->tcs_lock);
+	spin_unlock_irqrestore(&tcs->tcs_lock, flags);
 
 	return 0;
 }
@@ -1093,7 +1038,7 @@
 		return irq;
 
 	ret = devm_request_irq(&pdev->dev, irq, tcs_irq_handler,
-			IRQF_ONESHOT | IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
+			IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
 			"tcs_irq", drv);
 	if (ret)
 		return ret;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index e66f404..aac7161 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -69,6 +69,13 @@
 	struct dm_stats_aux stats_aux;
 };
 
+union map_info *dm_get_rq_mapinfo(struct request *rq)
+{
+	if (rq && rq->end_io_data)
+		return &((struct dm_rq_target_io *)rq->end_io_data)->info;
+	return NULL;
+}
+
 #define MINOR_ALLOCED ((void *)-1)
 
 /*
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index c897669..19de267 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -2,3 +2,4 @@
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/
 obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu/
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
index f8c864f..87707b1 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
@@ -1 +1,3 @@
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o cam_req_mgr_util.o cam_req_mgr_core.o  cam_req_mgr_workq.o
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o cam_req_mgr_util.o cam_req_mgr_core.o cam_req_mgr_workq.o cam_mem_mgr.o
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
new file mode 100644
index 0000000..f3ef0e9
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -0,0 +1,968 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-MEM-MGR %s:%d " fmt, __func__, __LINE__
+
+#ifdef CONFIG_MEM_MGR_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+#include <asm/cacheflush.h>
+
+#include "cam_req_mgr_util.h"
+#include "cam_mem_mgr.h"
+#include "cam_smmu_api.h"
+
+static struct cam_mem_table tbl;
+
+static int cam_mem_util_map_cpu_va(struct ion_handle *hdl,
+	uint64_t *vaddr,
+	size_t *len)
+{
+	*vaddr = (uintptr_t)ion_map_kernel(tbl.client, hdl);
+	if (IS_ERR_OR_NULL((void *)*vaddr)) {
+		pr_err("kernel map fail");
+		return -ENOSPC;
+	}
+
+	if (ion_handle_get_size(tbl.client, hdl, len)) {
+		pr_err("kernel get len failed");
+		ion_unmap_kernel(tbl.client, hdl);
+		return -ENOSPC;
+	}
+
+	return 0;
+}
+
+static int cam_mem_util_get_dma_dir(uint32_t flags)
+{
+	int rc = -EINVAL;
+
+	if (flags & CAM_MEM_FLAG_HW_READ_ONLY)
+		rc = DMA_TO_DEVICE;
+	else if (flags & CAM_MEM_FLAG_HW_WRITE_ONLY)
+		rc = DMA_FROM_DEVICE;
+	else if (flags & CAM_MEM_FLAG_HW_READ_WRITE)
+		rc = DMA_BIDIRECTIONAL;
+
+	return rc;
+}
+
+static int cam_mem_util_client_create(void)
+{
+	int rc = 0;
+
+	tbl.client = msm_ion_client_create("camera_global_pool");
+	if (IS_ERR_OR_NULL(tbl.client)) {
+		pr_err("fail to create client\n");
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static void cam_mem_util_client_destroy(void)
+{
+	ion_client_destroy(tbl.client);
+	tbl.client = NULL;
+}
+
+int cam_mem_mgr_init(void)
+{
+	int rc;
+	int i;
+	int bitmap_size;
+
+	memset(tbl.bufq, 0, sizeof(tbl.bufq));
+
+	rc = cam_mem_util_client_create();
+	if (rc < 0) {
+		pr_err("fail to create ion client\n");
+		goto client_fail;
+	}
+
+	bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long);
+	tbl.bitmap = kzalloc(sizeof(bitmap_size), GFP_KERNEL);
+	if (!tbl.bitmap) {
+		rc = -ENOMEM;
+		goto bitmap_fail;
+	}
+	tbl.bits = bitmap_size * BITS_PER_BYTE;
+	bitmap_zero(tbl.bitmap, tbl.bits);
+	/* We need to reserve slot 0 because 0 is invalid */
+	set_bit(0, tbl.bitmap);
+
+	for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) {
+		tbl.bufq[i].fd = -1;
+		tbl.bufq[i].buf_handle = -1;
+	}
+	mutex_init(&tbl.m_lock);
+	return rc;
+
+bitmap_fail:
+	cam_mem_util_client_destroy();
+client_fail:
+	return rc;
+}
+
+static int cam_mem_mgr_cleanup_table(void)
+{
+	int i;
+
+	mutex_lock(&tbl.m_lock);
+	for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) {
+		if (!tbl.bufq[i].active) {
+			CDBG("Buffer inactive at idx=%d, continuing\n", i);
+			continue;
+		} else {
+			pr_err("Active buffer at idx=%d, possible leak\n", i);
+		}
+
+		mutex_lock(&tbl.bufq[i].q_lock);
+		ion_free(tbl.client, tbl.bufq[i].i_hdl);
+		tbl.bufq[i].fd = -1;
+		tbl.bufq[i].flags = 0;
+		tbl.bufq[i].buf_handle = -1;
+		tbl.bufq[i].vaddr = 0;
+		tbl.bufq[i].len = 0;
+		memset(tbl.bufq[i].hdls, 0,
+			sizeof(int32_t) * tbl.bufq[i].num_hdl);
+		tbl.bufq[i].num_hdl = 0;
+		tbl.bufq[i].i_hdl = NULL;
+		tbl.bufq[i].active = false;
+		mutex_unlock(&tbl.bufq[i].q_lock);
+		mutex_destroy(&tbl.bufq[i].q_lock);
+	}
+	bitmap_zero(tbl.bitmap, tbl.bits);
+	/* We need to reserve slot 0 because 0 is invalid */
+	set_bit(0, tbl.bitmap);
+	mutex_unlock(&tbl.m_lock);
+
+	return 0;
+}
+
+void cam_mem_mgr_deinit(void)
+{
+	cam_mem_mgr_cleanup_table();
+	mutex_lock(&tbl.m_lock);
+	bitmap_zero(tbl.bitmap, tbl.bits);
+	kfree(tbl.bitmap);
+	tbl.bitmap = NULL;
+	cam_mem_util_client_destroy();
+	mutex_unlock(&tbl.m_lock);
+	mutex_destroy(&tbl.m_lock);
+}
+
+static int32_t cam_mem_get_slot(void)
+{
+	int32_t idx;
+
+	mutex_lock(&tbl.m_lock);
+	idx = find_first_zero_bit(tbl.bitmap, tbl.bits);
+	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+		mutex_unlock(&tbl.m_lock);
+		return -ENOMEM;
+	}
+
+	set_bit(idx, tbl.bitmap);
+	tbl.bufq[idx].active = true;
+	mutex_init(&tbl.bufq[idx].q_lock);
+	mutex_unlock(&tbl.m_lock);
+
+	return idx;
+}
+
+static void cam_mem_put_slot(int32_t idx)
+{
+	mutex_lock(&tbl.m_lock);
+	mutex_lock(&tbl.bufq[idx].q_lock);
+	tbl.bufq[idx].active = false;
+	mutex_unlock(&tbl.bufq[idx].q_lock);
+	mutex_destroy(&tbl.bufq[idx].q_lock);
+	clear_bit(idx, tbl.bitmap);
+	mutex_unlock(&tbl.m_lock);
+}
+
+int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle,
+	uint64_t *iova_ptr, size_t *len_ptr)
+{
+	int rc = 0, idx;
+
+	idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
+	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+		return -EINVAL;
+
+	if (!tbl.bufq[idx].active)
+		return -EINVAL;
+
+	mutex_lock(&tbl.bufq[idx].q_lock);
+	if (buf_handle != tbl.bufq[idx].buf_handle) {
+		rc = -EINVAL;
+		goto handle_mismatch;
+	}
+
+	rc = cam_smmu_get_iova(mmu_handle,
+		tbl.bufq[idx].fd,
+		iova_ptr,
+		len_ptr);
+	if (rc < 0)
+		pr_err("fail to get buf hdl :%d", buf_handle);
+
+handle_mismatch:
+	mutex_unlock(&tbl.bufq[idx].q_lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_mem_get_io_buf);
+
+int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr, size_t *len)
+{
+	int rc = 0;
+	int idx;
+	struct ion_handle *ion_hdl = NULL;
+	uint64_t kvaddr = 0;
+	size_t klen = 0;
+
+	if (!buf_handle || !vaddr_ptr || !len)
+		return -EINVAL;
+
+	idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
+	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+		return -EINVAL;
+
+	if (!tbl.bufq[idx].active)
+		return -EPERM;
+
+	mutex_lock(&tbl.bufq[idx].q_lock);
+	if (buf_handle != tbl.bufq[idx].buf_handle) {
+		rc = -EINVAL;
+		goto exit_func;
+	}
+
+	ion_hdl = tbl.bufq[idx].i_hdl;
+	if (!ion_hdl) {
+		pr_err("Invalid ION handle\n");
+		rc = -EINVAL;
+		goto exit_func;
+	}
+
+	if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) {
+		if (!tbl.bufq[idx].kmdvaddr) {
+			rc = cam_mem_util_map_cpu_va(ion_hdl,
+				&kvaddr, &klen);
+			if (rc)
+				goto exit_func;
+			tbl.bufq[idx].kmdvaddr = kvaddr;
+		}
+	} else {
+		rc = -EINVAL;
+		goto exit_func;
+	}
+
+	*vaddr_ptr = tbl.bufq[idx].kmdvaddr;
+	*len = tbl.bufq[idx].len;
+
+exit_func:
+	mutex_unlock(&tbl.bufq[idx].q_lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_mem_get_cpu_buf);
+
+int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd)
+{
+	int rc = 0, idx;
+	uint32_t ion_cache_ops;
+	unsigned long ion_flag = 0;
+
+	if (!cmd)
+		return -EINVAL;
+
+	idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle);
+	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+		return -EINVAL;
+
+	mutex_lock(&tbl.bufq[idx].q_lock);
+
+	if (!tbl.bufq[idx].active) {
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	if (cmd->buf_handle != tbl.bufq[idx].buf_handle) {
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	rc = ion_handle_get_flags(tbl.client, tbl.bufq[idx].i_hdl,
+		&ion_flag);
+	if (rc) {
+		pr_err("cache get flags failed %d\n", rc);
+		goto fail;
+	}
+
+	if (ION_IS_CACHED(ion_flag)) {
+		switch (cmd->mem_cache_ops) {
+		case CAM_MEM_CLEAN_CACHE:
+			ion_cache_ops = ION_IOC_CLEAN_CACHES;
+			break;
+		case CAM_MEM_INV_CACHE:
+			ion_cache_ops = ION_IOC_INV_CACHES;
+			break;
+		case CAM_MEM_CLEAN_INV_CACHE:
+			ion_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+			break;
+		default:
+			pr_err("invalid cache ops :%d", cmd->mem_cache_ops);
+			rc = -EINVAL;
+			goto fail;
+		}
+
+		rc = msm_ion_do_cache_op(tbl.client,
+				tbl.bufq[idx].i_hdl,
+				(void *)tbl.bufq[idx].vaddr,
+				tbl.bufq[idx].len,
+				ion_cache_ops);
+		if (rc)
+			pr_err("cache operation failed %d\n", rc);
+	}
+fail:
+	mutex_unlock(&tbl.bufq[idx].q_lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_cache_ops);
+
+static int cam_mem_util_get_ion_buffer(size_t len,
+	size_t align,
+	unsigned int heap_id_mask,
+	unsigned int flags,
+	struct ion_handle **hdl,
+	int *fd)
+{
+	int rc = 0;
+
+	*hdl = ion_alloc(tbl.client, len, align, heap_id_mask, flags);
+	if (IS_ERR_OR_NULL(*hdl))
+		return -ENOMEM;
+
+	*fd = ion_share_dma_buf_fd(tbl.client, *hdl);
+	if (*fd < 0) {
+		pr_err("dma buf get fd fail");
+		rc = -EINVAL;
+		goto get_fd_fail;
+	}
+
+	return rc;
+
+get_fd_fail:
+	ion_free(tbl.client, *hdl);
+	return rc;
+}
+
+static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd,
+	struct ion_handle **hdl,
+	int *fd)
+{
+	uint32_t heap_id;
+	uint32_t ion_flag = 0;
+	int rc;
+
+	if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)
+		heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID);
+	else
+		heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+
+	if (cmd->flags & CAM_MEM_FLAG_CACHE)
+		ion_flag |= ION_FLAG_CACHED;
+	else
+		ion_flag &= ~ION_FLAG_CACHED;
+
+	rc = cam_mem_util_get_ion_buffer(cmd->len,
+		cmd->align,
+		heap_id,
+		ion_flag,
+		hdl,
+		fd);
+
+	return rc;
+}
+
+
+static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd)
+{
+	if (!cmd->flags) {
+		pr_err("Invalid flags\n");
+		return -EINVAL;
+	}
+
+	if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) {
+		pr_err("Num of mmu hdl exceeded maximum(%d)\n",
+			CAM_MEM_MMU_MAX_HANDLE);
+		return -EINVAL;
+	}
+
+	if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE &&
+		cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) {
+		pr_err("Kernel mapping in secure mode not allowed");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd)
+{
+	if (!cmd->flags) {
+		pr_err("Invalid flags\n");
+		return -EINVAL;
+	}
+
+	if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) {
+		pr_err("Num of mmu hdl exceeded maximum(%d)\n",
+			CAM_MEM_MMU_MAX_HANDLE);
+		return -EINVAL;
+	}
+
+	if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE &&
+		cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) {
+		pr_err("Kernel mapping in secure mode not allowed");
+		return -EINVAL;
+	}
+
+	if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
+		pr_err("Shared memory buffers are not allowed to be mapped\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cam_mem_util_map_hw_va(uint32_t flags,
+	int32_t *mmu_hdls,
+	int32_t num_hdls,
+	int fd,
+	dma_addr_t *hw_vaddr,
+	size_t *len,
+	enum cam_smmu_region_id region)
+{
+	int i;
+	int rc = -1;
+	int dir = cam_mem_util_get_dma_dir(flags);
+
+	if (dir < 0) {
+		pr_err("fail to map DMA direction\n");
+		return dir;
+	}
+
+	if (flags & CAM_MEM_FLAG_PROTECTED_MODE) {
+		for (i = 0; i < num_hdls; i++) {
+			rc = cam_smmu_map_sec_iova(mmu_hdls[i],
+				fd,
+				dir,
+				(dma_addr_t *)hw_vaddr,
+				len);
+
+			if (rc < 0) {
+				pr_err("Failed to securely map to smmu");
+				goto multi_map_fail;
+			}
+		}
+	} else {
+		for (i = 0; i < num_hdls; i++) {
+			rc = cam_smmu_map_iova(mmu_hdls[i],
+				fd,
+				dir,
+				(dma_addr_t *)hw_vaddr,
+				len,
+				region);
+
+			if (rc < 0) {
+				pr_err("Failed to map to smmu");
+				goto multi_map_fail;
+			}
+		}
+	}
+
+	return rc;
+multi_map_fail:
+	if (flags & CAM_MEM_FLAG_PROTECTED_MODE)
+		for (--i; i > 0; i--)
+			cam_smmu_unmap_sec_iova(mmu_hdls[i], fd);
+	else
+		for (--i; i > 0; i--)
+			cam_smmu_unmap_iova(mmu_hdls[i],
+				fd,
+				CAM_SMMU_REGION_IO);
+	return rc;
+
+}
+
+int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd)
+{
+	int rc;
+	int32_t idx;
+	struct ion_handle *ion_hdl;
+	int ion_fd;
+	dma_addr_t hw_vaddr = 0;
+	size_t len;
+
+	if (!cmd) {
+		pr_err(" Invalid argument\n");
+		return -EINVAL;
+	}
+	len = cmd->len;
+
+	rc = cam_mem_util_check_flags(cmd);
+	if (rc) {
+		pr_err("Invalid flags: flags = %X\n", cmd->flags);
+		return rc;
+	}
+
+	rc = cam_mem_util_ion_alloc(cmd,
+		&ion_hdl,
+		&ion_fd);
+	if (rc) {
+		pr_err("Ion allocation failed\n");
+		return rc;
+	}
+
+	idx = cam_mem_get_slot();
+	if (idx < 0) {
+		rc = -ENOMEM;
+		goto slot_fail;
+	}
+
+	if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE ||
+		cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
+
+		enum cam_smmu_region_id region;
+
+		if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE)
+			region = CAM_SMMU_REGION_IO;
+
+
+		if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
+			region = CAM_SMMU_REGION_SHARED;
+
+		rc = cam_mem_util_map_hw_va(cmd->flags,
+			cmd->mmu_hdls,
+			cmd->num_hdl,
+			ion_fd,
+			&hw_vaddr,
+			&len,
+			region);
+		if (rc)
+			goto map_hw_fail;
+	}
+
+	mutex_lock(&tbl.bufq[idx].q_lock);
+	tbl.bufq[idx].fd = ion_fd;
+	tbl.bufq[idx].flags = cmd->flags;
+	tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, ion_fd);
+	tbl.bufq[idx].kmdvaddr = 0;
+
+	if (cmd->num_hdl > 0)
+		tbl.bufq[idx].vaddr = hw_vaddr;
+	else
+		tbl.bufq[idx].vaddr = 0;
+
+	tbl.bufq[idx].i_hdl = ion_hdl;
+	tbl.bufq[idx].len = cmd->len;
+	tbl.bufq[idx].num_hdl = cmd->num_hdl;
+	memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,
+		sizeof(int32_t) * cmd->num_hdl);
+	tbl.bufq[idx].is_imported = false;
+	mutex_unlock(&tbl.bufq[idx].q_lock);
+
+	cmd->out.buf_handle = tbl.bufq[idx].buf_handle;
+	cmd->out.fd = tbl.bufq[idx].fd;
+	cmd->out.vaddr = 0;
+
+	CDBG("buf handle: %x, fd: %d, len: %zu\n",
+		cmd->out.buf_handle, cmd->out.fd,
+		tbl.bufq[idx].len);
+
+	return rc;
+
+map_hw_fail:
+	cam_mem_put_slot(idx);
+slot_fail:
+	ion_free(tbl.client, ion_hdl);
+	return rc;
+}
+
+int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd)
+{
+	int32_t idx;
+	int rc;
+	struct ion_handle *ion_hdl;
+	dma_addr_t hw_vaddr = 0;
+	size_t len = 0;
+
+	if (!cmd || (cmd->fd < 0)) {
+		pr_err("Invalid argument\n");
+		return -EINVAL;
+	}
+
+	if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE)
+		return -EINVAL;
+
+	rc = cam_mem_util_check_map_flags(cmd);
+	if (rc) {
+		pr_err("Invalid flags: flags = %X\n", cmd->flags);
+		return rc;
+	}
+
+	ion_hdl = ion_import_dma_buf_fd(tbl.client, cmd->fd);
+	if (IS_ERR_OR_NULL((void *)(ion_hdl))) {
+		pr_err("Failed to import ion fd\n");
+		return -EINVAL;
+	}
+
+	if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) {
+		rc = cam_mem_util_map_hw_va(cmd->flags,
+			cmd->mmu_hdls,
+			cmd->num_hdl,
+			cmd->fd,
+			&hw_vaddr,
+			&len,
+			CAM_SMMU_REGION_IO);
+		if (rc)
+			goto map_fail;
+	}
+
+	idx = cam_mem_get_slot();
+	if (idx < 0) {
+		rc = -ENOMEM;
+		goto map_fail;
+	}
+
+	mutex_lock(&tbl.bufq[idx].q_lock);
+	tbl.bufq[idx].fd = cmd->fd;
+	tbl.bufq[idx].flags = cmd->flags;
+	tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, cmd->fd);
+	tbl.bufq[idx].kmdvaddr = 0;
+
+	if (cmd->num_hdl > 0)
+		tbl.bufq[idx].vaddr = hw_vaddr;
+	else
+		tbl.bufq[idx].vaddr = 0;
+
+	tbl.bufq[idx].i_hdl = ion_hdl;
+	tbl.bufq[idx].len = len;
+	tbl.bufq[idx].num_hdl = cmd->num_hdl;
+	memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,
+		sizeof(int32_t) * cmd->num_hdl);
+	tbl.bufq[idx].is_imported = true;
+	mutex_unlock(&tbl.bufq[idx].q_lock);
+
+	cmd->out.buf_handle = tbl.bufq[idx].buf_handle;
+	cmd->out.vaddr = 0;
+
+	return rc;
+
+map_fail:
+	ion_free(tbl.client, ion_hdl);
+	return rc;
+}
+
+static int cam_mem_util_unmap_hw_va(int32_t idx,
+	enum cam_smmu_region_id region)
+{
+	int i;
+	uint32_t flags;
+	int32_t *mmu_hdls;
+	int num_hdls;
+	int fd;
+	int rc = -EINVAL;
+
+	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+		pr_err("Incorrect index\n");
+		return rc;
+	}
+
+	flags = tbl.bufq[idx].flags;
+	mmu_hdls = tbl.bufq[idx].hdls;
+	num_hdls = tbl.bufq[idx].num_hdl;
+	fd = tbl.bufq[idx].fd;
+
+	if (flags & CAM_MEM_FLAG_PROTECTED_MODE) {
+		for (i = 0; i < num_hdls; i++) {
+			rc = cam_smmu_unmap_sec_iova(mmu_hdls[i], fd);
+			if (rc < 0)
+				goto unmap_end;
+		}
+	} else {
+		for (i = 0; i < num_hdls; i++) {
+			rc = cam_smmu_unmap_iova(mmu_hdls[i],
+				fd,
+				region);
+			if (rc < 0)
+				goto unmap_end;
+		}
+	}
+
+unmap_end:
+	return rc;
+}
+
+static int cam_mem_util_unmap(int32_t idx)
+{
+	int rc = 0;
+	enum cam_smmu_region_id region;
+
+	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+		pr_err("Incorrect index\n");
+		return -EINVAL;
+	}
+
+	CDBG("Flags = %X\n", tbl.bufq[idx].flags);
+
+	if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)
+		if (tbl.bufq[idx].i_hdl && tbl.bufq[idx].kmdvaddr)
+			ion_unmap_kernel(tbl.client, tbl.bufq[idx].i_hdl);
+
+	if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE)
+		region = CAM_SMMU_REGION_IO;
+
+	if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
+		region = CAM_SMMU_REGION_SHARED;
+
+	rc = cam_mem_util_unmap_hw_va(idx,
+		region);
+
+	mutex_lock(&tbl.bufq[idx].q_lock);
+	tbl.bufq[idx].flags = 0;
+	tbl.bufq[idx].buf_handle = -1;
+	tbl.bufq[idx].vaddr = 0;
+	memset(tbl.bufq[idx].hdls, 0,
+		sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE);
+
+	CDBG("Ion handle at idx = %d freeing = %pK, fd = %d\n",
+		idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd);
+
+	if (tbl.bufq[idx].i_hdl && !tbl.bufq[idx].is_imported) {
+		CDBG("Freeing up non-imported buffer at fd = %d, hdl = %pK",
+			tbl.bufq[idx].fd,
+			tbl.bufq[idx].i_hdl);
+		ion_free(tbl.client, tbl.bufq[idx].i_hdl);
+		tbl.bufq[idx].i_hdl = NULL;
+	} else {
+		CDBG("Not freeing up imported buffer at fd = %d",
+			tbl.bufq[idx].fd);
+	}
+
+	tbl.bufq[idx].fd = -1;
+	tbl.bufq[idx].is_imported = false;
+	tbl.bufq[idx].i_hdl = NULL;
+	tbl.bufq[idx].len = 0;
+	tbl.bufq[idx].num_hdl = 0;
+	mutex_unlock(&tbl.bufq[idx].q_lock);
+	cam_mem_put_slot(idx);
+
+	return rc;
+}
+
+int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd)
+{
+	int idx;
+	int rc;
+
+	if (!cmd) {
+		pr_err("Invalid argument\n");
+		return -EINVAL;
+	}
+
+	idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle);
+	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+		pr_err("Incorrect index extracted from mem handle\n");
+		return -EINVAL;
+	}
+
+	if (!tbl.bufq[idx].active) {
+		pr_err("Released buffer state should be active\n");
+		return -EINVAL;
+	}
+
+	if (tbl.bufq[idx].buf_handle != cmd->buf_handle) {
+		pr_err("Released buf handle not matching within table\n");
+		return -EINVAL;
+	}
+
+	CDBG("Releasing hdl = %u\n", cmd->buf_handle);
+	rc = cam_mem_util_unmap(idx);
+
+	return rc;
+}
+
+int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
+	struct cam_mem_mgr_memory_desc *out)
+{
+	struct ion_handle *hdl;
+	int ion_fd;
+	int rc = 0;
+	uint32_t heap_id;
+	int32_t ion_flag = 0;
+	uint64_t kvaddr;
+	dma_addr_t iova = 0;
+	size_t request_len = 0;
+	int32_t idx;
+	uint32_t mem_handle;
+	int32_t smmu_hdl = 0;
+	int32_t num_hdl = 0;
+	enum cam_smmu_region_id region;
+
+	if (!inp || !out) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	if (inp->region != CAM_MEM_MGR_REGION_SHARED &&
+		inp->region != CAM_MEM_MGR_REGION_NON_SECURE_IO) {
+		pr_err("Invalid flags for request mem\n");
+		return -EINVAL;
+	}
+
+	if (inp->flags & CAM_MEM_FLAG_CACHE)
+		ion_flag |= ION_FLAG_CACHED;
+	else
+		ion_flag &= ~ION_FLAG_CACHED;
+
+	heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+
+	rc = cam_mem_util_get_ion_buffer(inp->size,
+		inp->align,
+		heap_id,
+		ion_flag,
+		&hdl,
+		&ion_fd);
+
+	if (rc) {
+		pr_err("ION alloc failed for shared buffer\n");
+		goto ion_fail;
+	} else {
+		CDBG("Got ION fd = %d, hdl = %pK\n", ion_fd, hdl);
+	}
+
+	rc = cam_mem_util_map_cpu_va(hdl, &kvaddr, &request_len);
+	if (rc) {
+		pr_err("Failed to get kernel vaddr\n");
+		goto map_fail;
+	}
+
+	if (!inp->smmu_hdl) {
+		pr_err("Invalid SMMU handle\n");
+		rc = -EINVAL;
+		goto smmu_fail;
+	}
+
+	if (inp->region == CAM_MEM_MGR_REGION_SHARED)
+		region = CAM_SMMU_REGION_SHARED;
+
+	if (inp->region == CAM_MEM_MGR_REGION_NON_SECURE_IO)
+		region = CAM_SMMU_REGION_IO;
+
+	rc = cam_smmu_map_iova(inp->smmu_hdl,
+		ion_fd,
+		CAM_SMMU_MAP_RW,
+		&iova,
+		&request_len,
+		region);
+
+	if (rc < 0) {
+		pr_err("SMMU mapping failed\n");
+		goto smmu_fail;
+	}
+
+	smmu_hdl = inp->smmu_hdl;
+	num_hdl = 1;
+
+	idx = cam_mem_get_slot();
+	if (idx < 0) {
+		rc = -ENOMEM;
+		goto slot_fail;
+	}
+
+	mutex_lock(&tbl.bufq[idx].q_lock);
+	mem_handle = GET_MEM_HANDLE(idx, ion_fd);
+	tbl.bufq[idx].fd = ion_fd;
+	tbl.bufq[idx].flags = inp->flags;
+	tbl.bufq[idx].buf_handle = mem_handle;
+	tbl.bufq[idx].kmdvaddr = kvaddr;
+
+	tbl.bufq[idx].vaddr = iova;
+
+	tbl.bufq[idx].i_hdl = hdl;
+	tbl.bufq[idx].len = inp->size;
+	tbl.bufq[idx].num_hdl = num_hdl;
+	memcpy(tbl.bufq[idx].hdls, &smmu_hdl,
+		sizeof(int32_t));
+	tbl.bufq[idx].is_imported = false;
+	mutex_unlock(&tbl.bufq[idx].q_lock);
+
+	out->kva = kvaddr;
+	out->iova = (uint32_t)iova;
+	out->smmu_hdl = smmu_hdl;
+	out->mem_handle = mem_handle;
+	out->len = inp->size;
+	out->region = inp->region;
+
+	return rc;
+slot_fail:
+	cam_smmu_unmap_iova(inp->smmu_hdl,
+		ion_fd,
+		inp->region);
+smmu_fail:
+	ion_unmap_kernel(tbl.client, hdl);
+map_fail:
+	ion_free(tbl.client, hdl);
+ion_fail:
+	return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_request_mem);
+
+int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp)
+{
+	int32_t idx;
+	int rc;
+
+	if (!inp) {
+		pr_err("Invalid argument\n");
+		return -EINVAL;
+	}
+
+	idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle);
+	if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+		pr_err("Incorrect index extracted from mem handle\n");
+		return -EINVAL;
+	}
+
+	if (!tbl.bufq[idx].active) {
+		pr_err("Released buffer state should be active\n");
+		return -EINVAL;
+	}
+
+	if (tbl.bufq[idx].buf_handle != inp->mem_handle) {
+		pr_err("Released buf handle not matching within table\n");
+		return -EINVAL;
+	}
+
+	CDBG("Releasing hdl = %X\n", inp->mem_handle);
+	rc = cam_mem_util_unmap(idx);
+
+	return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_release_mem);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h
new file mode 100644
index 0000000..c5f839b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h
@@ -0,0 +1,121 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_MEM_MGR_H_
+#define _CAM_MEM_MGR_H_
+
+#include <media/cam_req_mgr.h>
+#include "cam_mem_mgr_api.h"
+
+#define CAM_MEM_BUFQ_MAX 1024
+
+/**
+ * struct cam_mem_buf_queue
+ *
+ * @i_hdl:       ion handle for the buffer
+ * @q_lock:      mutex lock for buffer
+ * @hdls:        list of mapped handles
+ * @num_hdl:     number of handles
+ * @fd:          file descriptor of buffer
+ * @buf_handle:  unique handle for buffer
+ * @align:       alignment for allocation
+ * @len:         size of buffer
+ * @flags:       attributes of buffer
+ * @vaddr:       IOVA of buffer
+ * @kmdvaddr:    Kernel virtual address
+ * @active:      state of the buffer
+ * @is_imported: Flag indicating if buffer is imported from an FD in user space
+ */
+struct cam_mem_buf_queue {
+	struct ion_handle *i_hdl;
+	struct mutex q_lock;
+	int32_t hdls[CAM_MEM_MMU_MAX_HANDLE];
+	int32_t num_hdl;
+	int32_t fd;
+	int32_t buf_handle;
+	int32_t align;
+	size_t len;
+	uint32_t flags;
+	uint64_t vaddr;
+	uint64_t kmdvaddr;
+	bool active;
+	bool is_imported;
+};
+
+/**
+ * struct cam_mem_table
+ *
+ * @m_lock: mutex lock for table
+ * @bitmap: bitmap of the mem mgr utility
+ * @bits: max bits of the utility
+ * @client: ion client pointer
+ * @bufq: array of buffers
+ */
+struct cam_mem_table {
+	struct mutex m_lock;
+	void *bitmap;
+	size_t bits;
+	struct ion_client *client;
+	struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX];
+};
+
+/**
+ * @brief: Allocates and maps buffer
+ *
+ * @cmd:   Allocation information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd);
+
+/**
+ * @brief: Releases a buffer reference
+ *
+ * @cmd:   Buffer release information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd);
+
+/**
+ * @brief Maps a buffer
+ *
+ * @cmd: Buffer mapping information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd);
+
+/**
+ * @brief: Perform cache ops on the buffer
+ *
+ * @cmd:   Cache ops information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd);
+
+/**
+ * @brief: Initializes the memory manager
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_init(void);
+
+/**
+ * @brief:  Tears down the memory manager
+ *
+ * @return None
+ */
+void cam_mem_mgr_deinit(void);
+
+#endif /* _CAM_MEM_MGR_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
new file mode 100644
index 0000000..32a754e
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
@@ -0,0 +1,105 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CAM_MEM_MGR_API_H_
+#define _CAM_MEM_MGR_API_H_
+
+#include <media/cam_req_mgr.h>
+
+/* Region IDs for memory manager */
+#define CAM_MEM_MGR_REGION_FIRMWARE      0
+#define CAM_MEM_MGR_REGION_SHARED        1
+#define CAM_MEM_MGR_REGION_NON_SECURE_IO 2
+#define CAM_MEM_MGR_REGION_SECURE_IO     3
+#define CAM_MEM_MGR_REGION_SCRATCH       4
+
+/**
+ * struct cam_mem_mgr_request_desc
+ *
+ * @size    : Size of memory requested for allocation
+ * @align   : Alignment of requested memory
+ * @smmu_hdl: SMMU handle to identify context bank where memory will be mapped
+ * @flags   : Flags to indicate cached/uncached property
+ * @region  : Region where memory should be allocated
+ */
+struct cam_mem_mgr_request_desc {
+	uint64_t size;
+	uint64_t align;
+	int32_t smmu_hdl;
+	uint32_t flags;
+	uint32_t region;
+};
+
+/**
+ * struct cam_mem_mgr_memory_desc
+ *
+ * @kva        : Kernel virtual address of allocated memory
+ * @iova       : IOVA of allocated memory
+ * @smmu_hdl   : SMMU handle of allocated memory
+ * @mem_handle : Mem handle identifying allocated memory
+ * @len        : Length of allocated memory
+ * @region     : Region to which allocated memory belongs
+ */
+struct cam_mem_mgr_memory_desc {
+	uint64_t kva;
+	uint32_t iova;
+	int32_t smmu_hdl;
+	uint32_t mem_handle;
+	uint64_t len;
+	uint32_t region;
+};
+
+/**
+ * @brief: Requests a memory buffer
+ *
+ * @inp:   Information specifying requested buffer properties
+ * @out:   Information about allocated buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
+	struct cam_mem_mgr_memory_desc *out);
+
+/**
+ * @brief: Releases a memory buffer
+ *
+ * @inp:   Information specifying buffer to be released
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp);
+
+/**
+ * @brief: Returns IOVA information about buffer
+ *
+ * @buf_handle: Handle of the buffer
+ * @mmu_handle: SMMU handle where buffer is mapped
+ * @iova_ptr  : Pointer to mmu's iova
+ * @len_ptr   : Length of the buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle,
+	uint64_t *iova_ptr, size_t *len_ptr);
+/**
+ * @brief: Returns CPU address information about buffer
+ *
+ * @buf_handle: Handle for the buffer
+ * @vaddr_ptr : pointer to kernel virtual address
+ * @len_ptr   : Length of the buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr,
+	size_t *len);
+
+#endif /* _CAM_MEM_MGR_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index f3af1bd..43b020c6 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
 #include "cam_req_mgr_util.h"
 #include "cam_req_mgr_core.h"
 #include "cam_subdev.h"
+#include "cam_mem_mgr.h"
 
 #define CAM_REQ_MGR_EVENT_MAX 30
 
@@ -115,7 +116,18 @@
 	spin_unlock_bh(&g_dev.cam_eventq_lock);
 
 	g_dev.open_cnt++;
+	rc = cam_mem_mgr_init();
+	if (rc) {
+		g_dev.open_cnt--;
+		pr_err("mem mgr init failed\n");
+		goto mem_mgr_init_fail;
+	}
 
+	mutex_unlock(&g_dev.cam_lock);
+	return rc;
+
+mem_mgr_init_fail:
+	v4l2_fh_release(filep);
 end:
 	mutex_unlock(&g_dev.cam_lock);
 	return rc;
@@ -154,6 +166,7 @@
 	spin_unlock_bh(&g_dev.cam_eventq_lock);
 
 	cam_req_mgr_util_free_hdls();
+	cam_mem_mgr_deinit();
 	mutex_unlock(&g_dev.cam_lock);
 
 	return 0;
@@ -316,6 +329,84 @@
 		rc = cam_req_mgr_sync_mode(&sync_mode);
 		}
 		break;
+	case CAM_REQ_MGR_ALLOC_BUF: {
+		struct cam_mem_mgr_alloc_cmd cmd;
+
+		if (k_ioctl->size != sizeof(cmd))
+			return -EINVAL;
+
+		if (copy_from_user(&cmd,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = cam_mem_mgr_alloc_and_map(&cmd);
+		if (!rc)
+			if (copy_to_user((void *)k_ioctl->handle,
+				&cmd, k_ioctl->size)) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		break;
+	case CAM_REQ_MGR_MAP_BUF: {
+		struct cam_mem_mgr_map_cmd cmd;
+
+		if (k_ioctl->size != sizeof(cmd))
+			return -EINVAL;
+
+		if (copy_from_user(&cmd,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = cam_mem_mgr_map(&cmd);
+		if (!rc)
+			if (copy_to_user((void *)k_ioctl->handle,
+				&cmd, k_ioctl->size)) {
+				rc = -EFAULT;
+				break;
+			}
+		}
+		break;
+	case CAM_REQ_MGR_RELEASE_BUF: {
+		struct cam_mem_mgr_release_cmd cmd;
+
+		if (k_ioctl->size != sizeof(cmd))
+			return -EINVAL;
+
+		if (copy_from_user(&cmd,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = cam_mem_mgr_release(&cmd);
+		}
+		break;
+	case CAM_REQ_MGR_CACHE_OPS: {
+		struct cam_mem_cache_ops_cmd cmd;
+
+		if (k_ioctl->size != sizeof(cmd))
+			return -EINVAL;
+
+		if (copy_from_user(&cmd,
+			(void *)k_ioctl->handle,
+			k_ioctl->size)) {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = cam_mem_mgr_cache_ops(&cmd);
+		if (rc)
+			rc = -EINVAL;
+		}
+		break;
 	default:
 		return -ENOIOCTLCMD;
 	}
@@ -444,6 +535,7 @@
 static int cam_req_mgr_remove(struct platform_device *pdev)
 {
 	cam_req_mgr_core_device_deinit();
+	cam_mem_mgr_deinit();
 	cam_req_mgr_util_deinit();
 	cam_media_device_cleanup();
 	cam_video_device_cleanup();
@@ -482,6 +574,12 @@
 		goto req_mgr_util_fail;
 	}
 
+	rc = cam_mem_mgr_init();
+	if (rc) {
+		pr_err("mem mgr init failed\n");
+		goto mem_mgr_init_fail;
+	}
+
 	rc = cam_req_mgr_core_device_init();
 	if (rc) {
 		pr_err("core device setup failed\n");
@@ -493,8 +591,12 @@
 	return rc;
 
 req_mgr_core_fail:
+	cam_mem_mgr_deinit();
+mem_mgr_init_fail:
 	cam_req_mgr_util_deinit();
 req_mgr_util_fail:
+	mutex_destroy(&g_dev.dev_lock);
+	mutex_destroy(&g_dev.cam_lock);
 	cam_video_device_cleanup();
 video_setup_fail:
 	cam_media_device_cleanup();
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
index 4f75a19..019a775 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
@@ -28,25 +28,34 @@
 #endif
 
 static struct cam_req_mgr_util_hdl_tbl *hdl_tbl;
-static struct mutex hdl_tbl_mutex = __MUTEX_INITIALIZER(hdl_tbl_mutex);
+static DEFINE_SPINLOCK(hdl_tbl_lock);
 
 int cam_req_mgr_util_init(void)
 {
 	int rc = 0;
 	int bitmap_size;
+	static struct cam_req_mgr_util_hdl_tbl *hdl_tbl_local;
 
-	mutex_lock(&hdl_tbl_mutex);
 	if (hdl_tbl) {
 		rc = -EINVAL;
 		pr_err("Hdl_tbl is already present\n");
 		goto hdl_tbl_check_failed;
 	}
 
-	hdl_tbl = kzalloc(sizeof(*hdl_tbl), GFP_KERNEL);
-	if (!hdl_tbl) {
+	hdl_tbl_local = kzalloc(sizeof(*hdl_tbl), GFP_KERNEL);
+	if (!hdl_tbl_local) {
 		rc = -ENOMEM;
 		goto hdl_tbl_alloc_failed;
 	}
+	spin_lock_bh(&hdl_tbl_lock);
+	if (hdl_tbl) {
+		spin_unlock_bh(&hdl_tbl_lock);
+		rc = -EEXIST;
+		kfree(hdl_tbl_local);
+		goto hdl_tbl_check_failed;
+	}
+	hdl_tbl = hdl_tbl_local;
+	spin_unlock_bh(&hdl_tbl_lock);
 
 	bitmap_size = BITS_TO_LONGS(CAM_REQ_MGR_MAX_HANDLES) * sizeof(long);
 	hdl_tbl->bitmap = kzalloc(sizeof(bitmap_size), GFP_KERNEL);
@@ -55,7 +64,6 @@
 		goto bitmap_alloc_fail;
 	}
 	hdl_tbl->bits = bitmap_size * BITS_PER_BYTE;
-	mutex_unlock(&hdl_tbl_mutex);
 
 	return rc;
 
@@ -64,16 +72,15 @@
 	hdl_tbl = NULL;
 hdl_tbl_alloc_failed:
 hdl_tbl_check_failed:
-	mutex_unlock(&hdl_tbl_mutex);
 	return rc;
 }
 
 int cam_req_mgr_util_deinit(void)
 {
-	mutex_lock(&hdl_tbl_mutex);
+	spin_lock_bh(&hdl_tbl_lock);
 	if (!hdl_tbl) {
 		pr_err("Hdl tbl is NULL\n");
-		mutex_unlock(&hdl_tbl_mutex);
+		spin_unlock_bh(&hdl_tbl_lock);
 		return -EINVAL;
 	}
 
@@ -81,7 +88,7 @@
 	hdl_tbl->bitmap = NULL;
 	kfree(hdl_tbl);
 	hdl_tbl = NULL;
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 
 	return 0;
 }
@@ -90,10 +97,10 @@
 {
 	int i = 0;
 
-	mutex_lock(&hdl_tbl_mutex);
+	spin_lock_bh(&hdl_tbl_lock);
 	if (!hdl_tbl) {
 		pr_err("Hdl tbl is NULL\n");
-		mutex_unlock(&hdl_tbl_mutex);
+		spin_unlock_bh(&hdl_tbl_lock);
 		return -EINVAL;
 	}
 
@@ -107,7 +114,7 @@
 		}
 	}
 	bitmap_zero(hdl_tbl->bitmap, CAM_REQ_MGR_MAX_HANDLES);
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 
 	return 0;
 }
@@ -132,17 +139,17 @@
 	int rand = 0;
 	int32_t handle = 0;
 
-	mutex_lock(&hdl_tbl_mutex);
+	spin_lock_bh(&hdl_tbl_lock);
 	if (!hdl_tbl) {
 		pr_err("Hdl tbl is NULL\n");
-		mutex_unlock(&hdl_tbl_mutex);
+		spin_unlock_bh(&hdl_tbl_lock);
 		return -EINVAL;
 	}
 
 	idx = cam_get_free_handle_index();
 	if (idx < 0) {
 		pr_err("Unable to create session handle\n");
-		mutex_unlock(&hdl_tbl_mutex);
+		spin_unlock_bh(&hdl_tbl_lock);
 		return idx;
 	}
 
@@ -154,7 +161,7 @@
 	hdl_tbl->hdl[idx].state = HDL_ACTIVE;
 	hdl_tbl->hdl[idx].priv = priv;
 	hdl_tbl->hdl[idx].ops = NULL;
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 
 	return handle;
 }
@@ -165,17 +172,17 @@
 	int rand = 0;
 	int32_t handle;
 
-	mutex_lock(&hdl_tbl_mutex);
+	spin_lock_bh(&hdl_tbl_lock);
 	if (!hdl_tbl) {
 		pr_err("Hdl tbl is NULL\n");
-		mutex_unlock(&hdl_tbl_mutex);
+		spin_unlock_bh(&hdl_tbl_lock);
 		return -EINVAL;
 	}
 
 	idx = cam_get_free_handle_index();
 	if (idx < 0) {
 		pr_err("Unable to create device handle\n");
-		mutex_unlock(&hdl_tbl_mutex);
+		spin_unlock_bh(&hdl_tbl_lock);
 		return idx;
 	}
 
@@ -187,7 +194,7 @@
 	hdl_tbl->hdl[idx].state = HDL_ACTIVE;
 	hdl_tbl->hdl[idx].priv = hdl_data->priv;
 	hdl_tbl->hdl[idx].ops = hdl_data->ops;
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 
 	return handle;
 }
@@ -198,7 +205,7 @@
 	int type;
 	void *priv;
 
-	mutex_lock(&hdl_tbl_mutex);
+	spin_lock_bh(&hdl_tbl_lock);
 	if (!hdl_tbl) {
 		pr_err("Hdl tbl is NULL\n");
 		goto device_priv_fail;
@@ -227,12 +234,12 @@
 	}
 
 	priv = hdl_tbl->hdl[idx].priv;
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 
 	return priv;
 
 device_priv_fail:
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 	return NULL;
 }
 
@@ -242,7 +249,7 @@
 	int type;
 	void *ops;
 
-	mutex_lock(&hdl_tbl_mutex);
+	spin_lock_bh(&hdl_tbl_lock);
 	if (!hdl_tbl) {
 		pr_err("Hdl tbl is NULL\n");
 		goto device_ops_fail;
@@ -271,12 +278,12 @@
 	}
 
 	ops = hdl_tbl->hdl[idx].ops;
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 
 	return ops;
 
 device_ops_fail:
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 	return NULL;
 }
 
@@ -285,7 +292,7 @@
 	int idx;
 	int type;
 
-	mutex_lock(&hdl_tbl_mutex);
+	spin_lock_bh(&hdl_tbl_lock);
 	if (!hdl_tbl) {
 		pr_err("Hdl tbl is NULL\n");
 		goto destroy_hdl_fail;
@@ -315,12 +322,12 @@
 
 	hdl_tbl->hdl[idx].state = HDL_FREE;
 	clear_bit(idx, hdl_tbl->bitmap);
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 
 	return 0;
 
 destroy_hdl_fail:
-	mutex_unlock(&hdl_tbl_mutex);
+	spin_unlock_bh(&hdl_tbl_lock);
 	return -EINVAL;
 }
 
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
index e327723..1f6a97a 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
@@ -22,12 +22,16 @@
 		return NULL;
 
 	spin_lock(&workq->task.lock);
+	if (list_empty(&workq->task.empty_head))
+		goto end;
+
 	task = list_first_entry(&workq->task.empty_head,
 		struct crm_workq_task, entry);
 	if (task) {
 		atomic_sub(1, &workq->task.free_cnt);
 		list_del_init(&task->entry);
 	}
+end:
 	spin_unlock(&workq->task.lock);
 
 	return task;
@@ -104,14 +108,14 @@
 	workq = (struct cam_req_mgr_core_workq *)
 		container_of(w, struct cam_req_mgr_core_workq, work);
 
-	spin_lock(&workq->task.lock);
 	list_for_each_entry_safe(task, task_save,
 		&workq->task.process_head, entry) {
 		atomic_sub(1, &workq->task.pending_cnt);
+		spin_lock(&workq->task.lock);
 		list_del_init(&task->entry);
+		spin_unlock(&workq->task.lock);
 		cam_req_mgr_process_task(task);
 	}
-	spin_unlock(&workq->task.lock);
 	CRM_DBG("processed task %p free_cnt %d",
 		task, atomic_read(&workq->task.free_cnt));
 }
@@ -138,7 +142,6 @@
 		goto end;
 	}
 
-	spin_lock(&workq->task.lock);
 	if (task->cancel == 1) {
 		cam_req_mgr_workq_put_task(task);
 		CRM_WARN("task aborted and queued back to pool");
@@ -146,12 +149,14 @@
 		spin_unlock(&workq->task.lock);
 		goto end;
 	}
+	spin_lock(&workq->task.lock);
 	list_add_tail(&task->entry,
 		&workq->task.process_head);
+	spin_unlock(&workq->task.lock);
 	atomic_add(1, &workq->task.pending_cnt);
 	CRM_DBG("enq task %p pending_cnt %d",
 		task, atomic_read(&workq->task.pending_cnt));
-	spin_unlock(&workq->task.lock);
+
 
 	queue_work(workq->job, &workq->work);
 
diff --git a/drivers/media/platform/msm/camera/cam_smmu/Makefile b/drivers/media/platform/msm/camera/cam_smmu/Makefile
new file mode 100644
index 0000000..3619da7
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu_api.o
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
new file mode 100644
index 0000000..f4215b5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -0,0 +1,2284 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "CAM-SMMU %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/dma-buf.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/of_platform.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_dma_iommu_mapping.h>
+#include <linux/workqueue.h>
+#include <linux/genalloc.h>
+
+#include "cam_smmu_api.h"
+
+#define SHARED_MEM_POOL_GRANULARITY 12
+
+#define IOMMU_INVALID_DIR -1
+#define BYTE_SIZE 8
+#define COOKIE_NUM_BYTE 2
+#define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE)
+#define COOKIE_MASK ((1<<COOKIE_SIZE)-1)
+#define HANDLE_INIT (-1)
+#define CAM_SMMU_CB_MAX 2
+
+#define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK))
+#define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK)
+
+#ifdef CONFIG_CAM_SMMU_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+struct firmware_alloc_info {
+	struct device *fw_dev;
+	void *fw_kva;
+	dma_addr_t fw_dma_hdl;
+};
+
+struct firmware_alloc_info icp_fw;
+
+struct cam_smmu_work_payload {
+	int idx;
+	struct iommu_domain *domain;
+	struct device *dev;
+	unsigned long iova;
+	int flags;
+	void *token;
+	struct list_head list;
+};
+
+enum cam_protection_type {
+	CAM_PROT_INVALID,
+	CAM_NON_SECURE,
+	CAM_SECURE,
+	CAM_PROT_MAX,
+};
+
+enum cam_iommu_type {
+	CAM_SMMU_INVALID,
+	CAM_QSMMU,
+	CAM_ARM_SMMU,
+	CAM_SMMU_MAX,
+};
+
+enum cam_smmu_buf_state {
+	CAM_SMMU_BUFF_EXIST,
+	CAM_SMMU_BUFF_NOT_EXIST
+};
+
+enum cam_smmu_init_dir {
+	CAM_SMMU_TABLE_INIT,
+	CAM_SMMU_TABLE_DEINIT,
+};
+
+struct scratch_mapping {
+	void *bitmap;
+	size_t bits;
+	unsigned int order;
+	dma_addr_t base;
+};
+
+struct cam_smmu_region_info {
+	dma_addr_t iova_start;
+	size_t iova_len;
+};
+
+struct cam_context_bank_info {
+	struct device *dev;
+	struct dma_iommu_mapping *mapping;
+	dma_addr_t va_start;
+	size_t va_len;
+	const char *name;
+	bool is_secure;
+	uint8_t scratch_buf_support;
+	uint8_t firmware_support;
+	uint8_t shared_support;
+	uint8_t io_support;
+	bool is_fw_allocated;
+
+	struct scratch_mapping scratch_map;
+	struct gen_pool *shared_mem_pool;
+
+	struct cam_smmu_region_info scratch_info;
+	struct cam_smmu_region_info firmware_info;
+	struct cam_smmu_region_info shared_info;
+	struct cam_smmu_region_info io_info;
+
+	struct list_head smmu_buf_list;
+	struct mutex lock;
+	int handle;
+	enum cam_smmu_ops_param state;
+
+	void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *,
+		struct device *, unsigned long,
+		int, void*);
+	void *token[CAM_SMMU_CB_MAX];
+	int cb_count;
+};
+
+struct cam_iommu_cb_set {
+	struct cam_context_bank_info *cb_info;
+	u32 cb_num;
+	u32 cb_init_count;
+	struct work_struct smmu_work;
+	struct mutex payload_list_lock;
+	struct list_head payload_list;
+};
+
+static const struct of_device_id msm_cam_smmu_dt_match[] = {
+	{ .compatible = "qcom,msm-cam-smmu", },
+	{ .compatible = "qcom,msm-cam-smmu-cb", },
+	{ .compatible = "qcom,msm-cam-smmu-fw-dev", },
+	{}
+};
+
+struct cam_dma_buff_info {
+	struct dma_buf *buf;
+	struct dma_buf_attachment *attach;
+	struct sg_table *table;
+	enum dma_data_direction dir;
+	enum cam_smmu_region_id region_id;
+	int iommu_dir;
+	int ref_count;
+	dma_addr_t paddr;
+	struct list_head list;
+	int ion_fd;
+	size_t len;
+	size_t phys_len;
+};
+
+static struct cam_iommu_cb_set iommu_cb_set;
+
+static enum dma_data_direction cam_smmu_translate_dir(
+	enum cam_smmu_map_dir dir);
+
+static int cam_smmu_check_handle_unique(int hdl);
+
+static int cam_smmu_create_iommu_handle(int idx);
+
+static int cam_smmu_create_add_handle_in_table(char *name,
+	int *hdl);
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
+	int ion_fd);
+
+static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
+	dma_addr_t base, size_t size,
+	int order);
+
+static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping,
+	size_t size,
+	dma_addr_t *iova);
+
+static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping,
+	dma_addr_t addr, size_t size);
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx,
+	dma_addr_t virt_addr);
+
+static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
+	enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+	size_t *len_ptr,
+	enum cam_smmu_region_id region_id);
+
+static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx,
+	size_t virt_len,
+	size_t phys_len,
+	unsigned int iommu_dir,
+	dma_addr_t *virt_addr);
+
+static int cam_smmu_unmap_buf_and_remove_from_list(
+	struct cam_dma_buff_info *mapping_info, int idx);
+
+static int cam_smmu_free_scratch_buffer_remove_from_list(
+	struct cam_dma_buff_info *mapping_info,
+	int idx);
+
+static void cam_smmu_clean_buffer_list(int idx);
+
+static void cam_smmu_print_list(int idx);
+
+static void cam_smmu_print_table(void);
+
+static int cam_smmu_probe(struct platform_device *pdev);
+
+static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr);
+
+static void cam_smmu_page_fault_work(struct work_struct *work)
+{
+	int j;
+	int idx;
+	struct cam_smmu_work_payload *payload;
+
+	mutex_lock(&iommu_cb_set.payload_list_lock);
+	if (list_empty(&iommu_cb_set.payload_list)) {
+		pr_err("Payload list empty\n");
+		mutex_unlock(&iommu_cb_set.payload_list_lock);
+		return;
+	}
+
+	payload = list_first_entry(&iommu_cb_set.payload_list,
+		struct cam_smmu_work_payload,
+		list);
+	list_del(&payload->list);
+	mutex_unlock(&iommu_cb_set.payload_list_lock);
+
+	/* Dereference the payload to call the handler */
+	idx = payload->idx;
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	cam_smmu_check_vaddr_in_range(idx, (void *)payload->iova);
+	for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+		if ((iommu_cb_set.cb_info[idx].handler[j])) {
+			iommu_cb_set.cb_info[idx].handler[j](
+				payload->domain,
+				payload->dev,
+				payload->iova,
+				payload->flags,
+				iommu_cb_set.cb_info[idx].token[j]);
+		}
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	kfree(payload);
+}
+
+static void cam_smmu_print_list(int idx)
+{
+	struct cam_dma_buff_info *mapping;
+
+	pr_err("index = %d\n", idx);
+	list_for_each_entry(mapping,
+		&iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+		pr_err("ion_fd = %d, paddr= 0x%pK, len = %u, region = %d\n",
+			 mapping->ion_fd, (void *)mapping->paddr,
+			 (unsigned int)mapping->len,
+			 mapping->region_id);
+	}
+}
+
+static void cam_smmu_print_table(void)
+{
+	int i;
+
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		pr_err("i= %d, handle= %d, name_addr=%pK\n", i,
+			   (int)iommu_cb_set.cb_info[i].handle,
+			   (void *)iommu_cb_set.cb_info[i].name);
+		pr_err("dev = %pK\n", iommu_cb_set.cb_info[i].dev);
+	}
+}
+
+static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr)
+{
+	struct cam_dma_buff_info *mapping;
+	unsigned long start_addr, end_addr, current_addr;
+
+	current_addr = (unsigned long)vaddr;
+	list_for_each_entry(mapping,
+			&iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+		start_addr = (unsigned long)mapping->paddr;
+		end_addr = (unsigned long)mapping->paddr + mapping->len;
+
+		if (start_addr <= current_addr && current_addr < end_addr) {
+			pr_err("va %pK valid: range:%pK-%pK, fd = %d cb: %s\n",
+				vaddr, (void *)start_addr, (void *)end_addr,
+				mapping->ion_fd,
+				iommu_cb_set.cb_info[idx].name);
+			goto end;
+		} else {
+			CDBG("va %pK is not in this range: %pK-%pK, fd = %d\n",
+				vaddr, (void *)start_addr, (void *)end_addr,
+				mapping->ion_fd);
+		}
+	}
+	pr_err("Cannot find vaddr:%pK in SMMU %s uses invalid virt address\n",
+		vaddr, iommu_cb_set.cb_info[idx].name);
+end:
+	return;
+}
+
+void cam_smmu_reg_client_page_fault_handler(int handle,
+	void (*client_page_fault_handler)(struct iommu_domain *,
+	struct device *, unsigned long,
+	int, void*), void *token)
+{
+	int idx, i = 0;
+
+	if (!token || (handle == HANDLE_INIT)) {
+		pr_err("Error: token is NULL or invalid handle\n");
+		return;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return;
+	}
+
+	if (client_page_fault_handler) {
+		if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) {
+			pr_err("%s Should not regiester more handlers\n",
+				iommu_cb_set.cb_info[idx].name);
+			mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+			return;
+		}
+		iommu_cb_set.cb_info[idx].cb_count++;
+		for (i = 0; i < iommu_cb_set.cb_info[idx].cb_count; i++) {
+			if (iommu_cb_set.cb_info[idx].token[i] == NULL) {
+				iommu_cb_set.cb_info[idx].token[i] = token;
+				iommu_cb_set.cb_info[idx].handler[i] =
+					client_page_fault_handler;
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i < CAM_SMMU_CB_MAX; i++) {
+			if (iommu_cb_set.cb_info[idx].token[i] == token) {
+				iommu_cb_set.cb_info[idx].token[i] = NULL;
+				iommu_cb_set.cb_info[idx].handler[i] =
+					NULL;
+				iommu_cb_set.cb_info[idx].cb_count--;
+				break;
+			}
+		}
+		if (i == CAM_SMMU_CB_MAX)
+			pr_err("Error: hdl %x no matching tokens: %s\n",
+				handle, iommu_cb_set.cb_info[idx].name);
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+}
+
+static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain,
+	struct device *dev, unsigned long iova,
+	int flags, void *token)
+{
+	char *cb_name;
+	int idx;
+	struct cam_smmu_work_payload *payload;
+
+	if (!token) {
+		pr_err("Error: token is NULL\n");
+		pr_err("Error: domain = %pK, device = %pK\n", domain, dev);
+		pr_err("iova = %lX, flags = %d\n", iova, flags);
+		return 0;
+	}
+
+	cb_name = (char *)token;
+	/* Check whether it is in the table */
+	for (idx = 0; idx < iommu_cb_set.cb_num; idx++) {
+		if (!strcmp(iommu_cb_set.cb_info[idx].name, cb_name))
+			break;
+	}
+
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: index is not valid, index = %d, token = %s\n",
+			idx, cb_name);
+		return 0;
+	}
+
+	payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC);
+	if (!payload)
+		return 0;
+
+	payload->domain = domain;
+	payload->dev = dev;
+	payload->iova = iova;
+	payload->flags = flags;
+	payload->token = token;
+	payload->idx = idx;
+
+	mutex_lock(&iommu_cb_set.payload_list_lock);
+	list_add_tail(&payload->list, &iommu_cb_set.payload_list);
+	mutex_unlock(&iommu_cb_set.payload_list_lock);
+
+	schedule_work(&iommu_cb_set.smmu_work);
+
+	return 0;
+}
+
+static int cam_smmu_translate_dir_to_iommu_dir(
+	enum cam_smmu_map_dir dir)
+{
+	switch (dir) {
+	case CAM_SMMU_MAP_READ:
+		return IOMMU_READ;
+	case CAM_SMMU_MAP_WRITE:
+		return IOMMU_WRITE;
+	case CAM_SMMU_MAP_RW:
+		return IOMMU_READ|IOMMU_WRITE;
+	case CAM_SMMU_MAP_INVALID:
+	default:
+		pr_err("Error: Direction is invalid. dir = %d\n", dir);
+		break;
+	};
+	return IOMMU_INVALID_DIR;
+}
+
+static enum dma_data_direction cam_smmu_translate_dir(
+	enum cam_smmu_map_dir dir)
+{
+	switch (dir) {
+	case CAM_SMMU_MAP_READ:
+		return DMA_FROM_DEVICE;
+	case CAM_SMMU_MAP_WRITE:
+		return DMA_TO_DEVICE;
+	case CAM_SMMU_MAP_RW:
+		return DMA_BIDIRECTIONAL;
+	case CAM_SMMU_MAP_INVALID:
+	default:
+		pr_err("Error: Direction is invalid. dir = %d\n", (int)dir);
+		break;
+	}
+	return DMA_NONE;
+}
+
+void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops)
+{
+	unsigned int i;
+	int j = 0;
+
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		iommu_cb_set.cb_info[i].handle = HANDLE_INIT;
+		INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_list);
+		iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH;
+		iommu_cb_set.cb_info[i].dev = NULL;
+		iommu_cb_set.cb_info[i].cb_count = 0;
+		for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+			iommu_cb_set.cb_info[i].token[j] = NULL;
+			iommu_cb_set.cb_info[i].handler[j] = NULL;
+		}
+		if (ops == CAM_SMMU_TABLE_INIT)
+			mutex_init(&iommu_cb_set.cb_info[i].lock);
+		else
+			mutex_destroy(&iommu_cb_set.cb_info[i].lock);
+	}
+}
+
+static int cam_smmu_check_handle_unique(int hdl)
+{
+	int i;
+
+	if (hdl == HANDLE_INIT) {
+		CDBG("iommu handle is init number. Need to try again\n");
+		return 1;
+	}
+
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT)
+			continue;
+
+		if (iommu_cb_set.cb_info[i].handle == hdl) {
+			CDBG("iommu handle %d conflicts\n", (int)hdl);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/**
+ *  use low 2 bytes for handle cookie
+ */
+static int cam_smmu_create_iommu_handle(int idx)
+{
+	int rand, hdl = 0;
+
+	get_random_bytes(&rand, COOKIE_NUM_BYTE);
+	hdl = GET_SMMU_HDL(idx, rand);
+	CDBG("create handle value = %x\n", (int)hdl);
+	return hdl;
+}
+
+static int cam_smmu_attach_device(int idx)
+{
+	int rc;
+	struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+	/* attach the mapping to device */
+	rc = arm_iommu_attach_device(cb->dev, cb->mapping);
+	if (rc < 0) {
+		pr_err("Error: ARM IOMMU attach failed. ret = %d\n", rc);
+		rc = -ENODEV;
+	}
+
+	return rc;
+}
+
+static int cam_smmu_create_add_handle_in_table(char *name,
+	int *hdl)
+{
+	int i;
+	int handle;
+
+	/* create handle and add in the iommu hardware table */
+	for (i = 0; i < iommu_cb_set.cb_num; i++) {
+		if (!strcmp(iommu_cb_set.cb_info[i].name, name)) {
+			mutex_lock(&iommu_cb_set.cb_info[i].lock);
+			if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) {
+				pr_err("Error: %s already got handle 0x%x\n",
+					name,
+					iommu_cb_set.cb_info[i].handle);
+				mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+				return -EINVAL;
+			}
+
+			/* make sure handle is unique */
+			do {
+				handle = cam_smmu_create_iommu_handle(i);
+			} while (cam_smmu_check_handle_unique(handle));
+
+			/* put handle in the table */
+			iommu_cb_set.cb_info[i].handle = handle;
+			iommu_cb_set.cb_info[i].cb_count = 0;
+			*hdl = handle;
+			CDBG("%s creates handle 0x%x\n", name, handle);
+			mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+			return 0;
+		}
+	}
+
+	pr_err("Error: Cannot find name %s or all handle exist!\n",
+			name);
+	cam_smmu_print_table();
+	return -EINVAL;
+}
+
+static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
+					dma_addr_t base, size_t size,
+					int order)
+{
+	unsigned int count = size >> (PAGE_SHIFT + order);
+	unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+	int err = 0;
+
+	if (!count) {
+		err = -EINVAL;
+		pr_err("Page count is zero, size passed = %zu\n", size);
+		goto bail;
+	}
+
+	scratch_map->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!scratch_map->bitmap) {
+		err = -ENOMEM;
+		goto bail;
+	}
+
+	scratch_map->base = base;
+	scratch_map->bits = BITS_PER_BYTE * bitmap_size;
+	scratch_map->order = order;
+
+bail:
+	return err;
+}
+
+static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping,
+	size_t size,
+	dma_addr_t *iova)
+{
+	unsigned int order = get_order(size);
+	unsigned int align = 0;
+	unsigned int count, start;
+
+	count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+		 (1 << mapping->order) - 1) >> mapping->order;
+
+	/*
+	 * Transparently, add a guard page to the total count of pages
+	 * to be allocated
+	 */
+	count++;
+
+	if (order > mapping->order)
+		align = (1 << (order - mapping->order)) - 1;
+
+	start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
+					   count, align);
+
+	if (start > mapping->bits)
+		return -ENOMEM;
+
+	bitmap_set(mapping->bitmap, start, count);
+	*iova = mapping->base + (start << (mapping->order + PAGE_SHIFT));
+
+	return 0;
+}
+
+static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping,
+	dma_addr_t addr, size_t size)
+{
+	unsigned int start = (addr - mapping->base) >>
+			     (mapping->order + PAGE_SHIFT);
+	unsigned int count = ((size >> PAGE_SHIFT) +
+			      (1 << mapping->order) - 1) >> mapping->order;
+
+	if (!addr) {
+		pr_err("Error: Invalid address\n");
+		return -EINVAL;
+	}
+
+	if (start + count > mapping->bits) {
+		pr_err("Error: Invalid page bits in scratch map\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Transparently, add a guard page to the total count of pages
+	 * to be freed
+	 */
+	count++;
+	bitmap_clear(mapping->bitmap, start, count);
+
+	return 0;
+}
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx,
+	dma_addr_t virt_addr)
+{
+	struct cam_dma_buff_info *mapping;
+
+	list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+			list) {
+		if (mapping->paddr == virt_addr) {
+			CDBG("Found virtual address %lx\n",
+				 (unsigned long)virt_addr);
+			return mapping;
+		}
+	}
+
+	pr_err("Error: Cannot find virtual address %lx by index %d\n",
+		(unsigned long)virt_addr, idx);
+	return NULL;
+}
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
+	int ion_fd)
+{
+	struct cam_dma_buff_info *mapping;
+
+	list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+			list) {
+		if (mapping->ion_fd == ion_fd) {
+			CDBG(" find ion_fd %d\n", ion_fd);
+			return mapping;
+		}
+	}
+
+	pr_err("Error: Cannot find fd %d by index %d\n",
+		ion_fd, idx);
+	return NULL;
+}
+
+static void cam_smmu_clean_buffer_list(int idx)
+{
+	int ret;
+	struct cam_dma_buff_info *mapping_info, *temp;
+
+	list_for_each_entry_safe(mapping_info, temp,
+			&iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+		CDBG("Free mapping address %pK, i = %d, fd = %d\n",
+			(void *)mapping_info->paddr, idx,
+			mapping_info->ion_fd);
+
+		if (mapping_info->ion_fd == 0xDEADBEEF)
+			/* Clean up scratch buffers */
+			ret = cam_smmu_free_scratch_buffer_remove_from_list(
+							mapping_info, idx);
+		else
+			/* Clean up regular mapped buffers */
+			ret = cam_smmu_unmap_buf_and_remove_from_list(
+					mapping_info,
+					idx);
+
+		if (ret < 0) {
+			pr_err("Buffer delete failed: idx = %d\n", idx);
+			pr_err("Buffer delete failed: addr = %lx, fd = %d\n",
+					(unsigned long)mapping_info->paddr,
+					mapping_info->ion_fd);
+			/*
+			 * Ignore this error and continue to delete other
+			 * buffers in the list
+			 */
+			continue;
+		}
+	}
+}
+
+static int cam_smmu_attach(int idx)
+{
+	int ret;
+
+	if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) {
+		ret = -EALREADY;
+	} else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+		ret = cam_smmu_attach_device(idx);
+		if (ret < 0) {
+			pr_err("Error: ATTACH fail\n");
+			return -ENODEV;
+		}
+		iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH;
+		ret = 0;
+	} else {
+		pr_err("Error: Not detach/attach: %d\n",
+			iommu_cb_set.cb_info[idx].state);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int cam_smmu_detach_device(int idx)
+{
+	int rc = 0;
+	struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+	/* detach the mapping to device if not already detached */
+	if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+		rc = -EALREADY;
+	} else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) {
+		arm_iommu_detach_device(cb->dev);
+		iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH;
+	}
+
+	return rc;
+}
+
+static int cam_smmu_alloc_iova(size_t size,
+	int32_t smmu_hdl, uint32_t *iova)
+{
+	int rc = 0;
+	int idx;
+	uint32_t vaddr = 0;
+
+	if (!iova || !size || (smmu_hdl == HANDLE_INIT)) {
+		pr_err("Error: Input args are invalid\n");
+		return -EINVAL;
+	}
+
+	CDBG("Allocating iova size = %zu for smmu hdl=%X\n", size, smmu_hdl);
+
+	idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, smmu_hdl);
+		return -EINVAL;
+	}
+
+	if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, smmu_hdl);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	if (!iommu_cb_set.cb_info[idx].shared_support) {
+		pr_err("Error: Shared memory not supported for hdl = %X\n",
+			smmu_hdl);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	vaddr = gen_pool_alloc(iommu_cb_set.cb_info[idx].shared_mem_pool, size);
+	if (!vaddr)
+		return -ENOMEM;
+
+	*iova = vaddr;
+
+get_addr_end:
+	return rc;
+}
+
+static int cam_smmu_free_iova(uint32_t addr, size_t size,
+	int32_t smmu_hdl)
+{
+	int rc = 0;
+	int idx;
+
+	if (!size || (smmu_hdl == HANDLE_INIT)) {
+		pr_err("Error: Input args are invalid\n");
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, smmu_hdl);
+		return -EINVAL;
+	}
+
+	if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, smmu_hdl);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	gen_pool_free(iommu_cb_set.cb_info[idx].shared_mem_pool, addr, size);
+
+get_addr_end:
+	return rc;
+}
+
+int cam_smmu_alloc_firmware(int32_t smmu_hdl,
+	dma_addr_t *iova,
+	uint64_t *cpuva,
+	size_t *len)
+{
+	int rc;
+	int32_t idx;
+	size_t firmware_len = 0;
+	size_t firmware_start = 0;
+	struct iommu_domain *domain;
+
+	if (!iova || !len || !cpuva || (smmu_hdl == HANDLE_INIT)) {
+		pr_err("Error: Input args are invalid\n");
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, smmu_hdl);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (!iommu_cb_set.cb_info[idx].firmware_support) {
+		pr_err("Firmware memory not supported for this SMMU handle\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].is_fw_allocated) {
+		pr_err("Trying to allocate twice\n");
+		rc = -ENOMEM;
+		goto unlock_and_end;
+	}
+
+	firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len;
+	firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+	CDBG("Firmware area len from DT = %zu\n", firmware_len);
+
+	icp_fw.fw_kva = dma_alloc_coherent(icp_fw.fw_dev,
+		firmware_len,
+		&icp_fw.fw_dma_hdl,
+		GFP_KERNEL);
+	if (!icp_fw.fw_kva) {
+		pr_err("FW memory alloc failed\n");
+		rc = -ENOMEM;
+		goto unlock_and_end;
+	} else {
+		CDBG("DMA alloc returned fw = %pK, hdl = %pK\n",
+			icp_fw.fw_kva, (void *)icp_fw.fw_dma_hdl);
+	}
+
+	domain = iommu_cb_set.cb_info[idx].mapping->domain;
+	rc = iommu_map(domain,
+		firmware_start,
+		icp_fw.fw_dma_hdl,
+		firmware_len,
+		IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV);
+
+	if (rc) {
+		pr_err("Failed to map FW into IOMMU\n");
+		rc = -ENOMEM;
+		goto alloc_fail;
+	}
+	iommu_cb_set.cb_info[idx].is_fw_allocated = true;
+
+	*iova = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+	*cpuva = (uint64_t)icp_fw.fw_kva;
+	*len = firmware_len;
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+
+	return rc;
+
+alloc_fail:
+	dma_free_coherent(icp_fw.fw_dev,
+		firmware_len,
+		icp_fw.fw_kva,
+		icp_fw.fw_dma_hdl);
+unlock_and_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+end:
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_alloc_firmware);
+
+int cam_smmu_dealloc_firmware(int32_t smmu_hdl)
+{
+	int rc = 0;
+	int32_t idx;
+	size_t firmware_len = 0;
+	size_t firmware_start = 0;
+	struct iommu_domain *domain;
+	size_t unmapped = 0;
+
+	if (smmu_hdl == HANDLE_INIT) {
+		pr_err("Error: Invalid handle\n");
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, smmu_hdl);
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (!iommu_cb_set.cb_info[idx].firmware_support) {
+		pr_err("Firmware memory not supported for this SMMU handle\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (!iommu_cb_set.cb_info[idx].is_fw_allocated) {
+		pr_err("Trying to deallocate firmware that is not allocated\n");
+		rc = -ENOMEM;
+		goto unlock_and_end;
+	}
+
+	firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len;
+	firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+	domain = iommu_cb_set.cb_info[idx].mapping->domain;
+	unmapped = iommu_unmap(domain,
+		firmware_start,
+		firmware_len);
+
+	if (unmapped != firmware_len) {
+		pr_err("Only %zu unmapped out of total %zu\n",
+			unmapped,
+			firmware_len);
+		rc = -EINVAL;
+	}
+
+	dma_free_coherent(icp_fw.fw_dev,
+		firmware_len,
+		icp_fw.fw_kva,
+		icp_fw.fw_dma_hdl);
+
+	icp_fw.fw_kva = 0;
+	icp_fw.fw_dma_hdl = 0;
+
+	iommu_cb_set.cb_info[idx].is_fw_allocated = false;
+
+unlock_and_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+end:
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_dealloc_firmware);
+
+static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
+	 enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+	 size_t *len_ptr,
+	 enum cam_smmu_region_id region_id)
+{
+	int rc = -1;
+	struct cam_dma_buff_info *mapping_info;
+	struct dma_buf *buf = NULL;
+	struct dma_buf_attachment *attach = NULL;
+	struct sg_table *table = NULL;
+	struct iommu_domain *domain;
+	size_t size = 0;
+	uint32_t iova = 0;
+
+	/* allocate memory for each buffer information */
+	buf = dma_buf_get(ion_fd);
+	if (IS_ERR_OR_NULL(buf)) {
+		rc = PTR_ERR(buf);
+		pr_err("Error: dma get buf failed. fd = %d\n", ion_fd);
+		goto err_out;
+	}
+
+	attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev);
+	if (IS_ERR_OR_NULL(attach)) {
+		rc = PTR_ERR(attach);
+		pr_err("Error: dma buf attach failed\n");
+		goto err_put;
+	}
+
+	table = dma_buf_map_attachment(attach, dma_dir);
+	if (IS_ERR_OR_NULL(table)) {
+		rc = PTR_ERR(table);
+		pr_err("Error: dma buf map attachment failed\n");
+		goto err_detach;
+	}
+
+	if (region_id == CAM_SMMU_REGION_SHARED) {
+		domain = iommu_cb_set.cb_info[idx].mapping->domain;
+		if (!domain) {
+			pr_err("CB has no domain set\n");
+			goto err_unmap_sg;
+		}
+
+		rc = cam_smmu_alloc_iova(*len_ptr,
+			iommu_cb_set.cb_info[idx].handle,
+			&iova);
+
+		if (rc < 0) {
+			pr_err("IOVA alloc failed for shared memory\n");
+			goto err_unmap_sg;
+		}
+
+		size = iommu_map_sg(domain,
+			iova,
+			table->sgl,
+			table->nents,
+			IOMMU_READ | IOMMU_WRITE);
+
+		if (size < 0) {
+			pr_err("IOMMU mapping failed\n");
+			rc = cam_smmu_free_iova(iova,
+				size,
+				iommu_cb_set.cb_info[idx].handle);
+
+			if (rc)
+				pr_err("IOVA free failed\n");
+			rc = -ENOMEM;
+			goto err_unmap_sg;
+		} else {
+			CDBG("iommu_map_sg returned %zu\n", size);
+			*paddr_ptr = iova;
+			*len_ptr = size;
+		}
+	} else if (region_id == CAM_SMMU_REGION_IO) {
+		rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev,
+			table->sgl, table->nents, dma_dir, buf);
+
+		if (rc != table->nents) {
+			pr_err("Error: msm_dma_map_sg_lazy failed\n");
+			rc = -ENOMEM;
+			goto err_unmap_sg;
+		} else {
+			*paddr_ptr = sg_dma_address(table->sgl);
+			*len_ptr = (size_t)sg_dma_len(table->sgl);
+		}
+	} else {
+		pr_err("Error: Wrong region id passed for %s\n", __func__);
+		rc = -EINVAL;
+		goto err_unmap_sg;
+	}
+
+	if (table->sgl) {
+		CDBG("DMA buf: %pK, device: %pK, attach: %pK, table: %pK\n",
+				(void *)buf,
+				(void *)iommu_cb_set.cb_info[idx].dev,
+				(void *)attach, (void *)table);
+		CDBG("table sgl: %pK, rc: %d, dma_address: 0x%x\n",
+				(void *)table->sgl, rc,
+				(unsigned int)table->sgl->dma_address);
+	} else {
+		rc = -EINVAL;
+		pr_err("Error: table sgl is null\n");
+		goto err_unmap_sg;
+	}
+
+	/* fill up mapping_info */
+	mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+	if (!mapping_info) {
+		rc = -ENOSPC;
+		goto err_alloc;
+	}
+	mapping_info->ion_fd = ion_fd;
+	mapping_info->buf = buf;
+	mapping_info->attach = attach;
+	mapping_info->table = table;
+	mapping_info->paddr = *paddr_ptr;
+	mapping_info->len = *len_ptr;
+	mapping_info->dir = dma_dir;
+	mapping_info->ref_count = 1;
+	mapping_info->region_id = region_id;
+
+	if (!*paddr_ptr || !*len_ptr) {
+		pr_err("Error: Space Allocation failed!\n");
+		kfree(mapping_info);
+		rc = -ENOSPC;
+		goto err_alloc;
+	}
+	CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
+		(void *)iommu_cb_set.cb_info[idx].dev,
+		(void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+	/* add to the list */
+	list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+	return 0;
+
+err_alloc:
+	if (region_id == CAM_SMMU_REGION_SHARED) {
+		cam_smmu_free_iova(iova,
+			size,
+			iommu_cb_set.cb_info[idx].handle);
+
+		iommu_unmap(iommu_cb_set.cb_info[idx].mapping->domain,
+			*paddr_ptr,
+			*len_ptr);
+	} else if (region_id == CAM_SMMU_REGION_IO) {
+		msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+			table->sgl,
+			table->nents,
+			dma_dir,
+			buf);
+	}
+err_unmap_sg:
+	dma_buf_unmap_attachment(attach, table, dma_dir);
+err_detach:
+	dma_buf_detach(buf, attach);
+err_put:
+	dma_buf_put(buf);
+err_out:
+	return rc;
+}
+
+static int cam_smmu_unmap_buf_and_remove_from_list(
+	struct cam_dma_buff_info *mapping_info,
+	int idx)
+{
+	int rc;
+	size_t size;
+	struct iommu_domain *domain;
+
+	if ((!mapping_info->buf) || (!mapping_info->table) ||
+		(!mapping_info->attach)) {
+		pr_err("Error: Invalid params dev = %pK, table = %pK\n",
+			(void *)iommu_cb_set.cb_info[idx].dev,
+			(void *)mapping_info->table);
+		pr_err("Error:dma_buf = %pK, attach = %pK\n",
+			(void *)mapping_info->buf,
+			(void *)mapping_info->attach);
+		return -EINVAL;
+	}
+
+	if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) {
+		CDBG("Removing SHARED buffer paddr = %pK, len = %zu\n",
+			(void *)mapping_info->paddr, mapping_info->len);
+
+		domain = iommu_cb_set.cb_info[idx].mapping->domain;
+
+		size = iommu_unmap(domain,
+			mapping_info->paddr,
+			mapping_info->len);
+
+		if (size != mapping_info->len) {
+			pr_err("IOMMU unmap failed\n");
+			pr_err("Unmapped = %zu, requested = %zu\n",
+				size,
+				mapping_info->len);
+		}
+
+		rc = cam_smmu_free_iova(mapping_info->paddr,
+			mapping_info->len,
+			iommu_cb_set.cb_info[idx].handle);
+
+		if (rc)
+			pr_err("IOVA free failed\n");
+
+	} else if (mapping_info->region_id == CAM_SMMU_REGION_IO) {
+		msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+			mapping_info->table->sgl, mapping_info->table->nents,
+			mapping_info->dir, mapping_info->buf);
+	}
+
+	dma_buf_unmap_attachment(mapping_info->attach,
+		mapping_info->table, mapping_info->dir);
+	dma_buf_detach(mapping_info->buf, mapping_info->attach);
+	dma_buf_put(mapping_info->buf);
+
+	mapping_info->buf = NULL;
+
+	list_del_init(&mapping_info->list);
+
+	/* free one buffer */
+	kfree(mapping_info);
+	return 0;
+}
+
+static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx,
+	int ion_fd, dma_addr_t *paddr_ptr,
+	size_t *len_ptr)
+{
+	struct cam_dma_buff_info *mapping;
+
+	list_for_each_entry(mapping,
+		&iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+		if (mapping->ion_fd == ion_fd) {
+			mapping->ref_count++;
+			*paddr_ptr = mapping->paddr;
+			*len_ptr = mapping->len;
+			return CAM_SMMU_BUFF_EXIST;
+		}
+	}
+
+	return CAM_SMMU_BUFF_NOT_EXIST;
+}
+
+int cam_smmu_get_handle(char *identifier, int *handle_ptr)
+{
+	int ret = 0;
+
+	if (!identifier) {
+		pr_err("Error: iommu hardware name is NULL\n");
+		return -EINVAL;
+	}
+
+	if (!handle_ptr) {
+		pr_err("Error: handle pointer is NULL\n");
+		return -EINVAL;
+	}
+
+	/* create and put handle in the table */
+	ret = cam_smmu_create_add_handle_in_table(identifier, handle_ptr);
+	if (ret < 0)
+		pr_err("Error: %s get handle fail\n", identifier);
+
+	return ret;
+}
+EXPORT_SYMBOL(cam_smmu_get_handle);
+
+int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
+{
+	int ret = 0, idx;
+
+	if (handle == HANDLE_INIT) {
+		pr_err("Error: Invalid handle\n");
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: Index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return -EINVAL;
+	}
+
+	switch (ops) {
+	case CAM_SMMU_ATTACH: {
+		ret = cam_smmu_attach(idx);
+		break;
+	}
+	case CAM_SMMU_DETACH: {
+		ret = cam_smmu_detach_device(idx);
+		break;
+	}
+	case CAM_SMMU_VOTE:
+	case CAM_SMMU_DEVOTE:
+	default:
+		pr_err("Error: idx = %d, ops = %d\n", idx, ops);
+		ret = -EINVAL;
+	}
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return ret;
+}
+EXPORT_SYMBOL(cam_smmu_ops);
+
+static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx,
+	size_t virt_len,
+	size_t phys_len,
+	unsigned int iommu_dir,
+	dma_addr_t *virt_addr)
+{
+	unsigned long nents = virt_len / phys_len;
+	struct cam_dma_buff_info *mapping_info = NULL;
+	size_t unmapped;
+	dma_addr_t iova = 0;
+	struct scatterlist *sg;
+	int i = 0;
+	int rc;
+	struct iommu_domain *domain = NULL;
+	struct page *page;
+	struct sg_table *table = NULL;
+
+	CDBG("%s: nents = %lu, idx = %d, virt_len  = %zx\n",
+		__func__, nents, idx, virt_len);
+	CDBG("%s: phys_len = %zx, iommu_dir = %d, virt_addr = %pK\n",
+		__func__, phys_len, iommu_dir, virt_addr);
+
+	/*
+	 * This table will go inside the 'mapping' structure
+	 * where it will be held until put_scratch_buffer is called
+	 */
+	table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+	if (!table) {
+		rc = -ENOMEM;
+		goto err_table_alloc;
+	}
+
+	rc = sg_alloc_table(table, nents, GFP_KERNEL);
+	if (rc < 0) {
+		rc = -EINVAL;
+		goto err_sg_alloc;
+	}
+
+	page = alloc_pages(GFP_KERNEL, get_order(phys_len));
+	if (!page) {
+		rc = -ENOMEM;
+		goto err_page_alloc;
+	}
+
+	/* Now we create the sg list */
+	for_each_sg(table->sgl, sg, table->nents, i)
+		sg_set_page(sg, page, phys_len, 0);
+
+
+	/* Get the domain from within our cb_set struct and map it*/
+	domain = iommu_cb_set.cb_info[idx].mapping->domain;
+
+	rc = cam_smmu_alloc_scratch_va(&iommu_cb_set.cb_info[idx].scratch_map,
+		virt_len, &iova);
+
+	if (rc < 0) {
+		pr_err("Could not find valid iova for scratch buffer");
+		goto err_iommu_map;
+	}
+
+	if (iommu_map_sg(domain,
+		iova,
+		table->sgl,
+		table->nents,
+		iommu_dir) != virt_len) {
+		pr_err("iommu_map_sg() failed");
+		goto err_iommu_map;
+	}
+
+	/* Now update our mapping information within the cb_set struct */
+	mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+	if (!mapping_info) {
+		rc = -ENOMEM;
+		goto err_mapping_info;
+	}
+
+	mapping_info->ion_fd = 0xDEADBEEF;
+	mapping_info->buf = NULL;
+	mapping_info->attach = NULL;
+	mapping_info->table = table;
+	mapping_info->paddr = iova;
+	mapping_info->len = virt_len;
+	mapping_info->iommu_dir = iommu_dir;
+	mapping_info->ref_count = 1;
+	mapping_info->phys_len = phys_len;
+	mapping_info->region_id = CAM_SMMU_REGION_SCRATCH;
+
+	CDBG("%s: paddr = %pK, len = %zx, phys_len = %zx",
+		__func__, (void *)mapping_info->paddr,
+		mapping_info->len, mapping_info->phys_len);
+
+	list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+	*virt_addr = (dma_addr_t)iova;
+
+	CDBG("%s: mapped virtual address = %lx\n", __func__,
+		(unsigned long)*virt_addr);
+	return 0;
+
+err_mapping_info:
+	unmapped = iommu_unmap(domain, iova,  virt_len);
+	if (unmapped != virt_len)
+		pr_err("Unmapped only %zx instead of %zx", unmapped, virt_len);
+err_iommu_map:
+	__free_pages(page, get_order(phys_len));
+err_page_alloc:
+	sg_free_table(table);
+err_sg_alloc:
+	kfree(table);
+err_table_alloc:
+	return rc;
+}
+
+static int cam_smmu_free_scratch_buffer_remove_from_list(
+	struct cam_dma_buff_info *mapping_info,
+	int idx)
+{
+	int rc = 0;
+	size_t unmapped;
+	struct iommu_domain *domain =
+		iommu_cb_set.cb_info[idx].mapping->domain;
+	struct scratch_mapping *scratch_map =
+		&iommu_cb_set.cb_info[idx].scratch_map;
+
+	if (!mapping_info->table) {
+		pr_err("Error: Invalid params: dev = %pK, table = %pK",
+			(void *)iommu_cb_set.cb_info[idx].dev,
+			(void *)mapping_info->table);
+		return -EINVAL;
+	}
+
+	/* Clean up the mapping_info struct from the list */
+	unmapped = iommu_unmap(domain, mapping_info->paddr, mapping_info->len);
+	if (unmapped != mapping_info->len)
+		pr_err("Unmapped only %zx instead of %zx",
+			unmapped, mapping_info->len);
+
+	rc = cam_smmu_free_scratch_va(scratch_map,
+		mapping_info->paddr,
+		mapping_info->len);
+	if (rc < 0) {
+		pr_err("Error: Invalid iova while freeing scratch buffer\n");
+		rc = -EINVAL;
+	}
+
+	__free_pages(sg_page(mapping_info->table->sgl),
+			get_order(mapping_info->phys_len));
+	sg_free_table(mapping_info->table);
+	kfree(mapping_info->table);
+	list_del_init(&mapping_info->list);
+
+	kfree(mapping_info);
+	mapping_info = NULL;
+
+	return rc;
+}
+
+int cam_smmu_get_scratch_iova(int handle,
+	enum cam_smmu_map_dir dir,
+	dma_addr_t *paddr_ptr,
+	size_t virt_len,
+	size_t phys_len)
+{
+	int idx, rc;
+	unsigned int iommu_dir;
+
+	if (!paddr_ptr || !virt_len || !phys_len) {
+		pr_err("Error: Input pointer or lengths invalid\n");
+		return -EINVAL;
+	}
+
+	if (virt_len < phys_len) {
+		pr_err("Error: virt_len > phys_len\n");
+		return -EINVAL;
+	}
+
+	if (handle == HANDLE_INIT) {
+		pr_err("Error: Invalid handle\n");
+		return -EINVAL;
+	}
+
+	iommu_dir = cam_smmu_translate_dir_to_iommu_dir(dir);
+	if (iommu_dir == IOMMU_INVALID_DIR) {
+		pr_err("Error: translate direction failed. dir = %d\n", dir);
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!iommu_cb_set.cb_info[idx].scratch_buf_support) {
+		pr_err("Error: Context bank does not support scratch bufs\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n",
+		__func__, handle, idx, dir);
+	CDBG("%s: virt_len = %zx, phys_len  = %zx\n",
+		__func__, phys_len, virt_len);
+
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+		pr_err("Err:Dev %s should call SMMU attach before map buffer\n",
+				iommu_cb_set.cb_info[idx].name);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!IS_ALIGNED(virt_len, PAGE_SIZE)) {
+		pr_err("Requested scratch buffer length not page aligned\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (!IS_ALIGNED(virt_len, phys_len)) {
+		pr_err("Requested virt length not aligned with phys length\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	rc = cam_smmu_alloc_scratch_buffer_add_to_list(idx,
+		virt_len,
+		phys_len,
+		iommu_dir,
+		paddr_ptr);
+	if (rc < 0)
+		pr_err("Error: mapping or add list fail\n");
+
+error:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+
+int cam_smmu_put_scratch_iova(int handle,
+	dma_addr_t paddr)
+{
+	int idx;
+	int rc = -1;
+	struct cam_dma_buff_info *mapping_info;
+
+	if (handle == HANDLE_INIT) {
+		pr_err("Error: Invalid handle\n");
+		return -EINVAL;
+	}
+
+	/* find index in the iommu_cb_set.cb_info */
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto handle_err;
+	}
+
+	if (!iommu_cb_set.cb_info[idx].scratch_buf_support) {
+		pr_err("Error: Context bank does not support scratch buffers\n");
+		rc = -EINVAL;
+		goto handle_err;
+	}
+
+	/* Based on virtual address and index, we can find mapping info
+	 * of the scratch buffer
+	 */
+	mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr);
+	if (!mapping_info) {
+		pr_err("Error: Invalid params\n");
+		rc = -ENODEV;
+		goto handle_err;
+	}
+
+	/* unmapping one buffer from device */
+	rc = cam_smmu_free_scratch_buffer_remove_from_list(mapping_info, idx);
+	if (rc < 0) {
+		pr_err("Error: unmap or remove list fail\n");
+		goto handle_err;
+	}
+
+handle_err:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+
+int cam_smmu_map_sec_iova(int handle, int ion_fd,
+	enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
+	size_t *len_ptr)
+{
+	/* not implemented yet */
+	return -EPERM;
+}
+EXPORT_SYMBOL(cam_smmu_map_sec_iova);
+
+int cam_smmu_map_iova(int handle, int ion_fd,
+	enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
+	size_t *len_ptr, enum cam_smmu_region_id region_id)
+{
+	int idx, rc;
+	enum dma_data_direction dma_dir;
+	enum cam_smmu_buf_state buf_state;
+
+	if (!paddr_ptr || !len_ptr) {
+		pr_err("Input pointers are invalid\n");
+		return -EINVAL;
+	}
+
+	if (handle == HANDLE_INIT) {
+		pr_err("Invalid handle\n");
+		return -EINVAL;
+	}
+
+	/* clean the content from clients */
+	*paddr_ptr = (dma_addr_t)NULL;
+	if (region_id != CAM_SMMU_REGION_SHARED)
+		*len_ptr = (size_t)0;
+
+	dma_dir = cam_smmu_translate_dir(dir);
+	if (dma_dir == DMA_NONE) {
+		pr_err("translate direction failed. dir = %d\n", dir);
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+		pr_err("Err:Dev %s should call SMMU attach before map buffer\n",
+				iommu_cb_set.cb_info[idx].name);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr,
+		len_ptr);
+	if (buf_state == CAM_SMMU_BUFF_EXIST) {
+		CDBG("ion_fd:%d already in the list, give same addr back",
+				 ion_fd);
+		rc = 0;
+		goto get_addr_end;
+	}
+	rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir,
+			paddr_ptr, len_ptr, region_id);
+	if (rc < 0)
+		pr_err("mapping or add list fail\n");
+
+get_addr_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_map_iova);
+
+
+int cam_smmu_get_iova(int handle, int ion_fd,
+	dma_addr_t *paddr_ptr, size_t *len_ptr)
+{
+	int idx, rc = 0;
+	enum cam_smmu_buf_state buf_state;
+
+	if (!paddr_ptr || !len_ptr) {
+		pr_err("Error: Input pointers are invalid\n");
+		return -EINVAL;
+	}
+
+	if (handle == HANDLE_INIT) {
+		pr_err("Error: Invalid handle\n");
+		return -EINVAL;
+	}
+
+	/* clean the content from clients */
+	*paddr_ptr = (dma_addr_t)NULL;
+	*len_ptr = (size_t)0;
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+	buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr);
+	if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) {
+		CDBG("ion_fd:%d not in the mapped list", ion_fd);
+		rc = -EINVAL;
+		goto get_addr_end;
+	}
+
+get_addr_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_get_iova);
+
+int cam_smmu_unmap_sec_iova(int handle, int ion_fd)
+{
+	/* not implemented yet */
+	return -EPERM;
+}
+EXPORT_SYMBOL(cam_smmu_unmap_sec_iova);
+
+int cam_smmu_unmap_iova(int handle,
+	int ion_fd,
+	enum cam_smmu_region_id region_id)
+{
+	int idx, rc;
+	struct cam_dma_buff_info *mapping_info;
+
+	if (handle == HANDLE_INIT) {
+		pr_err("Error: Invalid handle\n");
+		return -EINVAL;
+	}
+
+	/* find index in the iommu_cb_set.cb_info */
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto unmap_end;
+	}
+
+	/* Based on ion fd and index, we can find mapping info of buffer */
+	mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd);
+	if (!mapping_info) {
+		pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+			idx, ion_fd);
+		rc = -EINVAL;
+		goto unmap_end;
+	}
+
+	mapping_info->ref_count--;
+	if (mapping_info->ref_count > 0) {
+		CDBG("There are still %u buffer(s) with same fd %d",
+			mapping_info->ref_count, mapping_info->ion_fd);
+		rc = 0;
+		goto unmap_end;
+	}
+
+	/* Unmapping one buffer from device */
+	CDBG("SMMU: removing buffer idx = %d\n", idx);
+	rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx);
+	if (rc < 0)
+		pr_err("Error: unmap or remove list fail\n");
+
+unmap_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_unmap_iova);
+
+int cam_smmu_put_iova(int handle, int ion_fd)
+{
+	int idx;
+	int rc = 0;
+	struct cam_dma_buff_info *mapping_info;
+
+	if (handle == HANDLE_INIT) {
+		pr_err("Error: Invalid handle\n");
+		return -EINVAL;
+	}
+
+	/* find index in the iommu_cb_set.cb_info */
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		rc = -EINVAL;
+		goto put_addr_end;
+	}
+
+	/* based on ion fd and index, we can find mapping info of buffer */
+	mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd);
+	if (!mapping_info) {
+		pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+			idx, ion_fd);
+		rc = -EINVAL;
+		goto put_addr_end;
+	}
+
+	mapping_info->ref_count--;
+
+put_addr_end:
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return rc;
+}
+EXPORT_SYMBOL(cam_smmu_put_iova);
+
+int cam_smmu_destroy_handle(int handle)
+{
+	int idx;
+
+	if (handle == HANDLE_INIT) {
+		pr_err("Error: Invalid handle\n");
+		return -EINVAL;
+	}
+
+	idx = GET_SMMU_TABLE_IDX(handle);
+	if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+		pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+			idx, handle);
+		return -EINVAL;
+	}
+
+	mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+	if (iommu_cb_set.cb_info[idx].handle != handle) {
+		pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+			iommu_cb_set.cb_info[idx].handle, handle);
+		mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+		return -EINVAL;
+	}
+
+	if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) {
+		pr_err("Client %s buffer list is not clean!\n",
+			iommu_cb_set.cb_info[idx].name);
+		cam_smmu_print_list(idx);
+		cam_smmu_clean_buffer_list(idx);
+	}
+
+	iommu_cb_set.cb_info[idx].cb_count = 0;
+	iommu_cb_set.cb_info[idx].handle = HANDLE_INIT;
+	mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+	return 0;
+}
+EXPORT_SYMBOL(cam_smmu_destroy_handle);
+
+static void cam_smmu_deinit_cb(struct cam_context_bank_info *cb)
+{
+	arm_iommu_detach_device(cb->dev);
+
+	if (cb->io_support && cb->mapping) {
+		arm_iommu_release_mapping(cb->mapping);
+		cb->mapping = NULL;
+	}
+
+	if (cb->shared_support) {
+		gen_pool_destroy(cb->shared_mem_pool);
+		cb->shared_mem_pool = NULL;
+	}
+
+	if (cb->scratch_buf_support) {
+		kfree(cb->scratch_map.bitmap);
+		cb->scratch_map.bitmap = NULL;
+	}
+}
+
+static void cam_smmu_release_cb(struct platform_device *pdev)
+{
+	int i = 0;
+
+	for (i = 0; i < iommu_cb_set.cb_num; i++)
+		cam_smmu_deinit_cb(&iommu_cb_set.cb_info[i]);
+
+	devm_kfree(&pdev->dev, iommu_cb_set.cb_info);
+	iommu_cb_set.cb_num = 0;
+}
+
+static int cam_smmu_setup_cb(struct cam_context_bank_info *cb,
+	struct device *dev)
+{
+	int rc = 0;
+
+	if (!cb || !dev) {
+		pr_err("Error: invalid input params\n");
+		return -EINVAL;
+	}
+
+	cb->dev = dev;
+	cb->is_fw_allocated = false;
+
+	/* Create a pool with 4K granularity for supporting shared memory */
+	if (cb->shared_support) {
+		cb->shared_mem_pool = gen_pool_create(
+			SHARED_MEM_POOL_GRANULARITY, -1);
+
+		if (!cb->shared_mem_pool)
+			return -ENOMEM;
+
+		rc = gen_pool_add(cb->shared_mem_pool,
+			cb->shared_info.iova_start,
+			cb->shared_info.iova_len,
+			-1);
+
+		CDBG("Shared mem start->%lX\n",
+			(unsigned long)cb->shared_info.iova_start);
+		CDBG("Shared mem len->%zu\n", cb->shared_info.iova_len);
+
+		if (rc) {
+			pr_err("Genpool chunk creation failed\n");
+			gen_pool_destroy(cb->shared_mem_pool);
+			cb->shared_mem_pool = NULL;
+			return rc;
+		}
+	}
+
+	if (cb->scratch_buf_support) {
+		rc = cam_smmu_init_scratch_map(&cb->scratch_map,
+			cb->scratch_info.iova_start,
+			cb->scratch_info.iova_len,
+			0);
+		if (rc < 0) {
+			pr_err("Error: failed to create scratch map\n");
+			rc = -ENODEV;
+			goto end;
+		}
+	}
+
+	/* create a virtual mapping */
+	if (cb->io_support) {
+		cb->mapping = arm_iommu_create_mapping(&platform_bus_type,
+			cb->io_info.iova_start, cb->io_info.iova_len);
+		if (IS_ERR(cb->mapping)) {
+			pr_err("Error: create mapping Failed\n");
+			rc = -ENODEV;
+			goto end;
+		}
+	} else {
+		pr_err("Context bank does not have IO region\n");
+		rc = -ENODEV;
+		goto end;
+	}
+
+	return rc;
+end:
+	if (cb->shared_support) {
+		gen_pool_destroy(cb->shared_mem_pool);
+		cb->shared_mem_pool = NULL;
+	}
+
+	if (cb->scratch_buf_support) {
+		kfree(cb->scratch_map.bitmap);
+		cb->scratch_map.bitmap = NULL;
+	}
+
+	return rc;
+}
+
+static int cam_alloc_smmu_context_banks(struct device *dev)
+{
+	struct device_node *domains_child_node = NULL;
+
+	if (!dev) {
+		pr_err("Error: Invalid device\n");
+		return -ENODEV;
+	}
+
+	iommu_cb_set.cb_num = 0;
+
+	/* traverse thru all the child nodes and increment the cb count */
+	for_each_available_child_of_node(dev->of_node, domains_child_node) {
+		if (of_device_is_compatible(domains_child_node,
+			"qcom,msm-cam-smmu-cb"))
+			iommu_cb_set.cb_num++;
+
+		if (of_device_is_compatible(domains_child_node,
+			"qcom,qsmmu-cam-cb"))
+			iommu_cb_set.cb_num++;
+	}
+
+	if (iommu_cb_set.cb_num == 0) {
+		pr_err("Error: no context banks present\n");
+		return -ENOENT;
+	}
+
+	/* allocate memory for the context banks */
+	iommu_cb_set.cb_info = devm_kzalloc(dev,
+		iommu_cb_set.cb_num * sizeof(struct cam_context_bank_info),
+		GFP_KERNEL);
+
+	if (!iommu_cb_set.cb_info) {
+		pr_err("Error: cannot allocate context banks\n");
+		return -ENOMEM;
+	}
+
+	cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_INIT);
+	iommu_cb_set.cb_init_count = 0;
+
+	CDBG("no of context banks :%d\n", iommu_cb_set.cb_num);
+	return 0;
+}
+
+static int cam_smmu_get_memory_regions_info(struct device_node *of_node,
+	struct cam_context_bank_info *cb)
+{
+	int rc = 0;
+	struct device_node *mem_map_node = NULL;
+	struct device_node *child_node = NULL;
+	const char *region_name;
+	int num_regions = 0;
+
+	if (!of_node || !cb) {
+		pr_err("Invalid argument(s)\n");
+		return -EINVAL;
+	}
+
+	mem_map_node = of_get_child_by_name(of_node, "iova-mem-map");
+	if (!mem_map_node) {
+		pr_err("iova-mem-map not present\n");
+		return -EINVAL;
+	}
+
+	for_each_available_child_of_node(mem_map_node, child_node) {
+		uint32_t region_start;
+		uint32_t region_len;
+		uint32_t region_id;
+
+		num_regions++;
+		rc = of_property_read_string(child_node,
+			"iova-region-name", &region_name);
+		if (rc < 0) {
+			of_node_put(mem_map_node);
+			pr_err("IOVA region not found\n");
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(child_node,
+			"iova-region-start", &region_start);
+		if (rc < 0) {
+			of_node_put(mem_map_node);
+			pr_err("Failed to read iova-region-start\n");
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(child_node,
+			"iova-region-len", &region_len);
+		if (rc < 0) {
+			of_node_put(mem_map_node);
+			pr_err("Failed to read iova-region-len\n");
+			return -EINVAL;
+		}
+
+		rc = of_property_read_u32(child_node,
+			"iova-region-id", &region_id);
+		if (rc < 0) {
+			of_node_put(mem_map_node);
+			pr_err("Failed to read iova-region-id\n");
+			return -EINVAL;
+		}
+
+		switch (region_id) {
+		case CAM_SMMU_REGION_FIRMWARE:
+			cb->firmware_support = 1;
+			cb->firmware_info.iova_start = region_start;
+			cb->firmware_info.iova_len = region_len;
+			break;
+		case CAM_SMMU_REGION_SHARED:
+			cb->shared_support = 1;
+			cb->shared_info.iova_start = region_start;
+			cb->shared_info.iova_len = region_len;
+			break;
+		case CAM_SMMU_REGION_SCRATCH:
+			cb->scratch_buf_support = 1;
+			cb->scratch_info.iova_start = region_start;
+			cb->scratch_info.iova_len = region_len;
+			break;
+		case CAM_SMMU_REGION_IO:
+			cb->io_support = 1;
+			cb->io_info.iova_start = region_start;
+			cb->io_info.iova_len = region_len;
+			break;
+		default:
+			pr_err("Incorrect region id present in DT file: %d\n",
+				region_id);
+		}
+
+		CDBG("Found label -> %s\n", cb->name);
+		CDBG("Found region -> %s\n", region_name);
+		CDBG("region_start -> %X\n", region_start);
+		CDBG("region_len -> %X\n", region_len);
+		CDBG("region_id -> %X\n", region_id);
+	}
+	of_node_put(mem_map_node);
+
+	if (!num_regions) {
+		pr_err("No memory regions found, at least one needed\n");
+		rc = -ENODEV;
+	}
+
+	return rc;
+}
+
+static int cam_populate_smmu_context_banks(struct device *dev,
+	enum cam_iommu_type type)
+{
+	int rc = 0;
+	struct cam_context_bank_info *cb;
+	struct device *ctx = NULL;
+
+	if (!dev) {
+		pr_err("Error: Invalid device\n");
+		return -ENODEV;
+	}
+
+	/* check the bounds */
+	if (iommu_cb_set.cb_init_count >= iommu_cb_set.cb_num) {
+		pr_err("Error: populate more than allocated cb\n");
+		rc = -EBADHANDLE;
+		goto cb_init_fail;
+	}
+
+	/* read the context bank from cb set */
+	cb = &iommu_cb_set.cb_info[iommu_cb_set.cb_init_count];
+
+	/* set the name of the context bank */
+	rc = of_property_read_string(dev->of_node, "label", &cb->name);
+	if (rc < 0) {
+		pr_err("Error: failed to read label from sub device\n");
+		goto cb_init_fail;
+	}
+
+	rc = cam_smmu_get_memory_regions_info(dev->of_node,
+		cb);
+	if (rc < 0) {
+		pr_err("Error: Getting region info\n");
+		return rc;
+	}
+
+	/* set up the iommu mapping for the  context bank */
+	if (type == CAM_QSMMU) {
+		pr_err("Error: QSMMU ctx not supported for : %s\n", cb->name);
+		return -ENODEV;
+	}
+
+	ctx = dev;
+	CDBG("getting Arm SMMU ctx : %s\n", cb->name);
+
+	rc = cam_smmu_setup_cb(cb, ctx);
+	if (rc < 0) {
+		pr_err("Error: failed to setup cb : %s\n", cb->name);
+		goto cb_init_fail;
+	}
+
+	if (cb->io_support && cb->mapping)
+		iommu_set_fault_handler(cb->mapping->domain,
+			cam_smmu_iommu_fault_handler,
+			(void *)cb->name);
+
+	/* increment count to next bank */
+	iommu_cb_set.cb_init_count++;
+
+	CDBG("X: cb init count :%d\n", iommu_cb_set.cb_init_count);
+
+cb_init_fail:
+	return rc;
+}
+
+static int cam_smmu_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct device *dev = &pdev->dev;
+
+	if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu")) {
+		rc = cam_alloc_smmu_context_banks(dev);
+		if (rc < 0) {
+			pr_err("Error: allocating context banks\n");
+			return -ENOMEM;
+		}
+	}
+	if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-cb")) {
+		rc = cam_populate_smmu_context_banks(dev, CAM_ARM_SMMU);
+		if (rc < 0) {
+			pr_err("Error: populating context banks\n");
+			return -ENOMEM;
+		}
+		return rc;
+	}
+	if (of_device_is_compatible(dev->of_node, "qcom,qsmmu-cam-cb")) {
+		rc = cam_populate_smmu_context_banks(dev, CAM_QSMMU);
+		if (rc < 0) {
+			pr_err("Error: populating context banks\n");
+			return -ENOMEM;
+		}
+		return rc;
+	}
+
+	if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-fw-dev")) {
+		icp_fw.fw_dev = &pdev->dev;
+		icp_fw.fw_kva = NULL;
+		icp_fw.fw_dma_hdl = 0;
+		return rc;
+	}
+
+	/* probe through all the subdevices */
+	rc = of_platform_populate(pdev->dev.of_node, msm_cam_smmu_dt_match,
+				NULL, &pdev->dev);
+	if (rc < 0) {
+		pr_err("Error: populating devices\n");
+	} else {
+		INIT_WORK(&iommu_cb_set.smmu_work, cam_smmu_page_fault_work);
+		mutex_init(&iommu_cb_set.payload_list_lock);
+		INIT_LIST_HEAD(&iommu_cb_set.payload_list);
+	}
+
+	return rc;
+}
+
+static int cam_smmu_remove(struct platform_device *pdev)
+{
+	/* release all the context banks and memory allocated */
+	cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT);
+	if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu"))
+		cam_smmu_release_cb(pdev);
+	return 0;
+}
+
+static struct platform_driver cam_smmu_driver = {
+	.probe = cam_smmu_probe,
+	.remove = cam_smmu_remove,
+	.driver = {
+		.name = "msm_cam_smmu",
+		.owner = THIS_MODULE,
+		.of_match_table = msm_cam_smmu_dt_match,
+	},
+};
+
+static int __init cam_smmu_init_module(void)
+{
+	return platform_driver_register(&cam_smmu_driver);
+}
+
+static void __exit cam_smmu_exit_module(void)
+{
+	platform_driver_unregister(&cam_smmu_driver);
+}
+
+module_init(cam_smmu_init_module);
+module_exit(cam_smmu_exit_module);
+MODULE_DESCRIPTION("MSM Camera SMMU driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
new file mode 100644
index 0000000..76e9135
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
@@ -0,0 +1,255 @@
+/* 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.
+ */
+
+#ifndef _CAM_SMMU_API_H_
+#define _CAM_SMMU_API_H_
+
+#include <linux/dma-direction.h>
+#include <linux/module.h>
+#include <linux/dma-buf.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/of_platform.h>
+#include <linux/iommu.h>
+#include <linux/random.h>
+#include <linux/spinlock_types.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+
+/*Enum for possible CAM SMMU operations */
+enum cam_smmu_ops_param {
+	CAM_SMMU_ATTACH,
+	CAM_SMMU_DETACH,
+	CAM_SMMU_VOTE,
+	CAM_SMMU_DEVOTE,
+	CAM_SMMU_OPS_INVALID
+};
+
+enum cam_smmu_map_dir {
+	CAM_SMMU_MAP_READ,
+	CAM_SMMU_MAP_WRITE,
+	CAM_SMMU_MAP_RW,
+	CAM_SMMU_MAP_INVALID
+};
+
+enum cam_smmu_region_id {
+	CAM_SMMU_REGION_FIRMWARE,
+	CAM_SMMU_REGION_SHARED,
+	CAM_SMMU_REGION_SCRATCH,
+	CAM_SMMU_REGION_IO
+};
+
+/**
+ * @brief           : Gets an smmu handle
+ *
+ * @param identifier: Unique identifier to be used by clients which they
+ *                    should get from device tree. CAM SMMU driver will
+ *                    not enforce how this string is obtained and will
+ *                    only validate this against the list of permitted
+ *                    identifiers
+ * @param handle_ptr: Based on the indentifier, CAM SMMU drivier will
+ *                    fill the handle pointed by handle_ptr
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_handle(char *identifier, int *handle_ptr);
+
+/**
+ * @brief       : Performs IOMMU operations
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param op    : Operation to be performed. Can be either CAM_SMMU_ATTACH
+ *                or CAM_SMMU_DETACH
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_ops(int handle, enum cam_smmu_ops_param op);
+
+/**
+ * @brief       : Maps IOVA for calling driver
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ * @dir         : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ *                DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @dma_addr    : Pointer to physical address where mapped address will be
+ *                returned if region_id is CAM_SMMU_REGION_IO. If region_id is
+ *                CAM_SMMU_REGION_SHARED, dma_addr is used as an input parameter
+ *                which specifies the cpu virtual address to map.
+ * @len         : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_map_iova(int handle,
+	int ion_fd, enum cam_smmu_map_dir dir,
+	dma_addr_t *dma_addr, size_t *len_ptr,
+	enum cam_smmu_region_id region_id);
+
+/**
+ * @brief       : Unmaps IOVA for calling driver
+ *
+ * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_unmap_iova(int handle,
+	int ion_fd,
+	enum cam_smmu_region_id region_id);
+
+/**
+ * @brief          : Allocates a scratch buffer
+ *
+ * This function allocates a scratch virtual buffer of length virt_len in the
+ * device virtual address space mapped to phys_len physically contiguous bytes
+ * in that device's SMMU.
+ *
+ * virt_len and phys_len are expected to be aligned to PAGE_SIZE and with each
+ * other, otherwise -EINVAL is returned.
+ *
+ * -EINVAL will be returned if virt_len is less than phys_len.
+ *
+ * Passing a too large phys_len might also cause failure if that much size is
+ * not available for allocation in a physically contiguous way.
+ *
+ * @param handle   : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param dir      : Direction of mapping which will translate to IOMMU_READ
+ *                   IOMMU_WRITE or a bit mask of both.
+ * @param paddr_ptr: Device virtual address that the client device will be
+ *                   able to read from/write to
+ * @param virt_len : Virtual length of the scratch buffer
+ * @param phys_len : Physical length of the scratch buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_get_scratch_iova(int handle,
+	enum cam_smmu_map_dir dir,
+	dma_addr_t *paddr_ptr,
+	size_t virt_len,
+	size_t phys_len);
+
+/**
+ * @brief          : Frees a scratch buffer
+ *
+ * This function frees a scratch buffer and releases the corresponding SMMU
+ * mappings.
+ *
+ * @param handle   : Handle to identify the CAMSMMU client (IFE, ICP, etc.)
+ * @param paddr    : Device virtual address of client's scratch buffer that
+ *                   will be freed.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_put_scratch_iova(int handle,
+	dma_addr_t paddr);
+
+/**
+ *@brief        : Destroys an smmu handle
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_destroy_handle(int handle);
+
+/**
+ * @brief       : Finds index by handle in the smmu client table
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @return Index of SMMU client. Nagative in case of error.
+ */
+int cam_smmu_find_index_by_handle(int hdl);
+
+/**
+ * @brief       : Registers smmu fault handler for client
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param client_page_fault_handler: It is triggered in IOMMU page fault
+ * @param token: It is input param when trigger page fault handler
+ */
+void cam_smmu_reg_client_page_fault_handler(int handle,
+	void (*client_page_fault_handler)(struct iommu_domain *,
+	struct device *, unsigned long,
+	int, void*), void *token);
+
+/**
+ * @brief Maps memory from an ION fd into IOVA space
+ *
+ * @param handle: SMMU handle identifying the context bank to map to
+ * @param ion_fd: ION fd of memory to map to
+ * @param paddr_ptr: Pointer IOVA address that will be returned
+ * @param len_ptr: Length of memory mapped
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_iova(int handle, int ion_fd,
+	dma_addr_t *paddr_ptr, size_t *len_ptr);
+/**
+ * @brief Unmaps memory from context bank
+ *
+ * @param handle: SMMU handle identifying the context bank
+ * @param ion_fd: ION fd of memory to unmap
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_put_iova(int handle, int ion_fd);
+
+/**
+ * @brief Maps secure memory for SMMU handle
+ *
+ * @param handle: SMMU handle identifying context bank
+ * @param ion_fd: ION fd to map securely
+ * @param dir: DMA Direction for the mapping
+ * @param dma_addr: Returned IOVA address after mapping
+ * @param len_ptr: Length of memory mapped
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_map_sec_iova(int handle,
+	int ion_fd, enum cam_smmu_map_dir dir,
+	dma_addr_t *dma_addr, size_t *len_ptr);
+
+/**
+ * @brief Unmaps secure memopry for SMMU handle
+ *
+ * @param handle: SMMU handle identifying context bank
+ * @param ion_fd: ION fd to unmap
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_unmap_sec_iova(int handle, int ion_fd);
+
+
+/**
+ * @brief Allocates firmware for context bank
+ *
+ * @param smmu_hdl: SMMU handle identifying context bank
+ * @param iova: IOVA address of allocated firmware
+ * @param kvaddr: CPU mapped address of allocated firmware
+ * @param len: Length of allocated firmware memory
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_alloc_firmware(int32_t smmu_hdl,
+	dma_addr_t *iova,
+	uint64_t *kvaddr,
+	size_t *len);
+
+/**
+ * @brief Deallocates firmware memory for context bank
+ *
+ * @param smmu_hdl: SMMU handle identifying the context bank
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_dealloc_firmware(int32_t smmu_hdl);
+#endif /* _CAM_SMMU_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
index 4f5bf87..ecc62c8 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
@@ -57,6 +57,48 @@
 	return 0;
 }
 
+uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table,
+	uint32_t *sync_objs,
+	uint32_t num_objs)
+{
+	int i;
+	struct sync_table_row *child_row = NULL;
+	int success_count = 0;
+	int active_count = 0;
+
+	if (!table || !sync_objs)
+		return CAM_SYNC_STATE_SIGNALED_ERROR;
+
+	/*
+	 * We need to arrive at the state of the merged object based on
+	 * counts of error, active and success states of all children objects
+	 */
+	for (i = 0; i < num_objs; i++) {
+		child_row = table + sync_objs[i];
+		switch (child_row->state) {
+		case CAM_SYNC_STATE_SIGNALED_ERROR:
+			return CAM_SYNC_STATE_SIGNALED_ERROR;
+		case CAM_SYNC_STATE_SIGNALED_SUCCESS:
+			success_count++;
+			break;
+		case CAM_SYNC_STATE_ACTIVE:
+			active_count++;
+			break;
+		default:
+			pr_err("Invalid state of child object during merge\n");
+			return CAM_SYNC_STATE_SIGNALED_ERROR;
+		}
+	}
+
+	if (active_count)
+		return CAM_SYNC_STATE_ACTIVE;
+
+	if (success_count == num_objs)
+		return CAM_SYNC_STATE_SIGNALED_SUCCESS;
+
+	return CAM_SYNC_STATE_SIGNALED_ERROR;
+}
+
 int cam_sync_init_group_object(struct sync_table_row *table,
 	uint32_t idx,
 	uint32_t *sync_objs,
@@ -113,12 +155,16 @@
 
 	row->type = CAM_SYNC_TYPE_GROUP;
 	row->sync_id = idx;
-	row->state = CAM_SYNC_STATE_ACTIVE;
+	row->state = cam_sync_util_get_group_object_state(table,
+		sync_objs, num_objs);
 	row->remaining = num_objs;
 	init_completion(&row->signaled);
 	INIT_LIST_HEAD(&row->callback_list);
 	INIT_LIST_HEAD(&row->user_payload_list);
 
+	if (row->state != CAM_SYNC_STATE_ACTIVE)
+		complete_all(&row->signaled);
+
 	spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
 	return 0;
 }
@@ -208,6 +254,11 @@
 	int i;
 	struct sync_table_row *row = NULL;
 
+	if (num_objs <= 1) {
+		pr_err("Single object merge is not allowed\n");
+		return -EINVAL;
+	}
+
 	for (i = 0; i < num_objs; i++) {
 		row = sync_dev->sync_table + sync_obj[i];
 		spin_lock_bh(&sync_dev->row_spinlocks[sync_obj[i]]);
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index 683386c..b16e37e 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
@@ -412,6 +412,7 @@
 			goto put_regulator;
 		}
 		disable_irq(soc_info->irq_line->start);
+		soc_info->irq_data = irq_data;
 	}
 
 	/* Get Clock */
@@ -439,7 +440,8 @@
 
 	if (soc_info->irq_line) {
 		disable_irq(soc_info->irq_line->start);
-		free_irq(soc_info->irq_line->start, soc_info);
+		devm_free_irq(&soc_info->pdev->dev,
+			soc_info->irq_line->start, irq_data);
 	}
 
 put_regulator:
@@ -495,7 +497,8 @@
 
 	if (soc_info->irq_line) {
 		disable_irq(soc_info->irq_line->start);
-		free_irq(soc_info->irq_line->start, soc_info);
+		devm_free_irq(&soc_info->pdev->dev,
+			soc_info->irq_line->start, soc_info->irq_data);
 	}
 
 	return 0;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
index 0baa9e6..3e8226f 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
@@ -58,6 +58,7 @@
  * @index:                  Instance id for the camera device
  * @irq_name:               Name of the irq associated with the device
  * @irq_line:               Irq resource
+ * @irq_data:               Private data that is passed when IRQ is requested
  * @num_mem_block:          Number of entry in the "reg-names"
  * @mem_block_name:         Array of the reg block name
  * @mem_block_cam_base:     Array of offset of this register space compared
@@ -85,6 +86,7 @@
 
 	const char                     *irq_name;
 	struct resource                *irq_line;
+	void                           *irq_data;
 
 	uint32_t                        num_mem_block;
 	const char                     *mem_block_name[CAM_SOC_MAX_BLOCK];
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index 3bf6ce0..9194b44 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -96,7 +96,6 @@
  * @SDE_CAPS_R1_WB: MDSS V1.x WB block
  * @SDE_CAPS_R3_WB: MDSS V3.x WB block
  * @SDE_CAPS_R3_1P5_DOWNSCALE: 1.5x downscale rotator support
- * @SDE_CAPS_MIN_BUS_VOTE: minimum bus vote prior to power enable
  * @SDE_CAPS_SBUF_1: stream buffer support for inline rotation
  * @SDE_CAPS_UBWC_2: universal bandwidth compression version 2
  */
@@ -105,7 +104,6 @@
 	SDE_CAPS_R3_WB,
 	SDE_CAPS_R3_1P5_DOWNSCALE,
 	SDE_CAPS_SEC_ATTACH_DETACH_SMMU,
-	SDE_CAPS_MIN_BUS_VOTE,
 	SDE_CAPS_SBUF_1,
 	SDE_CAPS_UBWC_2,
 	SDE_CAPS_MAX,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 9a28700..30fda07 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -25,6 +25,7 @@
 #include <linux/msm-bus-board.h>
 #include <linux/regulator/consumer.h>
 #include <linux/dma-direction.h>
+#include <linux/sde_rsc.h>
 #include <soc/qcom/scm.h>
 #include <soc/qcom/secure_buffer.h>
 #include <asm/cacheflush.h>
@@ -293,14 +294,13 @@
 
 	SDEROT_DBG("core_clk %lu\n", total_clk_rate);
 	ATRACE_INT("core_clk", total_clk_rate);
-	sde_rotator_set_clk_rate(mgr, total_clk_rate, SDE_ROTATOR_CLK_ROT_CORE);
+	sde_rotator_set_clk_rate(mgr, total_clk_rate, SDE_ROTATOR_CLK_MDSS_ROT);
 
 	return 0;
 }
 
 static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on)
 {
-	struct sde_rot_data_type *mdata = sde_rot_get_mdata();
 	int ret;
 
 	if (WARN_ON(mgr->regulator_enable == on)) {
@@ -311,7 +311,7 @@
 	SDEROT_EVTLOG(on);
 	SDEROT_DBG("%s: rotator regulators\n", on ? "Enable" : "Disable");
 
-	if (test_bit(SDE_CAPS_MIN_BUS_VOTE, mdata->sde_caps_map) && on) {
+	if (on) {
 		mgr->minimum_bw_vote = mgr->enable_bw_vote;
 		sde_rotator_update_perf(mgr);
 	}
@@ -319,8 +319,13 @@
 	if (mgr->ops_hw_pre_pmevent)
 		mgr->ops_hw_pre_pmevent(mgr, on);
 
-	ret = sde_rot_enable_vreg(mgr->module_power.vreg_config,
-		mgr->module_power.num_vreg, on);
+	if (mgr->rsc_client)
+		ret = sde_rsc_client_state_update(mgr->rsc_client,
+				on ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE,
+				NULL, -1);
+	else
+		ret = sde_rot_enable_vreg(mgr->module_power.vreg_config,
+			mgr->module_power.num_vreg, on);
 	if (ret) {
 		SDEROT_WARN("Rotator regulator failed to %s\n",
 			on ? "enable" : "disable");
@@ -330,7 +335,7 @@
 	if (mgr->ops_hw_post_pmevent)
 		mgr->ops_hw_post_pmevent(mgr, on);
 
-	if (test_bit(SDE_CAPS_MIN_BUS_VOTE, mdata->sde_caps_map) && !on) {
+	if (!on) {
 		mgr->minimum_bw_vote = 0;
 		sde_rotator_update_perf(mgr);
 	}
@@ -407,13 +412,13 @@
 			if (ret)
 				goto error_mdss_axi;
 			ret = sde_rotator_enable_clk(mgr,
-						SDE_ROTATOR_CLK_ROT_CORE);
-			if (ret)
-				goto error_rot_core;
-			ret = sde_rotator_enable_clk(mgr,
 						SDE_ROTATOR_CLK_MDSS_ROT);
 			if (ret)
 				goto error_mdss_rot;
+			ret = sde_rotator_enable_clk(mgr,
+						SDE_ROTATOR_CLK_MDSS_ROT_SUB);
+			if (ret)
+				goto error_rot_sub;
 
 			/* Active+Sleep */
 			msm_bus_scale_client_update_context(
@@ -421,8 +426,9 @@
 				mgr->data_bus.curr_bw_uc_idx);
 			trace_rot_bw_ao_as_context(0);
 		} else {
+			sde_rotator_disable_clk(mgr,
+					SDE_ROTATOR_CLK_MDSS_ROT_SUB);
 			sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT);
-			sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_ROT_CORE);
 			sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI);
 			sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB);
 			sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_GCC_AXI);
@@ -438,9 +444,9 @@
 	}
 
 	return ret;
+error_rot_sub:
+	sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT);
 error_mdss_rot:
-	sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_ROT_CORE);
-error_rot_core:
 	sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI);
 error_mdss_axi:
 	sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB);
@@ -551,6 +557,12 @@
 	if (!input)
 		dir = DMA_FROM_DEVICE;
 
+	if (buffer->plane_count > SDE_ROT_MAX_PLANES) {
+		SDEROT_ERR("buffer plane_count exceeds MAX_PLANE limit:%d\n",
+				buffer->plane_count);
+		return -EINVAL;
+	}
+
 	data->sbuf = buffer->sbuf;
 	data->scid = buffer->scid;
 	data->writeback = buffer->writeback;
@@ -2731,11 +2743,19 @@
 			sde_rotator_search_dt_clk(pdev, mgr, "axi_clk",
 				SDE_ROTATOR_CLK_MDSS_AXI, true) ||
 			sde_rotator_search_dt_clk(pdev, mgr, "rot_core_clk",
-				SDE_ROTATOR_CLK_ROT_CORE, true) ||
-			sde_rotator_search_dt_clk(pdev, mgr, "rot_clk",
-				SDE_ROTATOR_CLK_MDSS_ROT, true))
+				SDE_ROTATOR_CLK_MDSS_ROT, false))
 		rc = -EINVAL;
 
+	/*
+	 * If 'MDSS_ROT' is already present, place 'rot_clk' under
+	 * MDSS_ROT_SUB. Otherwise, place it directly into MDSS_ROT.
+	 */
+	if (sde_rotator_get_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT))
+		rc = sde_rotator_search_dt_clk(pdev, mgr, "rot_clk",
+				SDE_ROTATOR_CLK_MDSS_ROT_SUB, true);
+	else
+		rc = sde_rotator_search_dt_clk(pdev, mgr, "rot_clk",
+				SDE_ROTATOR_CLK_MDSS_ROT, true);
 clk_err:
 	return rc;
 }
@@ -2766,9 +2786,21 @@
 {
 	int ret;
 
-	ret = sde_rotator_get_dt_vreg_data(&pdev->dev, &mgr->module_power);
-	if (ret)
+	mgr->rsc_client = sde_rsc_client_create(
+			SDE_RSC_INDEX, "sde_rotator_core", false);
+	if (IS_ERR(mgr->rsc_client)) {
+		ret = PTR_ERR(mgr->rsc_client);
+		pr_err("rsc client create returned %d\n", ret);
+		mgr->rsc_client = NULL;
 		return ret;
+	}
+
+	if (!mgr->rsc_client) {
+		ret = sde_rotator_get_dt_vreg_data(
+				&pdev->dev, &mgr->module_power);
+		if (ret)
+			return ret;
+	}
 
 	ret = sde_rotator_register_clk(pdev, mgr);
 	if (ret)
@@ -2788,9 +2820,15 @@
 {
 	struct platform_device *pdev = mgr->pdev;
 
-	sde_rotator_put_dt_vreg_data(&pdev->dev, &mgr->module_power);
 	sde_rotator_unregister_clk(mgr);
 	sde_rotator_bus_scale_unregister(mgr);
+
+	if (mgr->rsc_client) {
+		sde_rsc_client_destroy(mgr->rsc_client);
+		mgr->rsc_client = NULL;
+	} else {
+		sde_rotator_put_dt_vreg_data(&pdev->dev, &mgr->module_power);
+	}
 }
 
 int sde_rotator_core_init(struct sde_rot_mgr **pmgr,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 819f57b..0051e96 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -125,7 +125,7 @@
 enum sde_rotator_clk_type {
 	SDE_ROTATOR_CLK_MDSS_AHB,
 	SDE_ROTATOR_CLK_MDSS_AXI,
-	SDE_ROTATOR_CLK_ROT_CORE,
+	SDE_ROTATOR_CLK_MDSS_ROT_SUB,
 	SDE_ROTATOR_CLK_MDSS_ROT,
 	SDE_ROTATOR_CLK_MNOC_AHB,
 	SDE_ROTATOR_CLK_GCC_AHB,
@@ -373,6 +373,7 @@
  * @reg_bus: register bus configuration state
  * @module_power: power/clock configuration state
  * @regulator_enable: true if foot switch is enabled; false otherwise
+ * @rsc_client: pointer to rsc client handle
  * @res_ref_cnt: reference count of how many times resource is requested
  * @rot_enable_clk_cnt: reference count of how many times clock is requested
  * @rot_clk: array of rotator and periphery clocks
@@ -417,6 +418,8 @@
 	struct sde_module_power module_power;
 	bool regulator_enable;
 
+	struct sde_rsc_client *rsc_client;
+
 	int res_ref_cnt;
 	int rot_enable_clk_cnt;
 	struct sde_rot_clk *rot_clk;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index 1c94632..90b7194 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -438,6 +438,8 @@
 {
 	struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q);
 	struct sde_rotator_device *rot_dev = ctx->rot_dev;
+	struct sde_rotator_request *request;
+	struct list_head *curr, *next;
 	int i;
 	int ret;
 
@@ -458,6 +460,21 @@
 		sde_rot_mgr_lock(rot_dev->mgr);
 		sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private);
 		sde_rot_mgr_unlock(rot_dev->mgr);
+		list_for_each_safe(curr, next, &ctx->pending_list) {
+			request = container_of(curr, struct sde_rotator_request,
+						list);
+
+			SDEDEV_DBG(rot_dev->dev, "cancel request s:%d\n",
+					ctx->session_id);
+			mutex_unlock(q->lock);
+			cancel_work_sync(&request->submit_work);
+			cancel_work_sync(&request->retire_work);
+			mutex_lock(q->lock);
+			spin_lock(&ctx->list_lock);
+			list_del_init(&request->list);
+			list_add_tail(&request->list, &ctx->retired_list);
+			spin_unlock(&ctx->list_lock);
+		}
 	}
 
 	sde_rotator_return_all_buffers(q, VB2_BUF_STATE_ERROR);
@@ -2594,8 +2611,13 @@
 static long sde_rotator_compat_ioctl32(struct file *file,
 	unsigned int cmd, unsigned long arg)
 {
+	struct video_device *vdev = video_devdata(file);
+	struct sde_rotator_ctx *ctx =
+			sde_rotator_ctx_from_fh(file->private_data);
 	long ret;
 
+	mutex_lock(vdev->lock);
+
 	switch (cmd) {
 	case VIDIOC_S_SDE_ROTATOR_FENCE:
 	case VIDIOC_G_SDE_ROTATOR_FENCE:
@@ -2604,14 +2626,14 @@
 
 		if (copy_from_user(&fence, (void __user *)arg,
 				sizeof(struct msm_sde_rotator_fence)))
-			return -EFAULT;
+			goto ioctl32_error;
 
 		ret = sde_rotator_private_ioctl(file, file->private_data,
 			0, cmd, (void *)&fence);
 
 		if (copy_to_user((void __user *)arg, &fence,
 				sizeof(struct msm_sde_rotator_fence)))
-			return -EFAULT;
+			goto ioctl32_error;
 
 		break;
 	}
@@ -2622,24 +2644,31 @@
 
 		if (copy_from_user(&comp_ratio, (void __user *)arg,
 				sizeof(struct msm_sde_rotator_comp_ratio)))
-			return -EFAULT;
+			goto ioctl32_error;
 
 		ret = sde_rotator_private_ioctl(file, file->private_data,
 			0, cmd, (void *)&comp_ratio);
 
 		if (copy_to_user((void __user *)arg, &comp_ratio,
 				sizeof(struct msm_sde_rotator_comp_ratio)))
-			return -EFAULT;
+			goto ioctl32_error;
 
 		break;
 	}
 	default:
+		SDEDEV_ERR(ctx->rot_dev->dev, "invalid ioctl32 type:%x\n", cmd);
 		ret = -ENOIOCTLCMD;
 		break;
 
 	}
 
+	mutex_unlock(vdev->lock);
 	return ret;
+
+ioctl32_error:
+	mutex_unlock(vdev->lock);
+	SDEDEV_ERR(ctx->rot_dev->dev, "error handling ioctl32 cmd:%x\n", cmd);
+	return -EFAULT;
 }
 #endif
 
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 8f2746d..1bab010 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -2366,7 +2366,6 @@
 	/* features exposed via mdss h/w version */
 	if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_400)) {
 		SDEROT_DBG("Supporting sys cache inline rotation\n");
-		set_bit(SDE_CAPS_MIN_BUS_VOTE,  mdata->sde_caps_map);
 		set_bit(SDE_CAPS_SBUF_1,  mdata->sde_caps_map);
 		set_bit(SDE_CAPS_UBWC_2,  mdata->sde_caps_map);
 		rot->inpixfmts = sde_hw_rotator_v4_inpixfmts;
@@ -2597,6 +2596,11 @@
 	}
 
 	if ((src_w != dst_w) || (src_h != dst_h)) {
+		if (!dst_w || !dst_h) {
+			SDEROT_DBG("zero output width/height not support\n");
+			ret = -EINVAL;
+			goto dnsc_err;
+		}
 		if ((src_w % dst_w) || (src_h % dst_h)) {
 			SDEROT_DBG("non integral scale not support\n");
 			ret = -EINVAL;
@@ -3078,9 +3082,9 @@
 		goto error_hw_rev_init;
 
 	/* set rotator CBCR to shutoff memory/periphery on clock off.*/
-	clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
+	clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_MDSS_ROT].clk,
 			CLKFLAG_NORETAIN_MEM);
-	clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
+	clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_MDSS_ROT].clk,
 			CLKFLAG_NORETAIN_PERIPH);
 
 	mdata->sde_rot_hw = rot;
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 0fa3262..7215fdf 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -920,6 +920,8 @@
 	pkt->session_id = hash32_ptr(session);
 	pkt->num_properties = 1;
 
+	dprintk(VIDC_DBG, "Setting HAL Property = 0x%x\n", ptype);
+
 	switch (ptype) {
 	case HAL_CONFIG_FRAME_RATE:
 	{
@@ -1115,6 +1117,14 @@
 		pkt->size += sizeof(u32) * 2;
 		break;
 	}
+	case HAL_PARAM_SECURE:
+	{
+		create_pkt_enable(pkt->rg_property_data,
+			  HFI_PROPERTY_PARAM_SECURE_SESSION,
+			  ((struct hal_enable *)pdata)->enable);
+		pkt->size += sizeof(u32) * 2;
+		break;
+	}
 	case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER:
 	{
 		create_pkt_enable(pkt->rg_property_data,
@@ -1265,6 +1275,7 @@
 		hfi->qp_packed = hal_quant->qpi | hal_quant->qpp << 8 |
 			hal_quant->qpb << 16;
 		hfi->layer_id = hal_quant->layer_id;
+		hfi->enable = hal_quant->enable;
 		pkt->size += sizeof(u32) + sizeof(struct hfi_quantization);
 		break;
 	}
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index c82db74..c5c4269 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -135,6 +135,14 @@
 	return msm_vidc_s_ext_ctrl((void *)vidc_inst, a);
 }
 
+int msm_v4l2_g_ext_ctrl(struct file *file, void *fh,
+					struct v4l2_ext_controls *a)
+{
+	struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+
+	return msm_vidc_g_ext_ctrl((void *)vidc_inst, a);
+}
+
 int msm_v4l2_reqbufs(struct file *file, void *fh,
 				struct v4l2_requestbuffers *b)
 {
@@ -250,6 +258,7 @@
 	.vidioc_g_ctrl = msm_v4l2_g_ctrl,
 	.vidioc_queryctrl = msm_v4l2_queryctrl,
 	.vidioc_s_ext_ctrls = msm_v4l2_s_ext_ctrl,
+	.vidioc_g_ext_ctrls = msm_v4l2_g_ext_ctrl,
 	.vidioc_subscribe_event = msm_v4l2_subscribe_event,
 	.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
 	.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 85e721f..a86c677 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -23,7 +23,6 @@
 #define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS MIN_NUM_CAPTURE_BUFFERS
 #define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
 #define MB_SIZE_IN_PIXEL (16 * 16)
-#define MAX_OPERATING_FRAME_RATE (300 << 16)
 #define OPERATING_FRAME_RATE_STEP (1 << 16)
 
 static const char *const mpeg_video_stream_format[] = {
@@ -360,7 +359,7 @@
 		.name = "Set Decoder Operating rate",
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = 0,
-		.maximum = MAX_OPERATING_FRAME_RATE,
+		.maximum = INT_MAX,
 		.default_value = 0,
 		.step = OPERATING_FRAME_RATE_STEP,
 	},
@@ -368,17 +367,6 @@
 
 #define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
 
-static u32 get_frame_size_nv12(int plane,
-					u32 height, u32 width)
-{
-	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
-}
-
-static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
-{
-	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
-}
-
 static u32 get_frame_size_compressed_full_yuv(int plane,
 					u32 max_mbs_per_frame, u32 size_per_mb)
 {
@@ -391,11 +379,6 @@
 	return (max_mbs_per_frame * size_per_mb * 3/2)/2;
 }
 
-static u32 get_frame_size_nv12_ubwc_10bit(int plane, u32 height, u32 width)
-{
-	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
-}
-
 static u32 get_frame_size(struct msm_vidc_inst *inst,
 					const struct msm_vidc_format *fmt,
 					int fmt_type, int plane)
@@ -446,7 +429,7 @@
 		.name = "UBWC YCbCr Semiplanar 4:2:0 10bit",
 		.description = "UBWC Y/CbCr 4:2:0 10bit",
 		.fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC,
-		.get_frame_size = get_frame_size_nv12_ubwc_10bit,
+		.get_frame_size = get_frame_size_tp10_ubwc,
 		.type = CAPTURE_PORT,
 	},
 	{
@@ -681,7 +664,7 @@
 	inst->bufq[OUTPUT_PORT].num_planes = 1;
 	inst->bufq[CAPTURE_PORT].num_planes = 1;
 	inst->prop.fps = DEFAULT_FPS;
-	inst->operating_rate = 0;
+	inst->clk_data.operating_rate = 0;
 	memcpy(&inst->fmts[OUTPUT_PORT], &vdec_formats[2],
 			sizeof(struct msm_vidc_format));
 	memcpy(&inst->fmts[CAPTURE_PORT], &vdec_formats[0],
@@ -778,7 +761,10 @@
 		msm_dcvs_try_enable(inst);
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+		property_id = HAL_PARAM_SECURE;
 		inst->flags |= VIDC_SECURE;
+		property_val = !!(inst->flags & VIDC_SECURE);
+		pdata = &property_val;
 		dprintk(VIDC_DBG, "Setting secure mode to: %d\n",
 				!!(inst->flags & VIDC_SECURE));
 		break;
@@ -965,8 +951,12 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
 		dprintk(VIDC_DBG,
 			"inst(%pK) operating rate changed from %d to %d\n",
-			inst, inst->operating_rate >> 16, ctrl->val >> 16);
-		inst->operating_rate = ctrl->val;
+			inst, inst->clk_data.operating_rate >> 16,
+				ctrl->val >> 16);
+		inst->clk_data.operating_rate = ctrl->val;
+
+		msm_vidc_update_operating_rate(inst);
+
 		break;
 	default:
 		break;
@@ -977,8 +967,8 @@
 
 	if (!rc && property_id) {
 		dprintk(VIDC_DBG,
-			"Control: HAL property=%#x,ctrl: id=%#x,value=%#x\n",
-			property_id, ctrl->id, ctrl->val);
+			"Control: Name = %s, ID = 0x%x Value = %d\n",
+				ctrl->name, ctrl->id, ctrl->val);
 		rc = call_hfi_op(hdev, session_set_property, (void *)
 				inst->session, property_id, pdata);
 	}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index c102687..19a21ab 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -23,7 +23,6 @@
 #define DEFAULT_BIT_RATE 64000
 #define BIT_RATE_STEP 100
 #define DEFAULT_FRAME_RATE 15
-#define MAX_OPERATING_FRAME_RATE (300 << 16)
 #define OPERATING_FRAME_RATE_STEP (1 << 16)
 #define MAX_SLICE_BYTE_SIZE ((MAX_BIT_RATE)>>3)
 #define MIN_SLICE_BYTE_SIZE 512
@@ -286,6 +285,17 @@
 		.qmenu = NULL,
 	},
 	{
+		.id = V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK,
+		.name = "QP mask for diff frame types",
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.minimum = 1,
+		.maximum = 7,
+		.default_value = 7,
+		.step = 1,
+		.menu_skip_mask = 0,
+		.qmenu = NULL,
+	},
+	{
 		.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES,
 		.name = "Intra Period for B frames",
 		.type = V4L2_CTRL_TYPE_INTEGER,
@@ -867,7 +877,7 @@
 		.name = "Set Encoder Operating rate",
 		.type = V4L2_CTRL_TYPE_INTEGER,
 		.minimum = 0,
-		.maximum = MAX_OPERATING_FRAME_RATE,
+		.maximum = INT_MAX,
 		.default_value = 0,
 		.step = OPERATING_FRAME_RATE_STEP,
 	},
@@ -983,26 +993,6 @@
 
 #define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
 
-static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
-{
-	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
-}
-
-static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
-{
-	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
-}
-
-static u32 get_frame_size_rgba(int plane, u32 height, u32 width)
-{
-	return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888, width, height);
-}
-
-static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
-{
-	return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
-}
-
 static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
 {
 	int sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2;
@@ -1060,6 +1050,13 @@
 		.get_frame_size = get_frame_size_nv21,
 		.type = OUTPUT_PORT,
 	},
+	{
+		.name = "TP10 UBWC 4:2:0",
+		.description = "TP10 UBWC 4:2:0",
+		.fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC,
+		.get_frame_size = get_frame_size_tp10_ubwc,
+		.type = OUTPUT_PORT,
+	},
 };
 
 static int msm_venc_set_csc(struct msm_vidc_inst *inst);
@@ -1224,7 +1221,7 @@
 		bitrate.bit_rate = ctrl->val;
 		bitrate.layer_id = 0;
 		pdata = &bitrate;
-		inst->bitrate = ctrl->val;
+		inst->clk_data.bitrate = ctrl->val;
 		break;
 	}
 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
@@ -1501,6 +1498,9 @@
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
 		inst->flags |= VIDC_SECURE;
+		property_id = HAL_PARAM_SECURE;
+		property_val = !!(inst->flags & VIDC_SECURE);
+		pdata = &property_val;
 		dprintk(VIDC_INFO, "Setting secure mode to: %d\n",
 				!!(inst->flags & VIDC_SECURE));
 		break;
@@ -1641,43 +1641,65 @@
 		pdata = &baselayerid;
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP: {
-		struct v4l2_ctrl *qpp, *qpb;
+		struct v4l2_ctrl *qpp, *qpb, *mask;
 
 		property_id = HAL_CONFIG_VENC_FRAME_QP;
 		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP);
 		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP);
+		mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK);
 
 		quant.qpi = ctrl->val;
 		quant.qpp = qpp->val;
 		quant.qpb = qpb->val;
+		quant.enable = mask->val;
 		quant.layer_id = MSM_VIDC_ALL_LAYER_ID;
 		pdata = &quant;
 		break;
 	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP: {
-		struct v4l2_ctrl *qpi, *qpb;
+		struct v4l2_ctrl *qpi, *qpb, *mask;
 
 		property_id = HAL_CONFIG_VENC_FRAME_QP;
 		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP);
 		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP);
+		mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK);
 
 		quant.qpp = ctrl->val;
 		quant.qpi = qpi->val;
 		quant.qpb = qpb->val;
+		quant.enable = mask->val;
 		quant.layer_id = MSM_VIDC_ALL_LAYER_ID;
 		pdata = &quant;
 		break;
 	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP: {
-		struct v4l2_ctrl *qpp, *qpi;
+		struct v4l2_ctrl *qpp, *qpi, *mask;
 
 		property_id = HAL_CONFIG_VENC_FRAME_QP;
 		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP);
 		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP);
+		mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK);
 
 		quant.qpb = ctrl->val;
 		quant.qpp = qpp->val;
 		quant.qpi = qpi->val;
+		quant.enable = mask->val;
+		quant.layer_id = MSM_VIDC_ALL_LAYER_ID;
+		pdata = &quant;
+		break;
+	}
+	case V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK: {
+		struct v4l2_ctrl *qpi, *qpp, *qpb;
+
+		property_id = HAL_CONFIG_VENC_FRAME_QP;
+		qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP);
+		qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP);
+		qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP);
+
+		quant.qpi = qpi->val;
+		quant.qpp = qpp->val;
+		quant.qpb = qpb->val;
+		quant.enable = ctrl->val;
 		quant.layer_id = MSM_VIDC_ALL_LAYER_ID;
 		pdata = &quant;
 		break;
@@ -1711,8 +1733,12 @@
 	case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
 		dprintk(VIDC_DBG,
 			"inst(%pK) operating rate changed from %d to %d\n",
-			inst, inst->operating_rate >> 16, ctrl->val >> 16);
-		inst->operating_rate = ctrl->val;
+			inst, inst->clk_data.operating_rate >> 16,
+				ctrl->val >> 16);
+		inst->clk_data.operating_rate = ctrl->val;
+
+		msm_vidc_update_operating_rate(inst);
+
 		break;
 	case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE:
 	{
@@ -1795,6 +1821,7 @@
 		else
 			enable.enable = 0;
 		pdata = &enable;
+		inst->clk_data.low_latency_mode = (bool) enable.enable;
 		break;
 	}
 	case V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8:
@@ -1832,9 +1859,9 @@
 #undef TRY_GET_CTRL
 
 	if (!rc && property_id) {
-		dprintk(VIDC_DBG, "Control: HAL property=%x,ctrl_value=%d\n",
-				property_id,
-				ctrl->val);
+		dprintk(VIDC_DBG,
+			"Control: Name = %s, ID = 0x%x Value = %d\n",
+				ctrl->name, ctrl->id, ctrl->val);
 		rc = call_hfi_op(hdev, session_set_property,
 				(void *)inst->session, property_id, pdata);
 	}
@@ -1849,7 +1876,7 @@
 	struct v4l2_ext_control *control;
 	struct hfi_device *hdev;
 	struct hal_ltr_mode ltr_mode;
-	u32 property_id = 0, layer_id = MSM_VIDC_ALL_LAYER_ID;
+	u32 property_id = 0;
 	void *pdata = NULL;
 	struct msm_vidc_capability *cap = NULL;
 	struct hal_aspect_ratio sar;
@@ -1927,76 +1954,75 @@
 			pdata = &blur_res;
 			break;
 		case V4L2_CID_MPEG_VIDC_VIDEO_LAYER_ID:
-			layer_id = control[i].value;
+			qp.layer_id = control[i].value;
+			/* Enable QP for all frame types by default */
+			qp.enable = 7;
+			qp_range.layer_id = control[i].value;
 			i++;
 			while (i < ctrl->count) {
 			switch (control[i].id) {
 			case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP:
 				qp.qpi = control[i].value;
-				qp.layer_id = layer_id;
 				property_id =
 					HAL_CONFIG_VENC_FRAME_QP;
 				pdata = &qp;
 				break;
 			case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP:
 				qp.qpp = control[i].value;
-				qp.layer_id = layer_id;
 				property_id =
 					HAL_CONFIG_VENC_FRAME_QP;
 				pdata = &qp;
 				break;
 			case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP:
 				qp.qpb = control[i].value;
-				qp.layer_id = layer_id;
+				property_id =
+					HAL_CONFIG_VENC_FRAME_QP;
+				pdata = &qp;
+				break;
+			case V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK:
+				qp.enable = control[i].value;
 				property_id =
 					HAL_CONFIG_VENC_FRAME_QP;
 				pdata = &qp;
 				break;
 			case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MIN:
 				qp_range.qpi_min = control[i].value;
-				qp_range.layer_id = layer_id;
 				property_id =
 					HAL_PARAM_VENC_SESSION_QP_RANGE;
 				pdata = &qp_range;
 				break;
 			case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MIN:
 				qp_range.qpp_min = control[i].value;
-				qp_range.layer_id = layer_id;
 				property_id =
-				HAL_PARAM_VENC_SESSION_QP_RANGE;
+					HAL_PARAM_VENC_SESSION_QP_RANGE;
 				pdata = &qp_range;
 				break;
 			case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MIN:
 				qp_range.qpb_min = control[i].value;
-				qp_range.layer_id = layer_id;
 				property_id =
 					HAL_PARAM_VENC_SESSION_QP_RANGE;
 				pdata = &qp_range;
 				break;
 			case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MAX:
 				qp_range.qpi_max = control[i].value;
-				qp_range.layer_id = layer_id;
 				property_id =
 					HAL_PARAM_VENC_SESSION_QP_RANGE;
 				pdata = &qp_range;
 				break;
 			case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MAX:
 				qp_range.qpp_max = control[i].value;
-				qp_range.layer_id = layer_id;
 				property_id =
 					HAL_PARAM_VENC_SESSION_QP_RANGE;
 				pdata = &qp_range;
 				break;
 			case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX:
 				qp_range.qpb_max = control[i].value;
-				qp_range.layer_id = layer_id;
 				property_id =
 					HAL_PARAM_VENC_SESSION_QP_RANGE;
 				pdata = &qp_range;
 				break;
 			case V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE:
 				bitrate.bit_rate = control[i].value;
-				bitrate.layer_id = layer_id;
 				property_id =
 					HAL_CONFIG_VENC_TARGET_BITRATE;
 				pdata = &bitrate;
@@ -2048,7 +2074,7 @@
 	/* To start with, both ports are 1 plane each */
 	inst->bufq[OUTPUT_PORT].num_planes = 1;
 	inst->bufq[CAPTURE_PORT].num_planes = 1;
-	inst->operating_rate = 0;
+	inst->clk_data.operating_rate = 0;
 
 	memcpy(&inst->fmts[CAPTURE_PORT], &venc_formats[4],
 			sizeof(struct msm_vidc_format));
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index e071037..576809b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -28,6 +28,8 @@
 
 static int try_get_ctrl(struct msm_vidc_inst *inst,
 	struct v4l2_ctrl *ctrl);
+static int msm_vidc_get_count(struct msm_vidc_inst *inst,
+	struct v4l2_ctrl *ctrl);
 
 static int get_poll_flags(void *instance)
 {
@@ -274,6 +276,40 @@
 }
 EXPORT_SYMBOL(msm_vidc_g_ctrl);
 
+int msm_vidc_g_ext_ctrl(void *instance, struct v4l2_ext_controls *control)
+{
+	struct msm_vidc_inst *inst = instance;
+	struct v4l2_ext_control *ext_control;
+	struct v4l2_ctrl ctrl;
+	int i = 0, rc = 0;
+
+	if (!inst || !control)
+		return -EINVAL;
+
+	ext_control = control->controls;
+
+	for (i = 0; i < control->count; i++) {
+		switch (ext_control[i].id) {
+		case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+		case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+			ctrl.id = ext_control[i].id;
+			ctrl.val = ext_control[i].value;
+
+			msm_vidc_get_count(inst, &ctrl);
+			ext_control->value = ctrl.val;
+			break;
+		default:
+			dprintk(VIDC_ERR,
+				"This control %x is not supported yet\n",
+					ext_control[i].id);
+			rc = -EINVAL;
+			break;
+		}
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_vidc_g_ext_ctrl);
+
 int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *control)
 {
 	struct msm_vidc_inst *inst = instance;
@@ -1187,6 +1223,8 @@
 	buf_count.buffer_type = type;
 	buf_count.buffer_count_actual = act_count;
 	buf_count.buffer_count_min_host = host_count;
+	dprintk(VIDC_DBG, "%s : Act count = %d Host count = %d\n",
+		__func__, act_count, host_count);
 	rc = call_hfi_op(hdev, session_set_property,
 		inst->session, HAL_PARAM_BUFFER_COUNT_ACTUAL, &buf_count);
 	if (rc)
@@ -1433,7 +1471,9 @@
 			"Failed to move inst: %pK to start done state\n", inst);
 		goto fail_start;
 	}
-	msm_dcvs_init(inst);
+
+	msm_clock_data_reset(inst);
+
 	if (msm_comm_get_stream_output_mode(inst) ==
 			HAL_VIDEO_DECODER_SECONDARY) {
 		rc = msm_comm_queue_output_buffers(inst);
@@ -1519,6 +1559,9 @@
 		dprintk(VIDC_ERR,
 			"Failed to move inst: %pK to state %d\n",
 				inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
+
+	msm_clock_data_reset(inst);
+
 	return rc;
 }
 
@@ -1839,33 +1882,52 @@
 static int try_get_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
 {
 	int rc = 0;
-
-	/*
-	 * HACK: unlock the control prior to querying the hardware.  Otherwise
-	 * lower level code that attempts to do g_ctrl() will end up deadlocking
-	 * us.
-	 */
+	struct hal_buffer_requirements *bufreq = NULL;
+	enum hal_buffer buffer_type;
 
 	switch (ctrl->id) {
 
 	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
 	case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
 	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE:
 		ctrl->val = inst->profile;
-	break;
+		break;
 
 	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
 	case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
+	case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL:
 		ctrl->val = inst->level;
-	break;
+		break;
 
 	case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
 		ctrl->val = inst->entropy_mode;
-	break;
+		break;
 
 	case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+		if (inst->in_reconfig)
+			msm_comm_try_get_bufreqs(inst);
+
+		buffer_type = msm_comm_get_hal_output_buffer(inst);
+		bufreq = get_buff_req_buffer(inst,
+			buffer_type);
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+				"Failed to find bufreqs for buffer type = %d\n",
+					buffer_type);
+			return -EINVAL;
+		}
+		ctrl->val = bufreq->buffer_count_min_host;
+		break;
 	case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
-		rc = msm_vidc_get_count(inst, ctrl);
+		bufreq = get_buff_req_buffer(inst, HAL_BUFFER_INPUT);
+		if (!bufreq) {
+			dprintk(VIDC_ERR,
+				"Failed to find bufreqs for buffer type = %d\n",
+					HAL_BUFFER_INPUT);
+			return -EINVAL;
+		}
+		ctrl->val = bufreq->buffer_count_min_host;
 		break;
 	default:
 		/*
@@ -1873,7 +1935,7 @@
 		 * modify ctrl->value
 		 */
 		break;
-}
+	}
 
 	return rc;
 }
@@ -1971,10 +2033,11 @@
 	inst->session_type = session_type;
 	inst->state = MSM_VIDC_CORE_UNINIT_DONE;
 	inst->core = core;
-	inst->freq = 0;
-	inst->core_id = VIDC_CORE_ID_DEFAULT;
+	inst->clk_data.min_freq = 0;
+	inst->clk_data.curr_freq = 0;
+	inst->clk_data.bitrate = 0;
+	inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
 	inst->bit_depth = MSM_VIDC_BIT_DEPTH_8;
-	inst->bitrate = 0;
 	inst->pic_struct = MSM_VIDC_PIC_STRUCT_PROGRESSIVE;
 	inst->colour_space = MSM_VIDC_BT601_6_525;
 	inst->profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
@@ -2031,12 +2094,15 @@
 		goto fail_init;
 	}
 
+	msm_dcvs_try_enable(inst);
 	if (msm_vidc_check_for_inst_overload(core)) {
 		dprintk(VIDC_ERR,
 			"Instance count reached Max limit, rejecting session");
 		goto fail_init;
 	}
 
+	msm_comm_scale_clocks_and_bus(inst);
+
 	inst->debugfs_root =
 		msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index d43ae5a..cd518fb 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -23,17 +23,12 @@
 	struct msm_vidc_inst *inst = NULL;
 	struct vidc_bus_vote_data *vote_data = NULL;
 
-	if (!core) {
+	if (!core || !core->device) {
 		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, core);
 		return -EINVAL;
 	}
 
 	hdev = core->device;
-	if (!hdev) {
-		dprintk(VIDC_ERR, "%s Invalid device handle: %pK\n",
-				__func__, hdev);
-		return -EINVAL;
-	}
 
 	mutex_lock(&core->lock);
 	list_for_each_entry(inst, &core->instances, list)
@@ -65,12 +60,17 @@
 		vote_data[i].height = max(inst->prop.height[CAPTURE_PORT],
 				inst->prop.height[OUTPUT_PORT]);
 
-		if (inst->operating_rate)
-			vote_data[i].fps = (inst->operating_rate >> 16) ?
-				inst->operating_rate >> 16 : 1;
+		if (inst->clk_data.operating_rate)
+			vote_data[i].fps =
+				(inst->clk_data.operating_rate >> 16) ?
+				inst->clk_data.operating_rate >> 16 : 1;
 		else
 			vote_data[i].fps = inst->prop.fps;
 
+		if (!msm_vidc_clock_scaling ||
+			inst->clk_data.buffer_counter < DCVS_FTB_WINDOW)
+			vote_data[i].power_mode = VIDC_POWER_TURBO;
+
 		/*
 		 * TODO: support for OBP-DBP split mode hasn't been yet
 		 * implemented, once it is, this part of code needs to be
@@ -126,18 +126,19 @@
 	int buffers_outside_fw = 0;
 	struct msm_vidc_core *core;
 	struct hal_buffer_requirements *output_buf_req;
-	struct dcvs_stats *dcvs;
+	struct clock_data *dcvs;
 
 	if (!inst || !inst->core || !inst->core->device) {
 		dprintk(VIDC_ERR, "%s Invalid params\n", __func__);
 		return -EINVAL;
 	}
-	if (!inst->dcvs_mode) {
+
+	if (!inst->clk_data.dcvs_mode) {
 		dprintk(VIDC_DBG, "DCVS is not enabled\n");
 		return 0;
 	}
 
-	dcvs = &inst->dcvs;
+	dcvs = &inst->clk_data;
 
 	core = inst->core;
 	mutex_lock(&inst->lock);
@@ -210,7 +211,7 @@
 	}
 	mutex_unlock(&inst->freqs.lock);
 
-	inst->dcvs.buffer_counter++;
+	inst->clk_data.buffer_counter++;
 }
 
 
@@ -227,12 +228,13 @@
 
 	/* If current requirement is within DCVS limits, try DCVS. */
 
-	if (freq < inst->dcvs.load_high) {
+	if (freq < inst->clk_data.load_high) {
 		dprintk(VIDC_DBG, "Calling DCVS now\n");
 		// TODO calling DCVS here may reduce the residency. Re-visit.
 		msm_dcvs_scale_clocks(inst);
-		freq = inst->dcvs.load;
+		freq = inst->clk_data.load;
 	}
+	dprintk(VIDC_PROF, "%s Inst %pK : Freq = %lu\n", __func__, inst, freq);
 
 	return freq;
 }
@@ -274,9 +276,10 @@
 	unsigned long freq = 0;
 	unsigned long vpp_cycles = 0, vsp_cycles = 0;
 	u32 vpp_cycles_per_mb;
-	u32 mbs_per_frame;
+	u32 mbs_per_second;
 
-	mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+	mbs_per_second = msm_comm_get_inst_load(inst,
+		LOAD_CALC_NO_QUIRKS);
 
 	/*
 	 * Calculate vpp, vsp cycles separately for encoder and decoder.
@@ -286,17 +289,17 @@
 
 	if (inst->session_type == MSM_VIDC_ENCODER) {
 		vpp_cycles_per_mb = inst->flags & VIDC_LOW_POWER ?
-			inst->entry->low_power_cycles :
-			inst->entry->vpp_cycles;
+			inst->clk_data.entry->low_power_cycles :
+			inst->clk_data.entry->vpp_cycles;
 
-		vsp_cycles = mbs_per_frame * inst->entry->vsp_cycles;
+		vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
 
 		/* 10 / 7 is overhead factor */
-		vsp_cycles += (inst->bitrate * 10) / 7;
+		vsp_cycles += (inst->clk_data.bitrate * 10) / 7;
 	} else if (inst->session_type == MSM_VIDC_DECODER) {
-		vpp_cycles = mbs_per_frame * inst->entry->vpp_cycles;
+		vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles;
 
-		vsp_cycles = mbs_per_frame * inst->entry->vsp_cycles;
+		vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
 		/* 10 / 7 is overhead factor */
 		vsp_cycles += (inst->prop.fps * filled_len * 8 * 10) / 7;
 
@@ -306,6 +309,8 @@
 		return freq;
 	}
 
+	dprintk(VIDC_PROF, "%s Inst %pK : Freq = %lu\n", __func__, inst, freq);
+
 	freq = max(vpp_cycles, vsp_cycles);
 
 	return freq;
@@ -321,7 +326,7 @@
 
 	hdev = core->device;
 	allowed_clks_tbl = core->resources.allowed_clks_tbl;
-	if (!hdev || !allowed_clks_tbl) {
+	if (!allowed_clks_tbl) {
 		dprintk(VIDC_ERR,
 			"%s Invalid parameters\n", __func__);
 		return -EINVAL;
@@ -329,35 +334,104 @@
 
 	mutex_lock(&core->lock);
 	list_for_each_entry(temp, &core->instances, list) {
-		freq += temp->freq;
+		freq += temp->clk_data.curr_freq;
 	}
 	for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) {
 		rate = allowed_clks_tbl[i].clock_rate;
 		if (rate >= freq)
 			break;
 	}
+	core->min_freq = freq;
+	core->curr_freq = rate;
 	mutex_unlock(&core->lock);
 
-	core->freq = rate;
-	dprintk(VIDC_PROF, "Voting for freq = %lu", freq);
+	dprintk(VIDC_PROF, "Min freq = %lu Current Freq = %lu\n",
+		core->min_freq, core->curr_freq);
 	rc = call_hfi_op(hdev, scale_clocks,
-			hdev->hfi_device_data, rate);
+			hdev->hfi_device_data, core->curr_freq);
 
 	return rc;
 }
 
-static unsigned long msm_vidc_max_freq(struct msm_vidc_inst *inst)
+static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core)
 {
 	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
 	unsigned long freq = 0;
 
-	allowed_clks_tbl = inst->core->resources.allowed_clks_tbl;
+	allowed_clks_tbl = core->resources.allowed_clks_tbl;
 	freq = allowed_clks_tbl[0].clock_rate;
 	dprintk(VIDC_PROF, "Max rate = %lu", freq);
 
 	return freq;
 }
 
+int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst)
+{
+	struct v4l2_ctrl *ctrl = NULL;
+	struct msm_vidc_inst *temp;
+	struct msm_vidc_core *core;
+	unsigned long max_freq, freq_left, ops_left, load, cycles, freq = 0;
+	unsigned long mbs_per_frame;
+
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid args\n", __func__);
+		return -EINVAL;
+	}
+	core = inst->core;
+
+	mutex_lock(&core->lock);
+	max_freq = msm_vidc_max_freq(core);
+	list_for_each_entry(temp, &core->instances, list) {
+		if (temp == inst ||
+				temp->state < MSM_VIDC_START_DONE ||
+				temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)
+			continue;
+
+		freq += temp->clk_data.min_freq;
+	}
+
+	freq_left = max_freq - freq;
+
+	list_for_each_entry(temp, &core->instances, list) {
+
+		mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+		cycles = temp->clk_data.entry->vpp_cycles;
+		if (inst->session_type == MSM_VIDC_ENCODER)
+			cycles = temp->flags & VIDC_LOW_POWER ?
+				inst->clk_data.entry->low_power_cycles :
+				cycles;
+
+		load = cycles * mbs_per_frame;
+
+		ops_left = load ? (freq_left / load) : 0;
+		/* Convert remaining operating rate to Q16 format */
+		ops_left = ops_left << 16;
+
+		ctrl = v4l2_ctrl_find(&temp->ctrl_handler,
+			V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE);
+		if (ctrl) {
+			dprintk(VIDC_DBG,
+				"%s: Before Range = %lld --> %lld\n",
+				ctrl->name, ctrl->minimum, ctrl->maximum);
+			dprintk(VIDC_DBG,
+				"%s: Before Def value = %lld Cur val = %d\n",
+				ctrl->name, ctrl->default_value, ctrl->val);
+			v4l2_ctrl_modify_range(ctrl, ctrl->minimum,
+				ctrl->val + ops_left, ctrl->step,
+				ctrl->minimum);
+			dprintk(VIDC_DBG,
+				"%s: Updated Range = %lld --> %lld\n",
+				ctrl->name, ctrl->minimum, ctrl->maximum);
+			dprintk(VIDC_DBG,
+				"%s: Updated Def value = %lld Cur val = %d\n",
+				ctrl->name, ctrl->default_value, ctrl->val);
+		}
+	}
+	mutex_unlock(&core->lock);
+
+	return 0;
+}
+
 int msm_comm_scale_clocks(struct msm_vidc_inst *inst)
 {
 	struct vb2_buf_entry *temp, *next;
@@ -365,9 +439,10 @@
 	u32 filled_len = 0;
 	ion_phys_addr_t device_addr = 0;
 
-	if (inst->dcvs.buffer_counter < DCVS_FTB_WINDOW) {
-		freq = msm_vidc_max_freq(inst);
-		goto decision_done;
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
+			__func__, inst);
+		return -EINVAL;
 	}
 
 	mutex_lock(&inst->pendingq.lock);
@@ -381,7 +456,7 @@
 	mutex_unlock(&inst->pendingq.lock);
 
 	if (!filled_len || !device_addr) {
-		freq = inst->freq;
+		dprintk(VIDC_PROF, "No Change in frequency\n");
 		goto decision_done;
 	}
 
@@ -391,8 +466,15 @@
 
 	freq = msm_vidc_adjust_freq(inst);
 
+	inst->clk_data.min_freq = freq;
+
+	if (inst->clk_data.buffer_counter < DCVS_FTB_WINDOW ||
+		!msm_vidc_clock_scaling)
+		inst->clk_data.curr_freq = msm_vidc_max_freq(inst->core);
+	else
+		inst->clk_data.curr_freq = freq;
+
 decision_done:
-	inst->freq = freq;
 	msm_vidc_set_clocks(inst->core);
 	return 0;
 }
@@ -422,29 +504,29 @@
 
 int msm_dcvs_try_enable(struct msm_vidc_inst *inst)
 {
-	bool force_disable = false;
-
 	if (!inst) {
 		dprintk(VIDC_ERR, "%s: Invalid args: %p\n", __func__, inst);
 		return -EINVAL;
 	}
 
-	force_disable = inst->session_type == MSM_VIDC_ENCODER ?
-		!msm_vidc_enc_dcvs_mode :
-		!msm_vidc_dec_dcvs_mode;
-
-	if (force_disable || inst->flags & VIDC_THUMBNAIL) {
-		dprintk(VIDC_PROF, "Thumbnail sessions don't need DCVS : %pK\n",
-			inst);
-		inst->dcvs.extra_capture_buffer_count = 0;
-		inst->dcvs.extra_output_buffer_count = 0;
+	if (!msm_vidc_clock_scaling ||
+			inst->flags & VIDC_THUMBNAIL ||
+			inst->clk_data.low_latency_mode) {
+		dprintk(VIDC_PROF,
+			"This session doesn't need DCVS : %pK\n",
+				inst);
+		inst->clk_data.extra_capture_buffer_count = 0;
+		inst->clk_data.extra_output_buffer_count = 0;
+		inst->clk_data.dcvs_mode = false;
 		return false;
 	}
-	inst->dcvs_mode = true;
+	inst->clk_data.dcvs_mode = true;
 
 	// TODO : Update with proper number based on on-target tuning.
-	inst->dcvs.extra_capture_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
-	inst->dcvs.extra_output_buffer_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
+	inst->clk_data.extra_capture_buffer_count =
+		DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
+	inst->clk_data.extra_output_buffer_count =
+		DCVS_DEC_EXTRA_OUTPUT_BUFFERS;
 	return true;
 }
 
@@ -482,6 +564,12 @@
 	struct clock_profile_entry *entry = NULL;
 	int fourcc;
 
+	if (!inst || !inst->core) {
+		dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
+			__func__, inst);
+		return -EINVAL;
+	}
+
 	clk_freq_tbl = &inst->core->resources.clock_freq_tbl;
 	fourcc = inst->session_type == MSM_VIDC_DECODER ?
 		inst->fmts[OUTPUT_PORT].fourcc :
@@ -498,7 +586,7 @@
 				inst->session_type);
 
 		if (matched) {
-			inst->entry = entry;
+			inst->clk_data.entry = entry;
 			break;
 		}
 	}
@@ -512,7 +600,7 @@
 	return rc;
 }
 
-static inline void msm_dcvs_print_dcvs_stats(struct dcvs_stats *dcvs)
+static inline void msm_dcvs_print_dcvs_stats(struct clock_data *dcvs)
 {
 	dprintk(VIDC_DBG,
 		"DCVS: Load_Low %d, Load High %d\n",
@@ -524,31 +612,31 @@
 		dcvs->min_threshold, dcvs->max_threshold);
 }
 
-void msm_dcvs_init(struct msm_vidc_inst *inst)
+void msm_clock_data_reset(struct msm_vidc_inst *inst)
 {
 	struct msm_vidc_core *core;
-	int i = 0;
+	int i = 0, rc = 0;
 	struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
 	u64 total_freq = 0, rate = 0, load;
 	int cycles;
-	struct dcvs_stats *dcvs;
+	struct clock_data *dcvs;
 
 	dprintk(VIDC_DBG, "Init DCVS Load\n");
 
 	if (!inst || !inst->core) {
-		dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, inst);
+		dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n",
+			__func__, inst);
 		return;
 	}
 
 	core = inst->core;
-	dcvs = &inst->dcvs;
-	inst->dcvs = (struct dcvs_stats){0};
+	dcvs = &inst->clk_data;
 	load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS);
-	cycles = inst->entry->vpp_cycles;
+	cycles = inst->clk_data.entry->vpp_cycles;
 	allowed_clks_tbl = core->resources.allowed_clks_tbl;
 	if (inst->session_type == MSM_VIDC_ENCODER) {
 		cycles = inst->flags & VIDC_LOW_POWER ?
-			inst->entry->low_power_cycles :
+			inst->clk_data.entry->low_power_cycles :
 			cycles;
 
 		dcvs->buffer_type = HAL_BUFFER_INPUT;
@@ -573,7 +661,17 @@
 	dcvs->load = dcvs->load_high = rate;
 	dcvs->load_low = allowed_clks_tbl[i+1].clock_rate;
 
+	inst->clk_data.buffer_counter = 0;
+
 	msm_dcvs_print_dcvs_stats(dcvs);
+
+	msm_vidc_update_operating_rate(inst);
+
+	rc = msm_comm_scale_clocks_and_bus(inst);
+
+	if (rc)
+		dprintk(VIDC_ERR, "%s Failed to scale Clocks and Bus\n",
+			__func__);
 }
 
 int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst,
@@ -585,23 +683,26 @@
 	}
 
 	return buffer_type == HAL_BUFFER_INPUT ?
-		inst->dcvs.extra_output_buffer_count :
-		inst->dcvs.extra_capture_buffer_count;
+		inst->clk_data.extra_output_buffer_count :
+		inst->clk_data.extra_capture_buffer_count;
 }
 
 int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst)
 {
 	int rc = 0;
-	bool low_latency_mode;
 	struct hfi_device *hdev;
 	struct hal_video_work_mode pdata;
 	struct hal_enable latency;
 
-	hdev = inst->core->device;
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR,
+			"%s Invalid args: Inst = %pK\n",
+			__func__, inst);
+		return -EINVAL;
+	}
 
-	low_latency_mode = msm_comm_g_ctrl_for_id(inst,
-			V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE);
-	if (low_latency_mode) {
+	hdev = inst->core->device;
+	if (inst->clk_data.low_latency_mode) {
 		pdata.video_work_mode = VIDC_WORK_MODE_1;
 		goto decision_done;
 	}
@@ -636,7 +737,7 @@
 
 decision_done:
 
-	inst->work_mode = pdata.video_work_mode;
+	inst->clk_data.work_mode = pdata.video_work_mode;
 	rc = call_hfi_op(hdev, session_set_property,
 			(void *)inst->session, HAL_PARAM_VIDEO_WORK_MODE,
 			(void *)&pdata);
@@ -646,7 +747,8 @@
 
 	/* For WORK_MODE_1, set Low Latency mode by default to HW. */
 
-	if (inst->work_mode == VIDC_WORK_MODE_1) {
+	if (inst->session_type == MSM_VIDC_ENCODER &&
+			inst->clk_data.work_mode == VIDC_WORK_MODE_1) {
 		latency.enable = 1;
 		rc = call_hfi_op(hdev, session_set_property,
 			(void *)inst->session, HAL_PARAM_VENC_LOW_LATENCY,
@@ -675,8 +777,8 @@
 		return 0;
 	}
 	mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
-	if (inst->core->resources.max_hq_mbs_per_frame > mbs_per_frame ||
-		inst->core->resources.max_hq_fps > inst->prop.fps) {
+	if (mbs_per_frame >= inst->core->resources.max_hq_mbs_per_frame ||
+		inst->prop.fps >= inst->core->resources.max_hq_fps) {
 		enable = true;
 	}
 
@@ -692,9 +794,12 @@
 			__func__, inst);
 		goto fail_power_mode_set;
 	}
-	inst->flags |= VIDC_LOW_POWER;
-	dprintk(VIDC_PROF, "Power Save Mode set for inst: %pK\n", inst);
+	inst->flags = enable ?
+		inst->flags | VIDC_LOW_POWER :
+		inst->flags & ~VIDC_LOW_POWER;
 
+	dprintk(VIDC_PROF,
+		"Power Save Mode for inst: %pK Enable = %d\n", inst, enable);
 fail_power_mode_set:
 	return rc;
 }
@@ -704,15 +809,10 @@
 {
 	struct msm_vidc_inst *inst = NULL;
 
-	if (!core) {
-		dprintk(VIDC_ERR, "Invalid args: %pK\n", core);
-		return -EINVAL;
-	}
-
 	dprintk(VIDC_PROF, "Core %d : Moving all inst to LP mode\n", core_id);
 	mutex_lock(&core->lock);
 	list_for_each_entry(inst, &core->instances, list) {
-		if (inst->core_id == core_id &&
+		if (inst->clk_data.core_id == core_id &&
 			inst->session_type == MSM_VIDC_ENCODER)
 			msm_vidc_power_save_mode_enable(inst, true);
 	}
@@ -731,19 +831,19 @@
 	list_for_each_entry(inst, &core->instances, list) {
 		u32 cycles, lp_cycles;
 
-		if (!inst->core_id && core_id)
+		if (!(inst->clk_data.core_id && core_id))
 			continue;
 		if (inst->session_type == MSM_VIDC_DECODER) {
-			cycles = lp_cycles = inst->entry->vpp_cycles;
+			cycles = lp_cycles = inst->clk_data.entry->vpp_cycles;
 		} else if (inst->session_type == MSM_VIDC_ENCODER) {
 			lp_mode |= inst->flags & VIDC_LOW_POWER;
 			cycles = lp_mode ?
-				inst->entry->low_power_cycles :
-				inst->entry->vpp_cycles;
+				inst->clk_data.entry->low_power_cycles :
+				inst->clk_data.entry->vpp_cycles;
 		} else {
 			continue;
 		}
-		if (inst->core_id == 3)
+		if (inst->clk_data.core_id == 3)
 			cycles = cycles / 2;
 
 		current_inst_mbs_per_sec = msm_comm_get_inst_load(inst,
@@ -768,10 +868,17 @@
 		min_load = 0, min_lp_load = 0;
 	u32 min_core_id, min_lp_core_id;
 
+	if (!inst || !inst->core || !inst->core->device) {
+		dprintk(VIDC_ERR,
+			"%s Invalid args: Inst = %pK\n",
+			__func__, inst);
+		return -EINVAL;
+	}
+
 	core = inst->core;
 	hdev = core->device;
-	max_freq = msm_vidc_max_freq(inst);
-	inst->core_id = 0;
+	max_freq = msm_vidc_max_freq(inst->core);
+	inst->clk_data.core_id = 0;
 
 	core0_load = get_core_load(core, VIDC_CORE_ID_1, false);
 	core1_load = get_core_load(core, VIDC_CORE_ID_2, false);
@@ -786,11 +893,11 @@
 		VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
 
 	lp_cycles = inst->session_type == MSM_VIDC_ENCODER ?
-			inst->entry->low_power_cycles :
-			inst->entry->vpp_cycles;
+			inst->clk_data.entry->low_power_cycles :
+			inst->clk_data.entry->vpp_cycles;
 
 	current_inst_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS) *
-		inst->entry->vpp_cycles;
+		inst->clk_data.entry->vpp_cycles;
 
 	current_inst_lp_load = msm_comm_get_inst_load(inst,
 		LOAD_CALC_NO_QUIRKS) * lp_cycles;
@@ -814,7 +921,7 @@
 	if (inst->session_type == MSM_VIDC_ENCODER && hier_mode) {
 		if (current_inst_load / 2 + core0_load <= max_freq &&
 			current_inst_load / 2 + core1_load <= max_freq) {
-			inst->core_id = VIDC_CORE_ID_3;
+			inst->clk_data.core_id = VIDC_CORE_ID_3;
 			msm_vidc_power_save_mode_enable(inst, false);
 			goto decision_done;
 		}
@@ -825,32 +932,32 @@
 				core0_lp_load <= max_freq &&
 			current_inst_lp_load / 2 +
 				core1_lp_load <= max_freq) {
-			inst->core_id = VIDC_CORE_ID_3;
+			inst->clk_data.core_id = VIDC_CORE_ID_3;
 			msm_vidc_power_save_mode_enable(inst, true);
 			goto decision_done;
 		}
 	}
 
 	if (current_inst_load + min_load < max_freq) {
-		inst->core_id = min_core_id;
+		inst->clk_data.core_id = min_core_id;
 		dprintk(VIDC_DBG,
 			"Selected normally : Core ID = %d\n",
-				inst->core_id);
+				inst->clk_data.core_id);
 		msm_vidc_power_save_mode_enable(inst, false);
 	} else if (current_inst_lp_load + min_load < max_freq) {
 		/* Move current instance to LP and return */
-		inst->core_id = min_core_id;
+		inst->clk_data.core_id = min_core_id;
 		dprintk(VIDC_DBG,
 			"Selected by moving current to LP : Core ID = %d\n",
-				inst->core_id);
+				inst->clk_data.core_id);
 		msm_vidc_power_save_mode_enable(inst, true);
 
 	} else if (current_inst_lp_load + min_lp_load < max_freq) {
 		/* Move all instances to LP mode and return */
-		inst->core_id = min_lp_core_id;
+		inst->clk_data.core_id = min_lp_core_id;
 		dprintk(VIDC_DBG,
 			"Moved all inst's to LP: Core ID = %d\n",
-				inst->core_id);
+				inst->clk_data.core_id);
 		msm_vidc_move_core_to_power_save_mode(core, min_lp_core_id);
 	} else {
 		rc = -EINVAL;
@@ -860,7 +967,7 @@
 	}
 
 decision_done:
-	core_info.video_core_enable_mask = inst->core_id;
+	core_info.video_core_enable_mask = inst->clk_data.core_id;
 
 	rc = call_hfi_op(hdev, session_set_property,
 			(void *)inst->session,
@@ -874,3 +981,4 @@
 	return rc;
 }
 
+
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index d01f074..fe4822b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -31,7 +31,8 @@
 /* Considering one safeguard buffer */
 #define DCVS_BUFFER_SAFEGUARD (DCVS_DEC_EXTRA_OUTPUT_BUFFERS - 1)
 
-void msm_dcvs_init(struct msm_vidc_inst *inst);
+void msm_clock_data_reset(struct msm_vidc_inst *inst);
+int msm_vidc_update_operating_rate(struct msm_vidc_inst *inst);
 int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst,
 	enum hal_buffer buffer_type);
 int msm_dcvs_try_enable(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 853edf5..0efe93b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -584,9 +584,9 @@
 	capture_port_mbs = NUM_MBS_PER_FRAME(inst->prop.width[CAPTURE_PORT],
 		inst->prop.height[CAPTURE_PORT]);
 
-	if (inst->operating_rate) {
-		fps = (inst->operating_rate >> 16) ?
-			inst->operating_rate >> 16 : 1;
+	if (inst->clk_data.operating_rate) {
+		fps = (inst->clk_data.operating_rate >> 16) ?
+			inst->clk_data.operating_rate >> 16 : 1;
 		/*
 		 * Check if operating rate is less than fps.
 		 * If Yes, then use fps to scale clocks
@@ -2510,7 +2510,7 @@
 	}
 
 	tl = msm_comm_vidc_thermal_level(vidc_driver->thermal_level);
-	freq = core->freq;
+	freq = core->curr_freq;
 
 	is_turbo = is_core_turbo(core, freq);
 	dprintk(VIDC_DBG,
@@ -4094,9 +4094,8 @@
 	dprintk(VIDC_DBG, "%15s %8s %8s %8s %8s\n",
 		"buffer type", "count", "mincount_host", "mincount_fw", "size");
 	for (i = 0; i < HAL_BUFFER_MAX; i++) {
-		struct hal_buffer_requirements req = hprop.buf_req.buffer[i];
+		struct hal_buffer_requirements req = inst->buff_req.buffer[i];
 
-		inst->buff_req.buffer[i] = req;
 		if (req.buffer_type != HAL_BUFFER_NONE) {
 			dprintk(VIDC_DBG, "%15s %8d %8d %8d %8d\n",
 				get_buffer_name(req.buffer_type),
@@ -4738,9 +4737,9 @@
 		return 0;
 	}
 
-	// Finish FLUSH As Soon As Possible.
-	inst->dcvs.buffer_counter = 0;
-	msm_comm_scale_clocks_and_bus(inst);
+	/* Finish FLUSH As Soon As Possible. */
+
+	msm_clock_data_reset(inst);
 
 	msm_comm_flush_dynamic_buffers(inst);
 
@@ -5474,7 +5473,7 @@
 	}
 	core = inst->core;
 
-	dprintk(VIDC_ERR, "Venus core frequency = %lu", core->freq);
+	dprintk(VIDC_ERR, "Venus core frequency = %lu", core->curr_freq);
 	mutex_lock(&core->lock);
 	dprintk(VIDC_ERR, "Printing instance info that caused Error\n");
 	msm_comm_print_inst_info(inst);
@@ -5520,3 +5519,28 @@
 	mutex_unlock(&inst->lock);
 	return rc;
 }
+
+u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+}
+
+u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
+}
+
+u32 get_frame_size_rgba(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888, width, height);
+}
+
+u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height);
+}
+
+u32 get_frame_size_tp10_ubwc(int plane, u32 height, u32 width)
+{
+	return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index 9c7eec5..098063d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -98,4 +98,9 @@
 int msm_comm_v4l2_to_hal(int id, int value);
 int msm_comm_hal_to_v4l2(int id, int value);
 int msm_comm_session_continue(void *instance);
+u32 get_frame_size_nv12(int plane, u32 height, u32 width);
+u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width);
+u32 get_frame_size_rgba(int plane, u32 height, u32 width);
+u32 get_frame_size_nv21(int plane, u32 height, u32 width);
+u32 get_frame_size_tp10_ubwc(int plane, u32 height, u32 width);
 #endif
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 15ee8a8..f62c132 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -26,12 +26,10 @@
 int msm_vidc_fw_low_power_mode = 1;
 int msm_vidc_hw_rsp_timeout = 2000;
 bool msm_vidc_fw_coverage = !true;
-bool msm_vidc_dec_dcvs_mode = true;
-bool msm_vidc_enc_dcvs_mode = true;
 bool msm_vidc_sys_idle_indicator = !true;
 int msm_vidc_firmware_unload_delay = 15000;
 bool msm_vidc_thermal_mitigation_disabled = !true;
-bool msm_vidc_bitrate_clock_scaling = true;
+bool msm_vidc_clock_scaling = true;
 bool msm_vidc_debug_timeout = !true;
 
 #define MAX_DBG_BUF_SIZE 4096
@@ -174,8 +172,6 @@
 	__debugfs_create(x32, "fw_level", &msm_vidc_fw_debug) &&
 	__debugfs_create(u32, "fw_debug_mode", &msm_vidc_fw_debug_mode) &&
 	__debugfs_create(bool, "fw_coverage", &msm_vidc_fw_coverage) &&
-	__debugfs_create(bool, "dcvs_dec_mode", &msm_vidc_dec_dcvs_mode) &&
-	__debugfs_create(bool, "dcvs_enc_mode", &msm_vidc_enc_dcvs_mode) &&
 	__debugfs_create(u32, "fw_low_power_mode",
 			&msm_vidc_fw_low_power_mode) &&
 	__debugfs_create(u32, "debug_output", &msm_vidc_debug_out) &&
@@ -186,8 +182,8 @@
 			&msm_vidc_firmware_unload_delay) &&
 	__debugfs_create(bool, "disable_thermal_mitigation",
 			&msm_vidc_thermal_mitigation_disabled) &&
-	__debugfs_create(bool, "bitrate_clock_scaling",
-			&msm_vidc_bitrate_clock_scaling) &&
+	__debugfs_create(bool, "clock_scaling",
+			&msm_vidc_clock_scaling) &&
 	__debugfs_create(bool, "debug_timeout",
 			&msm_vidc_debug_timeout);
 
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index cf5ce22..f5c8e5a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -59,12 +59,10 @@
 extern int msm_vidc_fw_low_power_mode;
 extern int msm_vidc_hw_rsp_timeout;
 extern bool msm_vidc_fw_coverage;
-extern bool msm_vidc_dec_dcvs_mode;
-extern bool msm_vidc_enc_dcvs_mode;
 extern bool msm_vidc_sys_idle_indicator;
 extern int msm_vidc_firmware_unload_delay;
 extern bool msm_vidc_thermal_mitigation_disabled;
-extern bool msm_vidc_bitrate_clock_scaling;
+extern bool msm_vidc_clock_scaling;
 extern bool msm_vidc_debug_timeout;
 
 #define VIDC_MSG_PRIO2STRING(__level) ({ \
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 53bc068..37bccbd 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -52,7 +52,7 @@
 
 
 /* Maintains the number of FTB's between each FBD over a window */
-#define DCVS_FTB_WINDOW 32
+#define DCVS_FTB_WINDOW 16
 
 #define V4L2_EVENT_VIDC_BASE  10
 
@@ -205,7 +205,7 @@
 	int ebd;
 };
 
-struct dcvs_stats {
+struct clock_data {
 	int buffer_counter;
 	int load;
 	int load_low;
@@ -215,6 +215,15 @@
 	unsigned int extra_capture_buffer_count;
 	unsigned int extra_output_buffer_count;
 	enum hal_buffer buffer_type;
+	bool dcvs_mode;
+	unsigned long bitrate;
+	unsigned long min_freq;
+	unsigned long curr_freq;
+	u32 operating_rate;
+	struct clock_profile_entry *entry;
+	u32 core_id;
+	enum hal_work_mode work_mode;
+	bool low_latency_mode;
 };
 
 struct profile_data {
@@ -259,7 +268,8 @@
 	struct msm_vidc_capability *capabilities;
 	struct delayed_work fw_unload_work;
 	bool smmu_fault_handled;
-	unsigned long freq;
+	unsigned long min_freq;
+	unsigned long curr_freq;
 };
 
 struct msm_vidc_inst {
@@ -293,28 +303,21 @@
 	void *priv;
 	struct msm_vidc_debug debug;
 	struct buf_count count;
-	struct dcvs_stats dcvs;
+	struct clock_data clk_data;
 	enum msm_vidc_modes flags;
 	struct msm_vidc_capability capability;
 	u32 buffer_size_limit;
 	enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
 	struct v4l2_ctrl **ctrls;
-	bool dcvs_mode;
 	enum msm_vidc_pixel_depth bit_depth;
 	struct kref kref;
-	unsigned long bitrate;
-	unsigned long freq;
 	u32 buffers_held_in_driver;
 	atomic_t in_flush;
 	u32 pic_struct;
 	u32 colour_space;
-	u32 operating_rate;
 	u32 profile;
 	u32 level;
 	u32 entropy_mode;
-	struct clock_profile_entry *entry;
-	u32 core_id;
-	enum hal_work_mode work_mode;
 };
 
 extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index b0beeec..8752378 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -223,6 +223,7 @@
 	HAL_PARAM_VENC_IFRAMESIZE_TYPE,
 	HAL_PARAM_VIDEO_CORES_USAGE,
 	HAL_PARAM_VIDEO_WORK_MODE,
+	HAL_PARAM_SECURE,
 };
 
 enum hal_domain {
@@ -594,6 +595,7 @@
 	u32 qpp;
 	u32 qpb;
 	u32 layer_id;
+	u32 enable;
 };
 
 struct hal_quantization_range {
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 04d7d01..77164be 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -218,6 +218,8 @@
 	(HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
 #define  HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED	    \
 	(HFI_PROPERTY_PARAM_COMMON_START + 0x010)
+#define  HFI_PROPERTY_PARAM_SECURE_SESSION		\
+	(HFI_PROPERTY_PARAM_COMMON_START + 0x011)
 #define  HFI_PROPERTY_PARAM_WORK_MODE                       \
 	(HFI_PROPERTY_PARAM_COMMON_START + 0x015)
 
@@ -534,7 +536,8 @@
 struct hfi_quantization {
 	u32 qp_packed;
 	u32 layer_id;
-	u32 reserved[4];
+	u32 enable;
+	u32 reserved[3];
 };
 
 struct hfi_quantization_range {
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index bacecbd..f37d64c 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -45,27 +45,36 @@
 	compat_caddr_t		bitmap;
 };
 
-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+static int get_v4l2_window32(struct v4l2_window __user *kp,
+			struct v4l2_window32 __user *up)
 {
+	u32 clipcount = 0;
+
 	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
-		copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
-		get_user(kp->field, &up->field) ||
-		get_user(kp->chromakey, &up->chromakey) ||
-		get_user(kp->clipcount, &up->clipcount))
+		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_window)) ||
+		copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
+		copy_in_user(&kp->field, &up->field, sizeof(up->field)) ||
+		copy_in_user(&kp->chromakey, &up->chromakey,
+			sizeof(up->chromakey)) ||
+		copy_in_user(&kp->clipcount, &up->clipcount,
+			sizeof(up->clipcount)))
 			return -EFAULT;
-	if (kp->clipcount > 2048)
+	if (get_user(clipcount, &kp->clipcount))
+		return -EFAULT;
+	if (clipcount > 2048)
 		return -EINVAL;
-	if (kp->clipcount) {
+	if (clipcount) {
 		struct v4l2_clip32 __user *uclips;
 		struct v4l2_clip __user *kclips;
-		int n = kp->clipcount;
+		int n = clipcount;
 		compat_caddr_t p;
 
 		if (get_user(p, &up->clips))
 			return -EFAULT;
 		uclips = compat_ptr(p);
 		kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
-		kp->clips = kclips;
+		if (put_user(kclips, &kp->clips))
+			return -EFAULT;
 		while (--n >= 0) {
 			if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
 				return -EFAULT;
@@ -74,89 +83,106 @@
 			uclips += 1;
 			kclips += 1;
 		}
-	} else
-		kp->clips = NULL;
-	return 0;
-}
-
-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
-{
-	if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
-		put_user(kp->field, &up->field) ||
-		put_user(kp->chromakey, &up->chromakey) ||
-		put_user(kp->clipcount, &up->clipcount))
+	} else {
+		if (put_user(NULL, &kp->clips))
 			return -EFAULT;
+	}
 	return 0;
 }
 
-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+static int put_v4l2_window32(struct v4l2_window __user *kp,
+			struct v4l2_window32 __user *up)
 {
-	if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
+	if (copy_in_user(&up->w, &kp->w, sizeof(up->w)) ||
+		copy_in_user(&up->field, &kp->field, sizeof(up->field)) ||
+		copy_in_user(&up->chromakey, &kp->chromakey,
+			sizeof(up->chromakey)) ||
+		copy_in_user(&up->clipcount, &kp->clipcount,
+			sizeof(up->clipcount)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+static inline int get_v4l2_pix_format(struct v4l2_pix_format __user *kp,
+				struct v4l2_pix_format __user *up)
+{
+	if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format)))
+		return -EFAULT;
+	return 0;
+}
+
+static inline int get_v4l2_pix_format_mplane(
+				struct v4l2_pix_format_mplane __user *kp,
 				struct v4l2_pix_format_mplane __user *up)
 {
-	if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+	if (copy_in_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
+static inline int put_v4l2_pix_format(struct v4l2_pix_format __user *kp,
+				struct v4l2_pix_format __user *up)
 {
-	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
+	if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
+static inline int put_v4l2_pix_format_mplane(
+				struct v4l2_pix_format_mplane __user *kp,
 				struct v4l2_pix_format_mplane __user *up)
 {
-	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+	if (copy_in_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+static inline int get_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
+				struct v4l2_vbi_format __user *up)
 {
-	if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
+	if (copy_in_user(kp, up, sizeof(struct v4l2_vbi_format)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
+static inline int put_v4l2_vbi_format(struct v4l2_vbi_format __user *kp,
+				struct v4l2_vbi_format __user *up)
 {
-	if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
+	if (copy_in_user(up, kp, sizeof(struct v4l2_vbi_format)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+static inline int get_v4l2_sliced_vbi_format(
+				struct v4l2_sliced_vbi_format __user *kp,
+				struct v4l2_sliced_vbi_format __user *up)
 {
-	if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+	if (copy_in_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+static inline int put_v4l2_sliced_vbi_format(
+				struct v4l2_sliced_vbi_format __user *kp,
+				struct v4l2_sliced_vbi_format __user *up)
 {
-	if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+	if (copy_in_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int get_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+static inline int get_v4l2_sdr_format(struct v4l2_sdr_format __user *kp,
+				struct v4l2_sdr_format __user *up)
 {
-	if (copy_from_user(kp, up, sizeof(struct v4l2_sdr_format)))
+	if (copy_in_user(kp, up, sizeof(struct v4l2_sdr_format)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sdr_format __user *up)
+static inline int put_v4l2_sdr_format(struct v4l2_sdr_format __user *kp,
+					struct v4l2_sdr_format __user *up)
 {
-	if (copy_to_user(up, kp, sizeof(struct v4l2_sdr_format)))
+	if (copy_in_user(up, kp, sizeof(struct v4l2_sdr_format)))
 		return -EFAULT;
 	return 0;
 }
@@ -191,12 +217,17 @@
 	__u32			reserved[8];
 };
 
-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __get_v4l2_format32(struct v4l2_format __user *kp,
+				struct v4l2_format32 __user *up)
 {
-	if (get_user(kp->type, &up->type))
+	u32 type;
+
+	if (copy_in_user(&kp->type, &up->type, sizeof(up->type)))
 		return -EFAULT;
 
-	switch (kp->type) {
+	if (get_user(type, &kp->type))
+		return -EFAULT;
+	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
@@ -223,27 +254,39 @@
 	}
 }
 
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int get_v4l2_format32(struct v4l2_format __user *kp,
+				struct v4l2_format32 __user *up)
 {
-	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
+	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
+		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_format)))
 		return -EFAULT;
 	return __get_v4l2_format32(kp, up);
 }
 
-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
+				struct v4l2_create_buffers32 __user *up)
 {
 	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
-	    copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
+		!access_ok(VERIFY_WRITE, kp,
+			sizeof(struct v4l2_create_buffers)) ||
+		copy_in_user(kp, up,
+			offsetof(struct v4l2_create_buffers32, format)))
 		return -EFAULT;
 	return __get_v4l2_format32(&kp->format, &up->format);
 }
 
-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __put_v4l2_format32(struct v4l2_format __user *kp,
+				struct v4l2_format32 __user *up)
 {
-	if (put_user(kp->type, &up->type))
+	u32 type;
+
+	if (copy_in_user(&up->type, &kp->type, sizeof(up->type)))
 		return -EFAULT;
 
-	switch (kp->type) {
+	if (get_user(type, &kp->type))
+		return -EFAULT;
+
+	switch (type) {
 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 		return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
@@ -270,18 +313,24 @@
 	}
 }
 
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int put_v4l2_format32(struct v4l2_format __user *kp,
+				struct v4l2_format32 __user *up)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
+	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
+		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_format)))
 		return -EFAULT;
 	return __put_v4l2_format32(kp, up);
 }
 
-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
+				struct v4l2_create_buffers32 __user *up)
 {
 	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
-	    copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)) ||
-	    copy_to_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+		!access_ok(VERIFY_READ, kp,
+			sizeof(struct v4l2_create_buffers)) ||
+		copy_in_user(up, kp,
+			offsetof(struct v4l2_create_buffers32, format)) ||
+		copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
 		return -EFAULT;
 	return __put_v4l2_format32(&kp->format, &up->format);
 }
@@ -295,24 +344,30 @@
 	__u32		     reserved[4];
 };
 
-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int get_v4l2_standard32(struct v4l2_standard __user *kp,
+			struct v4l2_standard32 __user *up)
 {
 	/* other fields are not set by the user, nor used by the driver */
 	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
-		get_user(kp->index, &up->index))
+		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_standard)) ||
+		copy_in_user(&kp->index, &up->index, sizeof(up->index)))
 		return -EFAULT;
 	return 0;
 }
 
-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int put_v4l2_standard32(struct v4l2_standard __user *kp,
+				struct v4l2_standard32 __user *up)
 {
 	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
-		put_user(kp->index, &up->index) ||
-		put_user(kp->id, &up->id) ||
-		copy_to_user(up->name, kp->name, 24) ||
-		copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
-		put_user(kp->framelines, &up->framelines) ||
-		copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
+		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_standard)) ||
+		copy_in_user(&up->index, &kp->index, sizeof(up->index)) ||
+		copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
+		copy_in_user(up->name, kp->name, 24) ||
+		copy_in_user(&up->frameperiod, &kp->frameperiod,
+			sizeof(up->frameperiod)) ||
+		copy_in_user(&up->framelines, &kp->framelines,
+			sizeof(up->framelines)) ||
+		copy_in_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
 			return -EFAULT;
 	return 0;
 }
@@ -360,6 +415,10 @@
 
 	if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
 		copy_in_user(&up->data_offset, &up32->data_offset,
+				sizeof(__u32)) ||
+		copy_in_user(up->reserved, up32->reserved,
+				sizeof(up->reserved)) ||
+		copy_in_user(&up->length, &up32->length,
 				sizeof(__u32)))
 		return -EFAULT;
 
@@ -386,7 +445,9 @@
 {
 	if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
 		copy_in_user(&up32->data_offset, &up->data_offset,
-				sizeof(__u32)))
+				sizeof(__u32)) ||
+		copy_in_user(up32->reserved, up->reserved,
+				sizeof(up32->reserved)))
 		return -EFAULT;
 
 	/* For MMAP, driver might've set up the offset, so copy it back.
@@ -404,34 +465,48 @@
 	return 0;
 }
 
-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
+				struct v4l2_buffer32 __user *up)
 {
 	struct v4l2_plane32 __user *uplane32;
 	struct v4l2_plane __user *uplane;
 	compat_caddr_t p;
 	int num_planes;
+	struct timeval time;
+	u32 plane_count, memory, type;
 	int ret;
 
 	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
-		get_user(kp->index, &up->index) ||
-		get_user(kp->type, &up->type) ||
-		get_user(kp->flags, &up->flags) ||
-		get_user(kp->memory, &up->memory) ||
-		get_user(kp->length, &up->length))
+		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_buffer)) ||
+		copy_in_user(&kp->index, &up->index, sizeof(up->index)) ||
+		copy_in_user(&kp->type, &up->type, sizeof(up->type)) ||
+		copy_in_user(&kp->flags, &up->flags, sizeof(up->flags)) ||
+		copy_in_user(&kp->memory, &up->memory, sizeof(up->memory)) ||
+		copy_in_user(&kp->length, &up->length, sizeof(up->length)))
 			return -EFAULT;
 
-	if (V4L2_TYPE_IS_OUTPUT(kp->type))
-		if (get_user(kp->bytesused, &up->bytesused) ||
-			get_user(kp->field, &up->field) ||
-			get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-			get_user(kp->timestamp.tv_usec,
-					&up->timestamp.tv_usec))
+	if (get_user(type, &kp->type))
+		return -EFAULT;
+	if (V4L2_TYPE_IS_OUTPUT(type))
+		if (copy_in_user(&kp->bytesused, &up->bytesused,
+				sizeof(up->bytesused)) ||
+			copy_in_user(&kp->field, &up->field,
+				sizeof(up->field)) ||
+			get_user(time.tv_sec, &up->timestamp.tv_sec) ||
+			get_user(time.tv_usec, &up->timestamp.tv_usec) ||
+			put_user(time.tv_sec, &kp->timestamp.tv_sec) ||
+			put_user(time.tv_usec, &kp->timestamp.tv_usec))
 			return -EFAULT;
 
-	if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-		num_planes = kp->length;
+	if (get_user(memory, &kp->memory))
+		return -EFAULT;
+	if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+		if (get_user(plane_count, &kp->length))
+			return -EFAULT;
+		num_planes = plane_count;
 		if (num_planes == 0) {
-			kp->m.planes = NULL;
+			if (put_user(NULL, &kp->m.planes))
+				return -EFAULT;
 			/* num_planes == 0 is legal, e.g. when userspace doesn't
 			 * need planes array on DQBUF*/
 			return 0;
@@ -449,37 +524,43 @@
 		 * by passing a very big num_planes value */
 		uplane = compat_alloc_user_space(num_planes *
 						sizeof(struct v4l2_plane));
-		kp->m.planes = (__force struct v4l2_plane *)uplane;
+		if (put_user(uplane, &kp->m.planes))
+			return -EFAULT;
 
 		while (--num_planes >= 0) {
-			ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
+			ret = get_v4l2_plane32(uplane, uplane32, memory);
 			if (ret)
 				return ret;
 			++uplane;
 			++uplane32;
 		}
 	} else {
-		switch (kp->memory) {
+		switch (memory) {
 		case V4L2_MEMORY_MMAP:
-			if (get_user(kp->m.offset, &up->m.offset))
+			if (copy_in_user(&kp->m.offset, &up->m.offset,
+				sizeof(up->m.offset)))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_USERPTR:
 			{
 			compat_long_t tmp;
+			unsigned long userptr;
 
 			if (get_user(tmp, &up->m.userptr))
 				return -EFAULT;
 
-			kp->m.userptr = (unsigned long)compat_ptr(tmp);
+			userptr = (unsigned long)compat_ptr(tmp);
+			put_user(userptr, &kp->m.userptr);
 			}
 			break;
 		case V4L2_MEMORY_OVERLAY:
-			if (get_user(kp->m.offset, &up->m.offset))
+			if (copy_in_user(&kp->m.offset, &up->m.offset,
+				sizeof(up->m.offset)))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_DMABUF:
-			if (get_user(kp->m.fd, &up->m.fd))
+			if (copy_in_user(&kp->m.fd, &up->m.fd,
+				sizeof(up->m.fd)))
 				return -EFAULT;
 			break;
 		}
@@ -488,65 +569,86 @@
 	return 0;
 }
 
-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
+				struct v4l2_buffer32 __user *up)
 {
 	struct v4l2_plane32 __user *uplane32;
 	struct v4l2_plane __user *uplane;
 	compat_caddr_t p;
 	int num_planes;
 	int ret;
+	struct timeval time;
+	u32 memory, type, length;
 
 	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
-		put_user(kp->index, &up->index) ||
-		put_user(kp->type, &up->type) ||
-		put_user(kp->flags, &up->flags) ||
-		put_user(kp->memory, &up->memory))
-			return -EFAULT;
+		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_buffer)) ||
+		copy_in_user(&up->index, &kp->index, sizeof(up->index)) ||
+		copy_in_user(&up->type, &kp->type, sizeof(up->type)) ||
+		copy_in_user(&up->flags, &kp->flags, sizeof(up->flags)) ||
+		copy_in_user(&up->memory, &kp->memory, sizeof(up->memory)))
+		return -EFAULT;
 
-	if (put_user(kp->bytesused, &up->bytesused) ||
-		put_user(kp->field, &up->field) ||
-		put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-		put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
-		copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
-		put_user(kp->sequence, &up->sequence) ||
-		put_user(kp->reserved2, &up->reserved2) ||
-		put_user(kp->reserved, &up->reserved) ||
-		put_user(kp->length, &up->length))
-			return -EFAULT;
+	if (copy_in_user(&up->bytesused, &kp->bytesused,
+			sizeof(up->bytesused)) ||
+		copy_in_user(&up->field, &kp->field, sizeof(up->field)) ||
+		get_user(time.tv_sec, &kp->timestamp.tv_sec) ||
+		get_user(time.tv_usec, &kp->timestamp.tv_usec) ||
+		put_user(time.tv_sec, &up->timestamp.tv_sec) ||
+		put_user(time.tv_usec, &up->timestamp.tv_usec) ||
+		copy_in_user(&up->timecode, &kp->timecode,
+			sizeof(struct v4l2_timecode)) ||
+		copy_in_user(&up->sequence, &kp->sequence,
+			sizeof(up->sequence)) ||
+		copy_in_user(&up->reserved2, &kp->reserved2,
+			sizeof(up->reserved2)) ||
+		copy_in_user(&up->reserved, &kp->reserved,
+			sizeof(up->reserved)) ||
+		copy_in_user(&up->length, &kp->length, sizeof(up->length)))
+		return -EFAULT;
 
-	if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-		num_planes = kp->length;
+	if (get_user(type, &kp->type) ||
+		get_user(memory, &kp->memory) ||
+		get_user(length, &kp->length))
+		return -EINVAL;
+
+	if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+		num_planes = length;
 		if (num_planes == 0)
 			return 0;
 
-		uplane = (__force struct v4l2_plane __user *)kp->m.planes;
+		if (get_user(uplane, &kp->m.planes))
+			return -EFAULT;
 		if (get_user(p, &up->m.planes))
 			return -EFAULT;
 		uplane32 = compat_ptr(p);
 
 		while (--num_planes >= 0) {
-			ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
+			ret = put_v4l2_plane32(uplane, uplane32, memory);
 			if (ret)
 				return ret;
 			++uplane;
 			++uplane32;
 		}
 	} else {
-		switch (kp->memory) {
+		switch (memory) {
 		case V4L2_MEMORY_MMAP:
-			if (put_user(kp->m.offset, &up->m.offset))
+			if (copy_in_user(&up->m.offset, &kp->m.offset,
+				sizeof(up->m.offset)))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_USERPTR:
-			if (put_user(kp->m.userptr, &up->m.userptr))
+			if (copy_in_user(&up->m.userptr, &kp->m.userptr,
+				sizeof(up->m.userptr)))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_OVERLAY:
-			if (put_user(kp->m.offset, &up->m.offset))
+			if (copy_in_user(&up->m.offset, &kp->m.offset,
+				sizeof(up->m.offset)))
 				return -EFAULT;
 			break;
 		case V4L2_MEMORY_DMABUF:
-			if (put_user(kp->m.fd, &up->m.fd))
+			if (copy_in_user(&up->m.fd, &kp->m.fd,
+				sizeof(up->m.fd)))
 				return -EFAULT;
 			break;
 		}
@@ -571,29 +673,39 @@
 	} fmt;
 };
 
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+					struct v4l2_framebuffer32 __user *up)
 {
 	u32 tmp;
 
 	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
+		!access_ok(VERIFY_WRITE, kp,
+			sizeof(struct v4l2_framebuffer)) ||
 		get_user(tmp, &up->base) ||
-		get_user(kp->capability, &up->capability) ||
-		get_user(kp->flags, &up->flags) ||
-		copy_from_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
+		put_user(compat_ptr(tmp), &kp->base) ||
+		copy_in_user(&kp->capability, &up->capability,
+			sizeof(up->capability)) ||
+		copy_in_user(&kp->flags, &up->flags, sizeof(up->flags)) ||
+		copy_in_user(&kp->fmt, &up->fmt, sizeof(up->fmt)))
 			return -EFAULT;
-	kp->base = (__force void *)compat_ptr(tmp);
+
 	return 0;
 }
 
-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+					struct v4l2_framebuffer32 __user *up)
 {
-	u32 tmp = (u32)((unsigned long)kp->base);
+	unsigned long base;
 
 	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
-		put_user(tmp, &up->base) ||
-		put_user(kp->capability, &up->capability) ||
-		put_user(kp->flags, &up->flags) ||
-		copy_to_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
+		!access_ok(VERIFY_READ, kp,
+			sizeof(struct v4l2_framebuffer)) ||
+		copy_from_user(&base, &kp->base, sizeof(base)) ||
+		put_user((u32)base, &up->base) ||
+		copy_in_user(&up->capability, &kp->capability,
+			sizeof(up->capability)) ||
+		copy_in_user(&up->flags, &kp->flags, sizeof(up->flags)) ||
+		copy_in_user(&up->fmt, &kp->fmt, sizeof(up->fmt)))
 			return -EFAULT;
 	return 0;
 }
@@ -611,16 +723,18 @@
 
 /* The 64-bit v4l2_input struct has extra padding at the end of the struct.
    Otherwise it is identical to the 32-bit version. */
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+static inline int get_v4l2_input32(struct v4l2_input __user *kp,
+					struct v4l2_input32 __user *up)
 {
-	if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
+	if (copy_in_user(kp, up, sizeof(struct v4l2_input32)))
 		return -EFAULT;
 	return 0;
 }
 
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+static inline int put_v4l2_input32(struct v4l2_input __user *kp,
+					struct v4l2_input32 __user *up)
 {
-	if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
+	if (copy_in_user(up, kp, sizeof(struct v4l2_input32)))
 		return -EFAULT;
 	return 0;
 }
@@ -661,23 +775,33 @@
 	}
 }
 
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int get_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
+					struct v4l2_ext_controls32 __user *up)
 {
 	struct v4l2_ext_control32 __user *ucontrols;
 	struct v4l2_ext_control __user *kcontrols;
 	int n;
 	compat_caddr_t p;
+	u32 count;
 
 	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
-		get_user(kp->which, &up->which) ||
-		get_user(kp->count, &up->count) ||
-		get_user(kp->error_idx, &up->error_idx) ||
-		copy_from_user(kp->reserved, up->reserved,
-			       sizeof(kp->reserved)))
+		!access_ok(VERIFY_WRITE, kp,
+			sizeof(struct v4l2_ext_controls)) ||
+		copy_in_user(&kp->which, &up->which,
+			sizeof(up->which)) ||
+		copy_in_user(&kp->count, &up->count, sizeof(up->count)) ||
+		copy_in_user(&kp->error_idx, &up->error_idx,
+			sizeof(up->error_idx)) ||
+		copy_in_user(kp->reserved, up->reserved,
+			       sizeof(up->reserved)))
 			return -EFAULT;
-	n = kp->count;
+
+	if (get_user(count, &kp->count))
+		return -EFAULT;
+	n = count;
 	if (n == 0) {
-		kp->controls = NULL;
+		if (put_user(NULL, &kp->controls))
+			return -EINVAL;
 		return 0;
 	}
 	if (get_user(p, &up->controls))
@@ -687,7 +811,9 @@
 			n * sizeof(struct v4l2_ext_control32)))
 		return -EFAULT;
 	kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
-	kp->controls = (__force struct v4l2_ext_control *)kcontrols;
+	if (put_user(kcontrols, &kp->controls))
+		return -EFAULT;
+
 	while (--n >= 0) {
 		u32 id;
 
@@ -710,23 +836,33 @@
 	return 0;
 }
 
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int put_v4l2_ext_controls32(struct v4l2_ext_controls __user *kp,
+				struct v4l2_ext_controls32 __user *up)
 {
 	struct v4l2_ext_control32 __user *ucontrols;
-	struct v4l2_ext_control __user *kcontrols =
-		(__force struct v4l2_ext_control __user *)kp->controls;
-	int n = kp->count;
+	struct v4l2_ext_control __user *kcontrols;
+	int n;
+	u32 count;
 	compat_caddr_t p;
 
 	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
-		put_user(kp->which, &up->which) ||
-		put_user(kp->count, &up->count) ||
-		put_user(kp->error_idx, &up->error_idx) ||
-		copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+		!access_ok(VERIFY_READ, kp,
+			sizeof(struct v4l2_ext_controls)) ||
+		copy_in_user(&up->which, &kp->which,
+			sizeof(up->which)) ||
+		copy_in_user(&up->count, &kp->count,
+			sizeof(up->count)) ||
+		copy_in_user(&up->error_idx, &kp->error_idx,
+			sizeof(up->error_idx)) ||
+		copy_in_user(up->reserved, kp->reserved,
+			sizeof(up->reserved)) ||
+		get_user(count, &kp->count) ||
+		get_user(kcontrols, &kp->controls))
 			return -EFAULT;
-	if (!kp->count)
+	if (!count)
 		return 0;
 
+	n = count;
 	if (get_user(p, &up->controls))
 		return -EFAULT;
 	ucontrols = compat_ptr(p);
@@ -766,16 +902,22 @@
 	__u32				reserved[8];
 };
 
-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+static int put_v4l2_event32(struct v4l2_event __user *kp,
+			struct v4l2_event32 __user *up)
 {
+	struct timespec ts;
 	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
-		put_user(kp->type, &up->type) ||
-		copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
-		put_user(kp->pending, &up->pending) ||
-		put_user(kp->sequence, &up->sequence) ||
-		compat_put_timespec(&kp->timestamp, &up->timestamp) ||
-		put_user(kp->id, &up->id) ||
-		copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
+		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_event)) ||
+		copy_in_user(&up->type, &kp->type, sizeof(up->type)) ||
+		copy_in_user(&up->u, &kp->u, sizeof(up->u)) ||
+		copy_in_user(&up->pending, &kp->pending,
+			sizeof(up->pending)) ||
+		copy_in_user(&up->sequence, &kp->sequence,
+			sizeof(up->sequence)) ||
+		copy_from_user(&ts, &kp->timestamp, sizeof(ts)) ||
+		compat_put_timespec(&ts, &up->timestamp) ||
+		copy_in_user(&up->id, &kp->id, sizeof(up->id)) ||
+		copy_in_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
 			return -EFAULT;
 	return 0;
 }
@@ -788,31 +930,39 @@
 	compat_caddr_t edid;
 };
 
-static int get_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+static int get_v4l2_edid32(struct v4l2_edid __user *kp,
+						struct v4l2_edid32 __user *up)
 {
 	u32 tmp;
 
 	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_edid32)) ||
-		get_user(kp->pad, &up->pad) ||
-		get_user(kp->start_block, &up->start_block) ||
-		get_user(kp->blocks, &up->blocks) ||
+		!access_ok(VERIFY_WRITE, kp, sizeof(struct v4l2_edid)) ||
+		copy_in_user(&kp->pad, &up->pad, sizeof(up->pad)) ||
+		copy_in_user(&kp->start_block, &up->start_block,
+			sizeof(up->start_block)) ||
+		copy_in_user(&kp->blocks, &up->blocks, sizeof(up->blocks)) ||
 		get_user(tmp, &up->edid) ||
-		copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+		put_user(compat_ptr(tmp), &kp->edid) ||
+		copy_in_user(kp->reserved, up->reserved,
+			sizeof(kp->reserved)))
 			return -EFAULT;
-	kp->edid = (__force u8 *)compat_ptr(tmp);
 	return 0;
 }
 
-static int put_v4l2_edid32(struct v4l2_edid *kp, struct v4l2_edid32 __user *up)
+static int put_v4l2_edid32(struct v4l2_edid __user *kp,
+			struct v4l2_edid32 __user *up)
 {
-	u32 tmp = (u32)((unsigned long)kp->edid);
+	unsigned long ptr;
 
 	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_edid32)) ||
-		put_user(kp->pad, &up->pad) ||
-		put_user(kp->start_block, &up->start_block) ||
-		put_user(kp->blocks, &up->blocks) ||
-		put_user(tmp, &up->edid) ||
-		copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+		!access_ok(VERIFY_READ, kp, sizeof(struct v4l2_edid)) ||
+		copy_in_user(&up->pad, &kp->pad, sizeof(up->pad)) ||
+		copy_in_user(&up->start_block, &kp->start_block,
+			sizeof(up->start_block)) ||
+		copy_in_user(&up->blocks, &kp->blocks, sizeof(up->blocks)) ||
+		copy_from_user(&ptr, &kp->edid, sizeof(ptr)) ||
+		put_user((u32)ptr, &up->edid) ||
+		copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
 			return -EFAULT;
 	return 0;
 }
@@ -859,11 +1009,16 @@
 		struct v4l2_edid v2edid;
 		unsigned long vx;
 		int vi;
-	} karg;
+	} *karg;
 	void __user *up = compat_ptr(arg);
 	int compatible_arg = 1;
 	long err = 0;
 
+	karg = compat_alloc_user_space(sizeof(*karg));
+	if (karg == NULL) {
+		return -EFAULT;
+	}
+
 	/* First, convert the command. */
 	switch (cmd) {
 	case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
@@ -899,7 +1054,8 @@
 	case VIDIOC_STREAMOFF:
 	case VIDIOC_S_INPUT:
 	case VIDIOC_S_OUTPUT:
-		err = get_user(karg.vi, (s32 __user *)up);
+		err = copy_in_user(&karg->vi, (s32 __user *)up,
+			sizeof(karg->vi));
 		compatible_arg = 0;
 		break;
 
@@ -910,19 +1066,19 @@
 
 	case VIDIOC_G_EDID:
 	case VIDIOC_S_EDID:
-		err = get_v4l2_edid32(&karg.v2edid, up);
+		err = get_v4l2_edid32(&karg->v2edid, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_FMT:
 	case VIDIOC_S_FMT:
 	case VIDIOC_TRY_FMT:
-		err = get_v4l2_format32(&karg.v2f, up);
+		err = get_v4l2_format32(&karg->v2f, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_CREATE_BUFS:
-		err = get_v4l2_create32(&karg.v2crt, up);
+		err = get_v4l2_create32(&karg->v2crt, up);
 		compatible_arg = 0;
 		break;
 
@@ -930,12 +1086,12 @@
 	case VIDIOC_QUERYBUF:
 	case VIDIOC_QBUF:
 	case VIDIOC_DQBUF:
-		err = get_v4l2_buffer32(&karg.v2b, up);
+		err = get_v4l2_buffer32(&karg->v2b, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_S_FBUF:
-		err = get_v4l2_framebuffer32(&karg.v2fb, up);
+		err = get_v4l2_framebuffer32(&karg->v2fb, up);
 		compatible_arg = 0;
 		break;
 
@@ -944,19 +1100,19 @@
 		break;
 
 	case VIDIOC_ENUMSTD:
-		err = get_v4l2_standard32(&karg.v2s, up);
+		err = get_v4l2_standard32(&karg->v2s, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_ENUMINPUT:
-		err = get_v4l2_input32(&karg.v2i, up);
+		err = get_v4l2_input32(&karg->v2i, up);
 		compatible_arg = 0;
 		break;
 
 	case VIDIOC_G_EXT_CTRLS:
 	case VIDIOC_S_EXT_CTRLS:
 	case VIDIOC_TRY_EXT_CTRLS:
-		err = get_v4l2_ext_controls32(&karg.v2ecs, up);
+		err = get_v4l2_ext_controls32(&karg->v2ecs, up);
 		compatible_arg = 0;
 		break;
 	case VIDIOC_DQEVENT:
@@ -969,11 +1125,7 @@
 	if (compatible_arg)
 		err = native_ioctl(file, cmd, (unsigned long)up);
 	else {
-		mm_segment_t old_fs = get_fs();
-
-		set_fs(KERNEL_DS);
-		err = native_ioctl(file, cmd, (unsigned long)&karg);
-		set_fs(old_fs);
+		err = native_ioctl(file, cmd, (unsigned long)karg);
 	}
 
 	/* Special case: even after an error we need to put the
@@ -983,7 +1135,7 @@
 	case VIDIOC_G_EXT_CTRLS:
 	case VIDIOC_S_EXT_CTRLS:
 	case VIDIOC_TRY_EXT_CTRLS:
-		if (put_v4l2_ext_controls32(&karg.v2ecs, up))
+		if (put_v4l2_ext_controls32(&karg->v2ecs, up))
 			err = -EFAULT;
 		break;
 	}
@@ -995,44 +1147,44 @@
 	case VIDIOC_S_OUTPUT:
 	case VIDIOC_G_INPUT:
 	case VIDIOC_G_OUTPUT:
-		err = put_user(((s32)karg.vi), (s32 __user *)up);
+		err = copy_in_user(up, &karg->vi, sizeof(s32));
 		break;
 
 	case VIDIOC_G_FBUF:
-		err = put_v4l2_framebuffer32(&karg.v2fb, up);
+		err = put_v4l2_framebuffer32(&karg->v2fb, up);
 		break;
 
 	case VIDIOC_DQEVENT:
-		err = put_v4l2_event32(&karg.v2ev, up);
+		err = put_v4l2_event32(&karg->v2ev, up);
 		break;
 
 	case VIDIOC_G_EDID:
 	case VIDIOC_S_EDID:
-		err = put_v4l2_edid32(&karg.v2edid, up);
+		err = put_v4l2_edid32(&karg->v2edid, up);
 		break;
 
 	case VIDIOC_G_FMT:
 	case VIDIOC_S_FMT:
 	case VIDIOC_TRY_FMT:
-		err = put_v4l2_format32(&karg.v2f, up);
+		err = put_v4l2_format32(&karg->v2f, up);
 		break;
 
 	case VIDIOC_CREATE_BUFS:
-		err = put_v4l2_create32(&karg.v2crt, up);
+		err = put_v4l2_create32(&karg->v2crt, up);
 		break;
 
 	case VIDIOC_QUERYBUF:
 	case VIDIOC_QBUF:
 	case VIDIOC_DQBUF:
-		err = put_v4l2_buffer32(&karg.v2b, up);
+		err = put_v4l2_buffer32(&karg->v2b, up);
 		break;
 
 	case VIDIOC_ENUMSTD:
-		err = put_v4l2_standard32(&karg.v2s, up);
+		err = put_v4l2_standard32(&karg->v2s, up);
 		break;
 
 	case VIDIOC_ENUMINPUT:
-		err = put_v4l2_input32(&karg.v2i, up);
+		err = put_v4l2_input32(&karg->v2i, up);
 		break;
 	}
 	return err;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2c02d2d..877c4d1 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -5869,7 +5869,8 @@
 		 * It will return false if it is GPCE based crypto instance or
 		 * ICE is setup properly
 		 */
-		if (qseecom_enable_ice_setup(create_key_req.usage))
+		ret = qseecom_enable_ice_setup(create_key_req.usage);
+		if (ret)
 			goto free_buf;
 
 		do {
@@ -5998,7 +5999,8 @@
 		 * It will return false if it is GPCE based crypto instance or
 		 * ICE is setup properly
 		 */
-		if (qseecom_enable_ice_setup(wipe_key_req.usage))
+		ret = qseecom_enable_ice_setup(wipe_key_req.usage);
+		if (ret)
 			goto free_buf;
 
 		ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 220ba6d..1397d03 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -617,12 +617,25 @@
 	}
 
 out:
-	clk_scaling->devfreq_profile.freq_table = (unsigned long *)clk_scaling->freq_table;
+	/**
+	 * devfreq requires unsigned long type freq_table while the
+	 * freq_table in clk_scaling is un32. Here allocates an individual
+	 * memory space for it and release it when exit clock scaling.
+	 */
+	clk_scaling->devfreq_profile.freq_table =  kzalloc(
+			clk_scaling->freq_table_sz *
+			sizeof(*(clk_scaling->devfreq_profile.freq_table)),
+			GFP_KERNEL);
+	if (!clk_scaling->devfreq_profile.freq_table)
+		return -ENOMEM;
 	clk_scaling->devfreq_profile.max_state = clk_scaling->freq_table_sz;
 
-	for (i = 0; i < clk_scaling->freq_table_sz; i++)
+	for (i = 0; i < clk_scaling->freq_table_sz; i++) {
+		clk_scaling->devfreq_profile.freq_table[i] =
+			clk_scaling->freq_table[i];
 		pr_debug("%s: freq[%d] = %u\n",
 			mmc_hostname(host), i, clk_scaling->freq_table[i]);
+	}
 
 	return 0;
 }
@@ -858,6 +871,8 @@
 		return err;
 	}
 
+	kfree(host->clk_scaling.devfreq_profile.freq_table);
+
 	host->clk_scaling.devfreq = NULL;
 	atomic_set(&host->clk_scaling.devfreq_abort, 1);
 	pr_debug("%s: devfreq was removed\n", mmc_hostname(host));
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 7123ef9..445fc47 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -830,6 +830,7 @@
 
 	switch (uhs) {
 	case MMC_TIMING_UHS_SDR50:
+	case MMC_TIMING_UHS_DDR50:
 		pinctrl = imx_data->pins_100mhz;
 		break;
 	case MMC_TIMING_UHS_SDR104:
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 0134ba3..3971256 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -148,11 +148,11 @@
 			return err;
 	}
 
-	if (bytes == 0) {
-		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
-		if (err)
-			return err;
+	err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
+	if (err)
+		return err;
 
+	if (bytes == 0) {
 		err = clear_update_marker(ubi, vol, 0);
 		if (err)
 			return err;
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
index 61de231..3c89a73 100644
--- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -210,6 +210,7 @@
 #else
 void wcnss_prealloc_check_memory_leak(void) {}
 #endif
+EXPORT_SYMBOL(wcnss_prealloc_check_memory_leak);
 
 int wcnss_pre_alloc_reset(void)
 {
@@ -225,6 +226,7 @@
 
 	return n;
 }
+EXPORT_SYMBOL(wcnss_pre_alloc_reset);
 
 static int __init wcnss_pre_alloc_init(void)
 {
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 8b3216cd..16c9096 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -6457,7 +6457,6 @@
 	}
 
 	dev_set_drvdata(&msm_pcie_dev[rc_idx].pdev->dev, &msm_pcie_dev[rc_idx]);
-	msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]);
 
 	ret = msm_pcie_get_resources(&msm_pcie_dev[rc_idx],
 				msm_pcie_dev[rc_idx].pdev);
@@ -6508,6 +6507,8 @@
 		goto decrease_rc_num;
 	}
 
+	msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]);
+
 	msm_pcie_dev[rc_idx].drv_ready = true;
 
 	if (msm_pcie_dev[rc_idx].boot_option &
@@ -6763,12 +6764,12 @@
 		PCIE_DBG(pcie_dev, "RC%d: PM_Enter_L23 is NOT received\n",
 			pcie_dev->rc_idx);
 
-		msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
-
 	if (pcie_dev->use_pinctrl && pcie_dev->pins_sleep)
 		pinctrl_select_state(pcie_dev->pinctrl,
 					pcie_dev->pins_sleep);
 
+	msm_pcie_disable(pcie_dev, PM_PIPE_CLK | PM_CLK | PM_VREG);
+
 	PCIE_DBG(pcie_dev, "RC%d: exit\n", pcie_dev->rc_idx);
 
 	return ret;
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index d45fa51..a37947b 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -126,6 +126,7 @@
 	__stringify(IPA_CLIENT_Q6_DECOMP_PROD),
 	__stringify(IPA_CLIENT_Q6_DECOMP2_PROD),
 	__stringify(IPA_CLIENT_UC_USB_PROD),
+	__stringify(IPA_CLIENT_ETHERNET_PROD),
 
 	/* Below PROD client type is only for test purpose */
 	__stringify(IPA_CLIENT_TEST_PROD),
@@ -164,6 +165,7 @@
 	__stringify(IPA_CLIENT_Q6_DECOMP_CONS),
 	__stringify(IPA_CLIENT_Q6_DECOMP2_CONS),
 	__stringify(IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS),
+	__stringify(IPA_CLIENT_ETHERNET_CONS),
 	/* Below CONS client type is only for test purpose */
 	__stringify(IPA_CLIENT_TEST_CONS),
 	__stringify(IPA_CLIENT_TEST1_CONS),
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 15bb7b4..fb42ef7 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1584,6 +1584,7 @@
 	struct ipa_hw_imm_cmd_dma_shared_mem *cmd = NULL;
 	struct ipa_desc desc;
 	struct ipa_mem_buffer mem;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	int rc;
 
 	if (memory_region_size == 0)
@@ -1603,7 +1604,7 @@
 	memset(mem.base, 0, mem.size);
 
 	cmd = kzalloc(sizeof(*cmd),
-		GFP_KERNEL);
+		flag);
 	if (cmd == NULL) {
 		IPAERR("Failed to alloc immediate command object\n");
 		rc = -ENOMEM;
@@ -2166,6 +2167,7 @@
 	struct ipa_hw_imm_cmd_dma_shared_mem *cmd = NULL;
 	struct ipa_desc desc = {0};
 	struct ipa_mem_buffer mem;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	int rc = 0;
 
 	phys_addr = ipa_ctx->ipa_wrapper_base +
@@ -2203,7 +2205,7 @@
 	}
 	memset(mem.base, 0, mem.size);
 
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	cmd = kzalloc(sizeof(*cmd), flag);
 	if (cmd == NULL) {
 		IPAERR("Failed to alloc immediate command object\n");
 		rc = -ENOMEM;
@@ -2314,6 +2316,7 @@
 	struct ipa_desc desc = { 0 };
 	struct ipa_mem_buffer mem;
 	struct ipa_hdr_init_local *cmd = NULL;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	int rc = 0;
 
 	mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
@@ -2325,7 +2328,7 @@
 	}
 	memset(mem.base, 0, mem.size);
 
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	cmd = kzalloc(sizeof(*cmd), flag);
 	if (cmd == NULL) {
 		IPAERR("Failed to alloc header init command object\n");
 		rc = -ENOMEM;
@@ -2360,6 +2363,7 @@
 	struct ipa_mem_buffer mem;
 	struct ipa_hdr_init_local *cmd = NULL;
 	struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd = NULL;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 
 	mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
 	mem.base = dma_alloc_coherent(ipa_ctx->pdev, mem.size, &mem.phys_base,
@@ -2370,7 +2374,7 @@
 	}
 	memset(mem.base, 0, mem.size);
 
-	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	cmd = kzalloc(sizeof(*cmd), flag);
 	if (cmd == NULL) {
 		IPAERR("Failed to alloc header init command object\n");
 		dma_free_coherent(ipa_ctx->pdev, mem.size, mem.base,
@@ -2411,7 +2415,7 @@
 	memset(mem.base, 0, mem.size);
 	memset(&desc, 0, sizeof(desc));
 
-	dma_cmd = kzalloc(sizeof(*dma_cmd), GFP_KERNEL);
+	dma_cmd = kzalloc(sizeof(*dma_cmd), flag);
 	if (dma_cmd == NULL) {
 		IPAERR("Failed to alloc immediate command object\n");
 		dma_free_coherent(ipa_ctx->pdev,
@@ -2462,6 +2466,7 @@
 	struct ipa_desc desc = { 0 };
 	struct ipa_mem_buffer mem;
 	struct ipa_ip_v4_routing_init *v4_cmd = NULL;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	u32 *entry;
 	int i;
 	int rc = 0;
@@ -2486,7 +2491,7 @@
 		entry++;
 	}
 
-	v4_cmd = kzalloc(sizeof(*v4_cmd), GFP_KERNEL);
+	v4_cmd = kzalloc(sizeof(*v4_cmd), flag);
 	if (v4_cmd == NULL) {
 		IPAERR("Failed to alloc v4 routing init command object\n");
 		rc = -ENOMEM;
@@ -2522,6 +2527,7 @@
 	struct ipa_desc desc = { 0 };
 	struct ipa_mem_buffer mem;
 	struct ipa_ip_v6_routing_init *v6_cmd = NULL;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	u32 *entry;
 	int i;
 	int rc = 0;
@@ -2546,7 +2552,7 @@
 		entry++;
 	}
 
-	v6_cmd = kzalloc(sizeof(*v6_cmd), GFP_KERNEL);
+	v6_cmd = kzalloc(sizeof(*v6_cmd), flag);
 	if (v6_cmd == NULL) {
 		IPAERR("Failed to alloc v6 routing init command object\n");
 		rc = -ENOMEM;
@@ -2582,6 +2588,7 @@
 	struct ipa_desc desc = { 0 };
 	struct ipa_mem_buffer mem;
 	struct ipa_ip_v4_filter_init *v4_cmd = NULL;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	u32 *entry;
 	int i;
 	int rc = 0;
@@ -2604,7 +2611,7 @@
 		entry++;
 	}
 
-	v4_cmd = kzalloc(sizeof(*v4_cmd), GFP_KERNEL);
+	v4_cmd = kzalloc(sizeof(*v4_cmd), flag);
 	if (v4_cmd == NULL) {
 		IPAERR("Failed to alloc v4 fliter init command object\n");
 		rc = -ENOMEM;
@@ -2640,6 +2647,7 @@
 	struct ipa_desc desc = { 0 };
 	struct ipa_mem_buffer mem;
 	struct ipa_ip_v6_filter_init *v6_cmd = NULL;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	u32 *entry;
 	int i;
 	int rc = 0;
@@ -2662,7 +2670,7 @@
 		entry++;
 	}
 
-	v6_cmd = kzalloc(sizeof(*v6_cmd), GFP_KERNEL);
+	v6_cmd = kzalloc(sizeof(*v6_cmd), flag);
 	if (v6_cmd == NULL) {
 		IPAERR("Failed to alloc v6 fliter init command object\n");
 		rc = -ENOMEM;
@@ -3671,6 +3679,7 @@
 				 * pipe will be unsuspended as part of
 				 * enabling IPA clocks
 				 */
+				mutex_lock(&ipa_ctx->sps_pm.sps_pm_lock);
 				if (!atomic_read(
 					&ipa_ctx->sps_pm.dec_clients)
 					) {
@@ -3683,6 +3692,7 @@
 						1);
 					ipa_sps_process_irq_schedule_rel();
 				}
+				mutex_unlock(&ipa_ctx->sps_pm.sps_pm_lock);
 			} else {
 				resource = ipa2_get_rm_resource_from_ep(i);
 				res = ipa_rm_request_resource_with_timer(
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
index 3dca3e6..a822f66 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
@@ -322,8 +322,8 @@
 		dma_address = desc->dma_address;
 		tx_pkt->no_unmap_dma = true;
 	}
-	if (!dma_address) {
-		IPAERR("failed to DMA wrap\n");
+	if (dma_mapping_error(ipa_ctx->pdev, dma_address)) {
+		IPAERR("dma_map_single failed\n");
 		goto fail_dma_map;
 	}
 
@@ -445,7 +445,7 @@
 		}
 		dma_addr  = dma_map_single(ipa_ctx->pdev,
 				transfer.iovec, size, DMA_TO_DEVICE);
-		if (!dma_addr) {
+		if (dma_mapping_error(ipa_ctx->pdev, dma_addr)) {
 			IPAERR("dma_map_single failed for sps xfr buff\n");
 			kfree(transfer.iovec);
 			return -EFAULT;
@@ -493,6 +493,15 @@
 					tx_pkt->mem.base,
 					tx_pkt->mem.size,
 					DMA_TO_DEVICE);
+
+				if (dma_mapping_error(ipa_ctx->pdev,
+					tx_pkt->mem.phys_base)) {
+					IPAERR("dma_map_single ");
+					IPAERR("failed\n");
+					fail_dma_wrap = 1;
+					goto failure;
+				}
+
 			} else {
 				tx_pkt->mem.phys_base = desc[i].dma_address;
 				tx_pkt->no_unmap_dma = true;
@@ -1873,8 +1882,8 @@
 		rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev, ptr,
 						     sys->rx_buff_sz,
 						     DMA_FROM_DEVICE);
-		if (rx_pkt->data.dma_addr == 0 ||
-				rx_pkt->data.dma_addr == ~0) {
+		if (dma_mapping_error(ipa_ctx->pdev,
+				rx_pkt->data.dma_addr)) {
 			pr_err_ratelimited("%s dma map fail %p for %p sys=%p\n",
 			       __func__, (void *)rx_pkt->data.dma_addr,
 			       ptr, sys);
@@ -2029,18 +2038,20 @@
 		ptr = skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ);
 		rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev, ptr,
 				IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE);
-		if (rx_pkt->data.dma_addr == 0 ||
-				rx_pkt->data.dma_addr == ~0) {
+		if (dma_mapping_error(ipa_ctx->pdev,
+				rx_pkt->data.dma_addr)) {
 			IPAERR("dma_map_single failure %p for %p\n",
 			       (void *)rx_pkt->data.dma_addr, ptr);
 			goto fail_dma_mapping;
 		}
 
+		spin_lock_bh(&ipa_ctx->wc_memb.wlan_spinlock);
 		list_add_tail(&rx_pkt->link,
 			&ipa_ctx->wc_memb.wlan_comm_desc_list);
 		rx_len_cached = ++ipa_ctx->wc_memb.wlan_comm_total_cnt;
 
 		ipa_ctx->wc_memb.wlan_comm_free_cnt++;
+		spin_unlock_bh(&ipa_ctx->wc_memb.wlan_spinlock);
 
 	}
 
@@ -2101,8 +2112,8 @@
 		rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev, ptr,
 						     sys->rx_buff_sz,
 						     DMA_FROM_DEVICE);
-		if (rx_pkt->data.dma_addr == 0 ||
-				rx_pkt->data.dma_addr == ~0) {
+		if (dma_mapping_error(ipa_ctx->pdev,
+				rx_pkt->data.dma_addr)) {
 			IPAERR("dma_map_single failure %p for %p\n",
 			       (void *)rx_pkt->data.dma_addr, ptr);
 			goto fail_dma_mapping;
@@ -2159,9 +2170,10 @@
 		ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
 		rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev,
 			ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
-		if (rx_pkt->data.dma_addr == 0 ||
-			rx_pkt->data.dma_addr == ~0)
+		if (dma_mapping_error(ipa_ctx->pdev, rx_pkt->data.dma_addr)) {
+			IPAERR("dma_map_single failure for rx_pkt\n");
 			goto fail_dma_mapping;
+		}
 
 		list_add_tail(&rx_pkt->link, &sys->head_desc_list);
 		rx_len_cached = ++sys->len;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index e474a40..b60c7a6 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -1480,17 +1480,24 @@
 
 void ipa_delete_dflt_flt_rules(u32 ipa_ep_idx)
 {
+	struct ipa_flt_tbl *tbl;
 	struct ipa_ep_context *ep = &ipa_ctx->ep[ipa_ep_idx];
 
 	mutex_lock(&ipa_ctx->lock);
 	if (ep->dflt_flt4_rule_hdl) {
+		tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4];
 		__ipa_del_flt_rule(ep->dflt_flt4_rule_hdl);
 		ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v4);
+		/* Reset the sticky flag. */
+		tbl->sticky_rear = false;
 		ep->dflt_flt4_rule_hdl = 0;
 	}
 	if (ep->dflt_flt6_rule_hdl) {
+		tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6];
 		__ipa_del_flt_rule(ep->dflt_flt6_rule_hdl);
 		ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v6);
+		/* Reset the sticky flag. */
+		tbl->sticky_rear = false;
 		ep->dflt_flt6_rule_hdl = 0;
 	}
 	mutex_unlock(&ipa_ctx->lock);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
index 25f8923..046f77f 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
@@ -268,6 +268,7 @@
 	struct ipa_mem_buffer mem;
 	struct ipa_hdr_init_system *cmd = NULL;
 	struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd = NULL;
+	gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	int rc = -EFAULT;
 
 	if (ipa_generate_hdr_hw_tbl(&mem)) {
@@ -281,7 +282,7 @@
 				IPA_MEM_PART(apps_hdr_size));
 			goto fail_send_cmd;
 		} else {
-			dma_cmd = kzalloc(sizeof(*dma_cmd), GFP_ATOMIC);
+			dma_cmd = kzalloc(sizeof(*dma_cmd), flag);
 			if (dma_cmd == NULL) {
 				IPAERR("fail to alloc immediate cmd\n");
 				rc = -ENOMEM;
@@ -303,7 +304,7 @@
 				IPA_MEM_PART(apps_hdr_size_ddr));
 			goto fail_send_cmd;
 		} else {
-			cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+			cmd = kzalloc(sizeof(*cmd), flag);
 			if (cmd == NULL) {
 				IPAERR("fail to alloc hdr init cmd\n");
 				rc = -ENOMEM;
@@ -359,6 +360,7 @@
 	struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd_hdr = NULL;
 	struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd_ctx = NULL;
 	struct ipa_register_write *reg_write_cmd = NULL;
+	gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	int rc = -EFAULT;
 	u32 proc_ctx_size;
 	u32 proc_ctx_ofst;
@@ -383,7 +385,7 @@
 				IPA_MEM_PART(apps_hdr_size));
 			goto fail_send_cmd1;
 		} else {
-			dma_cmd_hdr = kzalloc(sizeof(*dma_cmd_hdr), GFP_ATOMIC);
+			dma_cmd_hdr = kzalloc(sizeof(*dma_cmd_hdr), flag);
 			if (dma_cmd_hdr == NULL) {
 				IPAERR("fail to alloc immediate cmd\n");
 				rc = -ENOMEM;
@@ -406,7 +408,7 @@
 			goto fail_send_cmd1;
 		} else {
 			hdr_init_cmd = kzalloc(sizeof(*hdr_init_cmd),
-				GFP_ATOMIC);
+				flag);
 			if (hdr_init_cmd == NULL) {
 				IPAERR("fail to alloc immediate cmd\n");
 				rc = -ENOMEM;
@@ -431,7 +433,7 @@
 			goto fail_send_cmd1;
 		} else {
 			dma_cmd_ctx = kzalloc(sizeof(*dma_cmd_ctx),
-				GFP_ATOMIC);
+				flag);
 			if (dma_cmd_ctx == NULL) {
 				IPAERR("fail to alloc immediate cmd\n");
 				rc = -ENOMEM;
@@ -456,7 +458,7 @@
 			goto fail_send_cmd1;
 		} else {
 			reg_write_cmd = kzalloc(sizeof(*reg_write_cmd),
-				GFP_ATOMIC);
+				flag);
 			if (reg_write_cmd == NULL) {
 				IPAERR("fail to alloc immediate cmd\n");
 				rc = -ENOMEM;
@@ -722,6 +724,11 @@
 				entry->hdr,
 				entry->hdr_len,
 				DMA_TO_DEVICE);
+			if (dma_mapping_error(ipa_ctx->pdev,
+				entry->phys_base)) {
+				IPAERR("dma_map_single failure for entry\n");
+				goto fail_dma_mapping;
+			}
 		}
 	} else {
 		entry->is_hdr_proc_ctx = false;
@@ -798,6 +805,8 @@
 	list_del(&entry->link);
 	dma_unmap_single(ipa_ctx->pdev, entry->phys_base,
 			entry->hdr_len, DMA_TO_DEVICE);
+fail_dma_mapping:
+	entry->is_hdr_proc_ctx = false;
 bad_hdr_len:
 	entry->cookie = 0;
 	kmem_cache_free(ipa_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 84849a2..21fdec0 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -695,6 +695,7 @@
 	struct ipa_mem_buffer head;
 	struct ipa_hw_imm_cmd_dma_shared_mem *cmd1 = NULL;
 	struct ipa_hw_imm_cmd_dma_shared_mem *cmd2 = NULL;
+	gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
 	u16 avail;
 	u32 num_modem_rt_index;
 	int rc = 0;
@@ -745,7 +746,7 @@
 	}
 
 	cmd1 = kzalloc(sizeof(struct ipa_hw_imm_cmd_dma_shared_mem),
-		GFP_KERNEL);
+		flag);
 	if (cmd1 == NULL) {
 		IPAERR("Failed to alloc immediate command object\n");
 		rc = -ENOMEM;
@@ -762,7 +763,7 @@
 
 	if (lcl) {
 		cmd2 = kzalloc(sizeof(struct ipa_hw_imm_cmd_dma_shared_mem),
-			GFP_KERNEL);
+			flag);
 		if (cmd2 == NULL) {
 			IPAERR("Failed to alloc immediate command object\n");
 			rc = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 83fd2b2..30f5712 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -3620,6 +3620,8 @@
 				 * pipe will be unsuspended as part of
 				 * enabling IPA clocks
 				 */
+				mutex_lock(&ipa3_ctx->transport_pm.
+					transport_pm_mutex);
 				if (!atomic_read(
 					&ipa3_ctx->transport_pm.dec_clients)
 					) {
@@ -3632,6 +3634,8 @@
 					1);
 					ipa3_process_irq_schedule_rel();
 				}
+				mutex_unlock(&ipa3_ctx->transport_pm.
+					transport_pm_mutex);
 			} else {
 				resource = ipa3_get_rm_resource_from_ep(i);
 				res =
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 3937cfe..89dd274 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -1004,6 +1004,7 @@
 	struct ipa3_ep_context *ep;
 	int empty;
 	int result;
+	int i;
 
 	if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
 	    ipa3_ctx->ep[clnt_hdl].valid == 0) {
@@ -1038,7 +1039,17 @@
 	if (IPA_CLIENT_IS_CONS(ep->client))
 		cancel_delayed_work_sync(&ep->sys->replenish_rx_work);
 	flush_workqueue(ep->sys->wq);
-	result = ipa3_stop_gsi_channel(clnt_hdl);
+	/* channel stop might fail on timeout if IPA is busy */
+	for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
+		result = ipa3_stop_gsi_channel(clnt_hdl);
+		if (result == GSI_STATUS_SUCCESS)
+			break;
+
+		if (result != -GSI_STATUS_AGAIN &&
+		    result != -GSI_STATUS_TIMED_OUT)
+			break;
+	}
+
 	if (result != GSI_STATUS_SUCCESS) {
 		IPAERR("GSI stop chan err: %d.\n", result);
 		ipa_assert();
@@ -3509,6 +3520,7 @@
 	if (!gsi_channel_props.ring_base_vaddr) {
 		IPAERR("fail to dma alloc %u bytes\n",
 			gsi_channel_props.ring_len);
+		result = -ENOMEM;
 		goto fail_alloc_channel_ring;
 	}
 	gsi_channel_props.ring_base_addr = dma_addr;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index 0cc1206..ff763c4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -1389,16 +1389,23 @@
 void ipa3_delete_dflt_flt_rules(u32 ipa_ep_idx)
 {
 	struct ipa3_ep_context *ep = &ipa3_ctx->ep[ipa_ep_idx];
+	struct ipa3_flt_tbl *tbl;
 
 	mutex_lock(&ipa3_ctx->lock);
 	if (ep->dflt_flt4_rule_hdl) {
+		tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4];
 		__ipa_del_flt_rule(ep->dflt_flt4_rule_hdl);
 		ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v4);
+		/* Reset the sticky flag. */
+		tbl->sticky_rear = false;
 		ep->dflt_flt4_rule_hdl = 0;
 	}
 	if (ep->dflt_flt6_rule_hdl) {
+		tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6];
 		__ipa_del_flt_rule(ep->dflt_flt6_rule_hdl);
 		ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v6);
+		/* Reset the sticky flag. */
+		tbl->sticky_rear = false;
 		ep->dflt_flt6_rule_hdl = 0;
 	}
 	mutex_unlock(&ipa3_ctx->lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 2ca33d8..3af4486 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1246,7 +1246,9 @@
  * Order and type of members should not be changed without a suitable change
  * to DTS file or the code that reads it.
  *
- * IPA v3.0 SRAM memory layout:
+ * IPA SRAM memory layout:
+ * +-------------------------+
+ * |    UC MEM               |
  * +-------------------------+
  * |    UC INFO              |
  * +-------------------------+
@@ -1314,10 +1316,14 @@
  * +-------------------------+
  * |    CANARY               |
  * +-------------------------+
+ * |    CANARY               |
+ * +-------------------------+
  * |  MODEM MEM              |
  * +-------------------------+
  * |    CANARY               |
  * +-------------------------+
+ * |  UC EVENT RING          | From IPA 3.5
+ * +-------------------------+
  */
 struct ipa3_mem_partition {
 	u32 ofst_start;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 5a38db3..f066d94 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4352,21 +4352,30 @@
 
 	memset(&mem, 0, sizeof(mem));
 
-	for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
-		IPADBG("Calling gsi_stop_channel\n");
+	if (IPA_CLIENT_IS_PROD(ep->client)) {
+		IPADBG("Calling gsi_stop_channel ch:%lu\n",
+			ep->gsi_chan_hdl);
 		res = gsi_stop_channel(ep->gsi_chan_hdl);
-		IPADBG("gsi_stop_channel returned %d\n", res);
+		IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+			ep->gsi_chan_hdl, res);
+		goto end_sequence;
+	}
+
+	for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
+		IPADBG("Calling gsi_stop_channel ch:%lu\n",
+			ep->gsi_chan_hdl);
+		res = gsi_stop_channel(ep->gsi_chan_hdl);
+		IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+			ep->gsi_chan_hdl, res);
 		if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT)
 			goto end_sequence;
 
-		if (IPA_CLIENT_IS_CONS(ep->client)) {
-			IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
-			/* Send a 1B packet DMA_TASK to IPA and try again */
-			res = ipa3_inject_dma_task_for_gsi();
-			if (res) {
-				IPAERR("Failed to inject DMA TASk for GSI\n");
-				goto end_sequence;
-			}
+		IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
+		/* Send a 1B packet DMA_TASK to IPA and try again */
+		res = ipa3_inject_dma_task_for_gsi();
+		if (res) {
+			IPAERR("Failed to inject DMA TASk for GSI\n");
+			goto end_sequence;
 		}
 
 		/* sleep for short period to flush IPA */
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index b985ecd..54bef52 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -434,23 +434,28 @@
 		return rc;
 	}
 
-	split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
-	pval.intval = slave_fcc_ua;
-	rc = power_supply_set_property(chip->pl_psy,
-			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
-	if (rc < 0) {
-		pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
-		return rc;
-	}
+	if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
+		split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
 
-	chip->slave_fcc_ua = slave_fcc_ua;
+		pval.intval = slave_fcc_ua;
+		rc = power_supply_set_property(chip->pl_psy,
+				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+				&pval);
+		if (rc < 0) {
+			pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
+			return rc;
+		}
 
-	pval.intval = master_fcc_ua;
-	rc = power_supply_set_property(chip->main_psy,
-			POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
-	if (rc < 0) {
-		pr_err("Could not set main fcc, rc=%d\n", rc);
-		return rc;
+		chip->slave_fcc_ua = slave_fcc_ua;
+
+		pval.intval = master_fcc_ua;
+		rc = power_supply_set_property(chip->main_psy,
+				POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+				&pval);
+		if (rc < 0) {
+			pr_err("Could not set main fcc, rc=%d\n", rc);
+			return rc;
+		}
 	}
 
 	pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
@@ -511,13 +516,14 @@
 	return 0;
 }
 
-#define ICL_STEP_UV	25000
+#define ICL_STEP_UA	25000
 static int usb_icl_vote_callback(struct votable *votable, void *data,
 			int icl_ua, const char *client)
 {
 	int rc;
 	struct pl_data *chip = data;
 	union power_supply_propval pval = {0, };
+	bool rerun_aicl = false;
 
 	if (!chip->main_psy)
 		return 0;
@@ -543,22 +549,28 @@
 	}
 
 	/* rerun AICL if new ICL is above settled ICL */
-	if (icl_ua > pval.intval) {
-		/* set a lower ICL */
-		pval.intval = max(pval.intval - ICL_STEP_UV, ICL_STEP_UV);
-		power_supply_set_property(chip->main_psy,
-				POWER_SUPPLY_PROP_CURRENT_MAX,
-				&pval);
-		/* wait for ICL change */
-		msleep(100);
+	if (icl_ua > pval.intval)
+		rerun_aicl = true;
 
-		pval.intval = icl_ua;
+	if (rerun_aicl) {
+		/* set a lower ICL */
+		pval.intval = max(pval.intval - ICL_STEP_UA, ICL_STEP_UA);
 		power_supply_set_property(chip->main_psy,
 				POWER_SUPPLY_PROP_CURRENT_MAX,
 				&pval);
 		/* wait for ICL change */
 		msleep(100);
 	}
+
+	/* set the effective ICL */
+	pval.intval = icl_ua;
+	power_supply_set_property(chip->main_psy,
+			POWER_SUPPLY_PROP_CURRENT_MAX,
+			&pval);
+	if (rerun_aicl)
+		/* wait for ICL change */
+		msleep(100);
+
 	vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0);
 
 	return 0;
@@ -678,9 +690,6 @@
 
 	chip->main_psy = power_supply_get_by_name("main");
 
-	if (chip->main_psy)
-		rerun_election(chip->usb_icl_votable);
-
 	return !!chip->main_psy;
 }
 
@@ -859,7 +868,18 @@
 	struct pl_data *chip = container_of(work,
 			struct pl_data, status_change_work);
 
-	if (!is_main_available(chip))
+	if (!chip->main_psy && is_main_available(chip)) {
+		/*
+		 * re-run election for FCC/FV/ICL once main_psy
+		 * is available to ensure all votes are reflected
+		 * on hardware
+		 */
+		rerun_election(chip->usb_icl_votable);
+		rerun_election(chip->fcc_votable);
+		rerun_election(chip->fv_votable);
+	}
+
+	if (!chip->main_psy)
 		return;
 
 	if (!is_batt_available(chip))
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index ca551a5a..5983b5c 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -128,11 +128,6 @@
 	FG_IRQ_MAX,
 };
 
-/* WA flags */
-enum {
-	DELTA_SOC_IRQ_WA = BIT(0),
-};
-
 /*
  * List of FG_SRAM parameters. Please add a parameter only if it is an entry
  * that will be used either to configure an entity (e.g. termination current)
@@ -152,6 +147,7 @@
 	FG_SRAM_CC_SOC,
 	FG_SRAM_CC_SOC_SW,
 	FG_SRAM_ACT_BATT_CAP,
+	FG_SRAM_TIMEBASE,
 	/* Entries below here are configurable during initialization */
 	FG_SRAM_CUTOFF_VOLT,
 	FG_SRAM_EMPTY_VOLT,
@@ -212,6 +208,7 @@
 
 enum wa_flags {
 	PMI8998_V1_REV_WA = BIT(0),
+	PM660_TSMC_OSC_WA = BIT(1),
 };
 
 enum slope_limit_status {
@@ -325,6 +322,23 @@
 	{ 128000,	4852 },
 };
 
+/* each tuple is - <temperature in degC, Timebase> */
+static const struct fg_pt fg_tsmc_osc_table[] = {
+	{ -20,		395064 },
+	{ -10,		398114 },
+	{   0,		401669 },
+	{  10,		404641 },
+	{  20,		408856 },
+	{  25,		412449 },
+	{  30,		416532 },
+	{  40,		420289 },
+	{  50,		425020 },
+	{  60,		430160 },
+	{  70,		434175 },
+	{  80,		439475 },
+	{  90,		444992 },
+};
+
 struct fg_chip {
 	struct device		*dev;
 	struct pmic_revid_data	*pmic_rev_id;
@@ -336,6 +350,7 @@
 	struct power_supply	*dc_psy;
 	struct power_supply	*parallel_psy;
 	struct iio_channel	*batt_id_chan;
+	struct iio_channel	*die_temp_chan;
 	struct fg_memif		*sram;
 	struct fg_irq_info	*irqs;
 	struct votable		*awake_votable;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index b42a65d..806460f 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -47,6 +47,7 @@
 #define ESR_UPD_TIGHT_LOW_TEMP_OFFSET	2
 #define ESR_UPD_BROAD_LOW_TEMP_OFFSET	3
 #define KI_COEFF_MED_DISCHG_WORD	9
+#define TIMEBASE_OFFSET			1
 #define KI_COEFF_MED_DISCHG_OFFSET	3
 #define KI_COEFF_HI_DISCHG_WORD		10
 #define KI_COEFF_HI_DISCHG_OFFSET	0
@@ -261,6 +262,8 @@
 		fg_decode_cc_soc),
 	PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
 		1, 1, 0, NULL, fg_decode_default),
+	PARAM(TIMEBASE, KI_COEFF_MED_DISCHG_WORD, TIMEBASE_OFFSET, 2, 1000,
+		61000, 0, fg_encode_default, NULL),
 	/* Entries below here are configurable during initialization */
 	PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
 		244141, 0, fg_encode_voltage, NULL),
@@ -1967,7 +1970,7 @@
 {
 	union power_supply_propval prop = {0, };
 	int rc;
-	bool parallel_en = false;
+	bool parallel_en = false, qnovo_en = false;
 
 	if (is_parallel_charger_available(chip)) {
 		rc = power_supply_get_property(chip->parallel_psy,
@@ -1980,19 +1983,25 @@
 		parallel_en = prop.intval;
 	}
 
-	fg_dbg(chip, FG_POWER_SUPPLY, "charge_status: %d parallel_en: %d esr_fcc_ctrl_en: %d\n",
-		chip->charge_status, parallel_en, chip->esr_fcc_ctrl_en);
+	rc = power_supply_get_property(chip->batt_psy,
+			POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, &prop);
+	if (!rc)
+		qnovo_en = prop.intval;
+
+	fg_dbg(chip, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n",
+		chip->charge_status, parallel_en, qnovo_en,
+		chip->esr_fcc_ctrl_en);
 
 	if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
-								parallel_en) {
+			(parallel_en || qnovo_en)) {
 		if (chip->esr_fcc_ctrl_en)
 			return 0;
 
 		/*
-		 * When parallel charging is enabled, configure ESR FCC to
-		 * 300mA to trigger an ESR pulse. Without this, FG can ask
-		 * the main charger to increase FCC when it is supposed to
-		 * decrease it.
+		 * When parallel charging or Qnovo is enabled, configure ESR
+		 * FCC to 300mA to trigger an ESR pulse. Without this, FG can
+		 * request the main charger to increase FCC when it is supposed
+		 * to decrease it.
 		 */
 		rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
 				ESR_FAST_CRG_IVAL_MASK |
@@ -2011,8 +2020,8 @@
 
 		/*
 		 * If we're here, then it means either the device is not in
-		 * charging state or parallel charging is disabled. Disable
-		 * ESR fast charge current control in SW.
+		 * charging state or parallel charging / Qnovo is disabled.
+		 * Disable ESR fast charge current control in SW.
 		 */
 		rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
 				ESR_FAST_CRG_CTL_EN_BIT, 0);
@@ -3365,6 +3374,40 @@
 	return fg_ima_init(chip);
 }
 
+static int fg_adjust_timebase(struct fg_chip *chip)
+{
+	int rc = 0, die_temp;
+	s32 time_base = 0;
+	u8 buf[2] = {0};
+
+	if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
+		rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
+		if (rc < 0) {
+			pr_err("Error in reading die_temp, rc:%d\n", rc);
+			return rc;
+		}
+
+		rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
+					die_temp / 1000, &time_base);
+		if (rc < 0) {
+			pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
+			return rc;
+		}
+
+		fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
+		rc = fg_sram_write(chip,
+			chip->sp[FG_SRAM_TIMEBASE].addr_word,
+			chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
+			chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
+		if (rc < 0) {
+			pr_err("Error in writing timebase, rc=%d\n", rc);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
 /* INTERRUPT HANDLERS STAY HERE */
 
 static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
@@ -3486,6 +3529,10 @@
 	chip->health = prop.intval;
 
 	if (chip->last_batt_temp != batt_temp) {
+		rc = fg_adjust_timebase(chip);
+		if (rc < 0)
+			pr_err("Error in adjusting timebase, rc=%d\n", rc);
+
 		chip->last_batt_temp = batt_temp;
 		power_supply_changed(chip->batt_psy);
 	}
@@ -3555,6 +3602,10 @@
 	if (rc < 0)
 		pr_err("Error in validating ESR, rc=%d\n", rc);
 
+	rc = fg_adjust_timebase(chip);
+	if (rc < 0)
+		pr_err("Error in adjusting timebase, rc=%d\n", rc);
+
 	if (batt_psy_initialized(chip))
 		power_supply_changed(chip->batt_psy);
 
@@ -3897,6 +3948,8 @@
 		chip->sp = pmi8998_v2_sram_params;
 		chip->alg_flags = pmi8998_v2_alg_flags;
 		chip->use_ima_single_mode = true;
+		if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
+			chip->wa_flags |= PM660_TSMC_OSC_WA;
 		break;
 	default:
 		return -EINVAL;
@@ -4238,6 +4291,21 @@
 		return rc;
 	}
 
+	rc = of_property_match_string(chip->dev->of_node,
+				"io-channel-names", "rradc_die_temp");
+	if (rc >= 0) {
+		chip->die_temp_chan = iio_channel_get(chip->dev,
+						"rradc_die_temp");
+		if (IS_ERR(chip->die_temp_chan)) {
+			if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
+				pr_err("rradc_die_temp unavailable %ld\n",
+					PTR_ERR(chip->die_temp_chan));
+			rc = PTR_ERR(chip->die_temp_chan);
+			chip->die_temp_chan = NULL;
+			return rc;
+		}
+	}
+
 	chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
 					chip);
 	if (IS_ERR(chip->awake_votable)) {
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index c74dc89..eb97eb0 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -89,7 +89,16 @@
 #define QNOVO_STRM_CTRL		0xA8
 #define QNOVO_IADC_OFFSET_OVR_VAL	0xA9
 #define QNOVO_IADC_OFFSET_OVR		0xAA
+
 #define QNOVO_DISABLE_CHARGING		0xAB
+#define ERR_SWITCHER_DISABLED		BIT(7)
+#define ERR_JEITA_SOFT_CONDITION	BIT(6)
+#define ERR_BAT_OV			BIT(5)
+#define ERR_CV_MODE			BIT(4)
+#define ERR_BATTERY_MISSING		BIT(3)
+#define ERR_SAFETY_TIMER_EXPIRED	BIT(2)
+#define ERR_CHARGING_DISABLED		BIT(1)
+#define ERR_JEITA_HARD_CONDITION	BIT(0)
 
 #define QNOVO_TR_IADC_OFFSET_0	0xF1
 #define QNOVO_TR_IADC_OFFSET_1	0xF2
@@ -1107,24 +1116,28 @@
 {
 	u8 val = 0;
 	int rc;
-	bool charging;
+	bool ok_to_qnovo;
 	bool changed = false;
 
 	rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1);
 	if (rc < 0) {
 		pr_err("Couldn't read error sts rc = %d\n", rc);
-		charging = false;
+		ok_to_qnovo = false;
 	} else {
-		charging = !(val & QNOVO_ERROR_CHARGING_DISABLED);
+		/*
+		 * For CV mode keep qnovo enabled, userspace is expected to
+		 * disable it after few runs
+		 */
+		ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? true : false;
 	}
 
-	if (chip->ok_to_qnovo ^ charging) {
+	if (chip->ok_to_qnovo ^ ok_to_qnovo) {
 
-		vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !charging, 0);
-		if (!charging)
+		vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !ok_to_qnovo, 0);
+		if (!ok_to_qnovo)
 			vote(chip->disable_votable, USER_VOTER, true, 0);
 
-		chip->ok_to_qnovo = charging;
+		chip->ok_to_qnovo = ok_to_qnovo;
 		changed = true;
 	}
 
@@ -1247,6 +1260,16 @@
 	chip->v_gain_mega = 1000000000 + (s64)(s8)vadc_gain * GAIN_LSB_FACTOR;
 	chip->v_gain_mega = div_s64(chip->v_gain_mega, 1000);
 
+	/* allow charger error conditions to disable qnovo, CV mode excluded */
+	val = ERR_SWITCHER_DISABLED | ERR_JEITA_SOFT_CONDITION | ERR_BAT_OV |
+		ERR_BATTERY_MISSING | ERR_SAFETY_TIMER_EXPIRED |
+		ERR_CHARGING_DISABLED | ERR_JEITA_HARD_CONDITION;
+	rc = qnovo_write(chip, QNOVO_DISABLE_CHARGING, &val, 1);
+	if (rc < 0) {
+		pr_err("Couldn't write QNOVO_DISABLE_CHARGING rc = %d\n", rc);
+		return rc;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 8fd45f18..e802fbd 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -244,6 +244,8 @@
 	int	boost_threshold_ua;
 	int	fv_uv;
 	int	wipower_max_uw;
+	int	min_freq_khz;
+	int	max_freq_khz;
 	u32	step_soc_threshold[STEP_CHARGING_MAX_STEPS - 1];
 	s32	step_cc_delta[STEP_CHARGING_MAX_STEPS];
 	struct	device_node *revid_dev_node;
@@ -338,6 +340,18 @@
 	if (rc < 0)
 		chip->dt.boost_threshold_ua = MICRO_P1A;
 
+	rc = of_property_read_u32(node,
+				"qcom,min-freq-khz",
+				&chip->dt.min_freq_khz);
+	if (rc < 0)
+		chip->dt.min_freq_khz = -EINVAL;
+
+	rc = of_property_read_u32(node,
+				"qcom,max-freq-khz",
+				&chip->dt.max_freq_khz);
+	if (rc < 0)
+		chip->dt.max_freq_khz = -EINVAL;
+
 	rc = of_property_read_u32(node, "qcom,wipower-max-uw",
 				&chip->dt.wipower_max_uw);
 	if (rc < 0)
@@ -526,6 +540,12 @@
 	struct smb_charger *chg = &chip->chg;
 	int rc = 0;
 
+	mutex_lock(&chg->lock);
+	if (!chg->typec_present) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
 	switch (psp) {
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
 		rc = smblib_set_prop_usb_voltage_min(chg, val);
@@ -564,6 +584,8 @@
 		break;
 	}
 
+unlock:
+	mutex_unlock(&chg->lock);
 	return rc;
 }
 
@@ -1336,10 +1358,12 @@
 		return rc;
 	}
 
-	/* disable try.SINK mode */
-	rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT, 0);
+	/* disable try.SINK mode and legacy cable IRQs */
+	rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT |
+				TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT |
+				TYPEC_LEGACY_CABLE_INT_EN_BIT, 0);
 	if (rc < 0) {
-		dev_err(chg->dev, "Couldn't set TRYSINK_MODE rc=%d\n", rc);
+		dev_err(chg->dev, "Couldn't set Type-C config rc=%d\n", rc);
 		return rc;
 	}
 
@@ -1438,6 +1462,16 @@
 		smblib_get_charge_param(chg, &chg->param.dc_icl,
 					&chip->dt.dc_icl_ua);
 
+	if (chip->dt.min_freq_khz > 0) {
+		chg->param.freq_buck.min_u = chip->dt.min_freq_khz;
+		chg->param.freq_boost.min_u = chip->dt.min_freq_khz;
+	}
+
+	if (chip->dt.max_freq_khz > 0) {
+		chg->param.freq_buck.max_u = chip->dt.max_freq_khz;
+		chg->param.freq_boost.max_u = chip->dt.max_freq_khz;
+	}
+
 	/* set a slower soft start setting for OTG */
 	rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG2_REG,
 				ENG_SSUPPLY_IVREF_OTG_SS_MASK, OTG_SS_SLOW);
@@ -1485,6 +1519,8 @@
 		DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
 	vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
 			true, 0);
+	vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
+			true, 0);
 	vote(chg->hvdcp_disable_votable_indirect, DEFAULT_VOTER,
 		chip->dt.hvdcp_disable, 0);
 	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
@@ -2022,6 +2058,16 @@
 	return rc;
 }
 
+static void smb2_disable_interrupts(struct smb_charger *chg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(smb2_irqs); i++) {
+		if (smb2_irqs[i].irq > 0)
+			disable_irq(smb2_irqs[i].irq);
+	}
+}
+
 #if defined(CONFIG_DEBUG_FS)
 
 static int force_batt_psy_update_write(void *data, u64 val)
@@ -2233,7 +2279,7 @@
 	rc = smblib_get_prop_batt_health(chg, &val);
 	if (rc < 0) {
 		pr_err("Couldn't get batt health rc=%d\n", rc);
-		goto cleanup;
+		val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
 	}
 	batt_health = val.intval;
 
@@ -2284,6 +2330,9 @@
 	struct smb2 *chip = platform_get_drvdata(pdev);
 	struct smb_charger *chg = &chip->chg;
 
+	/* disable all interrupts */
+	smb2_disable_interrupts(chg);
+
 	/* configure power role for UFP */
 	smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
 				TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index c8deedd..7d5a8bd 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -542,30 +542,6 @@
 		smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
 }
 
-static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg)
-{
-	const struct apsd_result *apsd_result;
-
-	/*
-	 * PD_INACTIVE_VOTER on hvdcp_disable_votable indicates whether
-	 * apsd rerun was tried earlier
-	 */
-	if (get_client_vote(chg->hvdcp_disable_votable_indirect,
-						PD_INACTIVE_VOTER)) {
-		vote(chg->hvdcp_disable_votable_indirect,
-				PD_INACTIVE_VOTER, false, 0);
-		/* ensure hvdcp is enabled */
-		if (!get_effective_result(
-				chg->hvdcp_disable_votable_indirect)) {
-			apsd_result = smblib_get_apsd_result(chg);
-			if (apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT)) {
-				smblib_rerun_apsd(chg);
-			}
-		}
-	}
-	return 0;
-}
-
 static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
 {
 	const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
@@ -684,6 +660,7 @@
 	chg->voltage_max_uv = MICRO_5V;
 	chg->usb_icl_delta_ua = 0;
 	chg->pulse_cnt = 0;
+	chg->uusb_apsd_rerun_done = false;
 
 	/* clear USB ICL vote for USB_PSY_VOTER */
 	rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
@@ -751,6 +728,7 @@
 				rc);
 	}
 
+	chg->uusb_apsd_rerun_done = true;
 	smblib_rerun_apsd(chg);
 
 	return 0;
@@ -1020,6 +998,7 @@
 	struct smb_charger *chg = data;
 	int rc;
 	u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
+	u8 stat;
 
 	/* vote to enable/disable HW autonomous INOV */
 	vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
@@ -1041,6 +1020,16 @@
 		return rc;
 	}
 
+	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
+		return rc;
+	}
+
+	/* re-run APSD if HVDCP was detected */
+	if (stat & QC_CHARGER_BIT)
+		smblib_rerun_apsd(chg);
+
 	return 0;
 }
 
@@ -1134,6 +1123,22 @@
 	return 0;
 }
 
+static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
+				void *data, int disable, const char *client)
+{
+	struct smb_charger *chg = data;
+
+	if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
+		return 0;
+
+	if (disable)
+		disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
+	else
+		enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
+
+	return 0;
+}
+
 /*******************
  * VCONN REGULATOR *
  * *****************/
@@ -1142,7 +1147,7 @@
 static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
 {
 	struct smb_charger *chg = rdev_get_drvdata(rdev);
-	u8 otg_stat, stat4;
+	u8 otg_stat, val;
 	int rc = 0, i;
 
 	if (!chg->external_vconn) {
@@ -1173,17 +1178,12 @@
 	 * VCONN_EN_ORIENTATION is overloaded with overriding the CC pin used
 	 * for Vconn, and it should be set with reverse polarity of CC_OUT.
 	 */
-	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
-		return rc;
-	}
-
 	smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
-	stat4 = stat4 & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
+	val = chg->typec_status[3] &
+			CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
 	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
 				 VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
-				 VCONN_EN_VALUE_BIT | stat4);
+				 VCONN_EN_VALUE_BIT | val);
 	if (rc < 0) {
 		smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
 		return rc;
@@ -1531,6 +1531,21 @@
 		break;
 	}
 
+	if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
+		return 0;
+
+	rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+				rc);
+			return rc;
+		}
+
+	stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
+		 ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
+	if (!stat)
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
 	return 0;
 }
 
@@ -2131,23 +2146,13 @@
 int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
 					 union power_supply_propval *val)
 {
-	int rc = 0;
-	u8 stat;
-
-	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
-		return rc;
-	}
-	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
-		   stat);
-
-	if (stat & CC_ATTACHED_BIT)
-		val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
+	if (chg->typec_status[3] & CC_ATTACHED_BIT)
+		val->intval =
+			(bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
 	else
 		val->intval = 0;
 
-	return rc;
+	return 0;
 }
 
 static const char * const smblib_typec_mode_name[] = {
@@ -2165,17 +2170,7 @@
 
 static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
 {
-	int rc;
-	u8 stat;
-
-	rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
-		return POWER_SUPPLY_TYPEC_NONE;
-	}
-	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
-
-	switch (stat) {
+	switch (chg->typec_status[0]) {
 	case 0:
 		return POWER_SUPPLY_TYPEC_NONE;
 	case UFP_TYPEC_RDSTD_BIT:
@@ -2193,17 +2188,7 @@
 
 static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
 {
-	int rc;
-	u8 stat;
-
-	rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
-		return POWER_SUPPLY_TYPEC_NONE;
-	}
-	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
-
-	switch (stat & DFP_TYPEC_MASK) {
+	switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
 	case DFP_RA_RA_BIT:
 		return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
 	case DFP_RD_RD_BIT:
@@ -2224,28 +2209,17 @@
 int smblib_get_prop_typec_mode(struct smb_charger *chg,
 			       union power_supply_propval *val)
 {
-	int rc;
-	u8 stat;
-
-	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+	if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
 		val->intval = POWER_SUPPLY_TYPEC_NONE;
-		return rc;
-	}
-	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
-
-	if (!(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
-		val->intval = POWER_SUPPLY_TYPEC_NONE;
-		return rc;
+		return 0;
 	}
 
-	if (stat & UFP_DFP_MODE_STATUS_BIT)
+	if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
 		val->intval = smblib_get_prop_dfp_mode(chg);
 	else
 		val->intval = smblib_get_prop_ufp_mode(chg);
 
-	return rc;
+	return 0;
 }
 
 int smblib_get_prop_typec_power_role(struct smb_charger *chg,
@@ -2337,16 +2311,7 @@
 int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
 			       union power_supply_propval *val)
 {
-	int rc;
-	u8 ctrl;
-
-	rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG rc=%d\n",
-			rc);
-		return rc;
-	}
-	val->intval = ctrl & EXIT_SNK_BASED_ON_CC_BIT;
+	val->intval = chg->pd_hard_reset;
 	return 0;
 }
 
@@ -2542,53 +2507,60 @@
 			      const union power_supply_propval *val)
 {
 	int rc;
-	u8 stat = 0;
-	bool cc_debounced;
-	bool orientation;
-	bool pd_active = val->intval;
+	bool orientation, cc_debounced, sink_attached, hvdcp;
+	u8 stat;
 
-	if (!get_effective_result(chg->pd_allowed_votable)) {
-		smblib_err(chg, "PD is not allowed\n");
+	if (!get_effective_result(chg->pd_allowed_votable))
 		return -EINVAL;
-	}
 
-	vote(chg->apsd_disable_votable, PD_VOTER, pd_active, 0);
-	vote(chg->pd_allowed_votable, PD_VOTER, pd_active, 0);
-	vote(chg->usb_irq_enable_votable, PD_VOTER, pd_active, 0);
-
-	/*
-	 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line
-	 * when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override) is set
-	 * or when VCONN_EN_VALUE_BIT is set.
-	 */
-	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
 	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+		smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
 		return rc;
 	}
 
-	if (pd_active) {
-		orientation = stat & CC_ORIENTATION_BIT;
+	cc_debounced = (bool)
+		(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
+	sink_attached = (bool)
+		(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
+	hvdcp = stat & QC_CHARGER_BIT;
+
+	chg->pd_active = val->intval;
+	if (chg->pd_active) {
+		vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
+		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+		vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+
+		/*
+		 * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
+		 * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
+		 * is set or when VCONN_EN_VALUE_BIT is set.
+		 */
+		orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
 		rc = smblib_masked_write(chg,
 				TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
 				VCONN_EN_ORIENTATION_BIT,
 				orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
-		if (rc < 0) {
+		if (rc < 0)
 			smblib_err(chg,
 				"Couldn't enable vconn on CC line rc=%d\n", rc);
-			return rc;
-		}
+
+		/* SW controlled CC_OUT */
+		rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+				TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
+									rc);
+
 		/*
 		 * Enforce 500mA for PD until the real vote comes in later.
 		 * It is guaranteed that pd_active is set prior to
 		 * pd_current_max
 		 */
 		rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
-		if (rc < 0) {
+		if (rc < 0)
 			smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
-					rc);
-			return rc;
-		}
+									rc);
 
 		/* since PD was found the cable must be non-legacy */
 		vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
@@ -2596,36 +2568,40 @@
 		/* clear USB ICL vote for DCP_VOTER */
 		rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
 		if (rc < 0)
-			smblib_err(chg,
-				"Couldn't un-vote DCP from USB ICL rc=%d\n",
-				rc);
+			smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
+									rc);
 
 		/* remove USB_PSY_VOTER */
 		rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
-		if (rc < 0) {
+		if (rc < 0)
 			smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
-			return rc;
-		}
+	} else {
+		vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
+		vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+		vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+		vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
+								false, 0);
+
+		/* HW controlled CC_OUT */
+		rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+							TYPEC_SPARE_CFG_BIT, 0);
+		if (rc < 0)
+			smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
+									rc);
+
+		/*
+		 * This WA should only run for HVDCP. Non-legacy SDP/CDP could
+		 * draw more, but this WA will remove Rd causing VBUS to drop,
+		 * and data could be interrupted. Non-legacy DCP could also draw
+		 * more, but it may impact compliance.
+		 */
+		if (!chg->typec_legacy_valid && cc_debounced &&
+							!sink_attached && hvdcp)
+			schedule_work(&chg->legacy_detection_work);
 	}
 
-	/* CC pin selection s/w override in PD session; h/w otherwise. */
-	rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
-				 TYPEC_SPARE_CFG_BIT,
-				 pd_active ? TYPEC_SPARE_CFG_BIT : 0);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't change cc_out ctrl to %s rc=%d\n",
-			pd_active ? "SW" : "HW", rc);
-		return rc;
-	}
-
-	cc_debounced = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
-	if (!pd_active && cc_debounced)
-		try_rerun_apsd_for_hvdcp(chg);
-
-	chg->pd_active = pd_active;
 	smblib_update_usb_type(chg);
 	power_supply_changed(chg->usb_psy);
-
 	return rc;
 }
 
@@ -2728,88 +2704,70 @@
 
 static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
 {
-	int rc = 0;
-	union power_supply_propval cc2_val = {0, };
+	int rc, ccout, ufp_mode;
+	u8 stat;
 
 	if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
-		return rc;
+		return 0;
 
-	if (chg->cc2_sink_detach_flag != CC2_SINK_NONE)
-		return rc;
+	if (chg->cc2_detach_wa_active)
+		return 0;
 
-	rc = smblib_get_prop_typec_cc_orientation(chg, &cc2_val);
+	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
 	if (rc < 0) {
-		smblib_err(chg, "Couldn't get cc orientation rc=%d\n", rc);
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
 		return rc;
 	}
-	if (cc2_val.intval == 1)
-		return rc;
+	ccout = (stat & CC_ATTACHED_BIT) ?
+					(!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
+	ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
+					!(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
 
-	rc = smblib_get_prop_typec_mode(chg, &cc2_val);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
-		return rc;
-	}
+	if (ccout != 2)
+		return 0;
 
-	switch (cc2_val.intval) {
-	case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
-		smblib_reg_block_update(chg, cc2_detach_settings);
-		chg->cc2_sink_detach_flag = CC2_SINK_STD;
-		schedule_work(&chg->rdstd_cc2_detach_work);
-		break;
-	case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
-	case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
-		chg->cc2_sink_detach_flag = CC2_SINK_MEDIUM_HIGH;
-		break;
-	default:
-		break;
-	}
+	if (!ufp_mode)
+		return 0;
 
+	chg->cc2_detach_wa_active = true;
+	/* The CC2 removal WA will cause a type-c-change IRQ storm */
+	smblib_reg_block_update(chg, cc2_detach_settings);
+	schedule_work(&chg->rdstd_cc2_detach_work);
 	return rc;
 }
 
 static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
 {
-	int rc = 0;
-
 	if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
-		return rc;
+		return 0;
 
-	if (chg->cc2_sink_detach_flag == CC2_SINK_STD) {
-		cancel_work_sync(&chg->rdstd_cc2_detach_work);
-		smblib_reg_block_restore(chg, cc2_detach_settings);
-	}
+	if (!chg->cc2_detach_wa_active)
+		return 0;
 
-	chg->cc2_sink_detach_flag = CC2_SINK_NONE;
-
-	return rc;
+	chg->cc2_detach_wa_active = false;
+	cancel_work_sync(&chg->rdstd_cc2_detach_work);
+	smblib_reg_block_restore(chg, cc2_detach_settings);
+	return 0;
 }
 
 int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
 				const union power_supply_propval *val)
 {
-	int rc;
+	int rc = 0;
 
+	if (chg->pd_hard_reset == val->intval)
+		return rc;
+
+	chg->pd_hard_reset = val->intval;
 	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
-				 EXIT_SNK_BASED_ON_CC_BIT,
-				 (val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
-	if (rc < 0) {
-		smblib_err(chg, "Could not set EXIT_SNK_BASED_ON_CC rc=%d\n",
+			EXIT_SNK_BASED_ON_CC_BIT,
+			(chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
 				rc);
-		return rc;
-	}
 
-	vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0);
-
-	if (val->intval)
-		rc = smblib_cc2_sink_removal_enter(chg);
-	else
-		rc = smblib_cc2_sink_removal_exit(chg);
-
-	if (rc < 0) {
-		smblib_err(chg, "Could not detect cc2 removal rc=%d\n", rc);
-		return rc;
-	}
+	vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
+							chg->pd_hard_reset, 0);
 
 	return rc;
 }
@@ -3116,25 +3074,43 @@
 	return IRQ_HANDLED;
 }
 
-#define PL_DELAY_MS			30000
-irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
+static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
 {
-	struct smb_irq_data *irq_data = data;
-	struct smb_charger *chg = irq_data->parent_data;
+	if (vbus_rising) {
+		/* use the typec flag even though its not typec */
+		chg->typec_present = 1;
+	} else {
+		chg->typec_present = 0;
+		smblib_update_usb_type(chg);
+		extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
+		smblib_uusb_removal(chg);
+	}
+}
+
+static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+{
+	if (vbus_rising)
+		smblib_cc2_sink_removal_exit(chg);
+	else
+		smblib_cc2_sink_removal_enter(chg);
+}
+
+#define PL_DELAY_MS			30000
+void smblib_usb_plugin_locked(struct smb_charger *chg)
+{
 	int rc;
 	u8 stat;
 	bool vbus_rising;
 
 	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
 	if (rc < 0) {
-		dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
-		return IRQ_HANDLED;
+		smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+		return;
 	}
 
 	vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
-	smblib_set_opt_freq_buck(chg,
-		vbus_rising ? chg->chg_freq.freq_5V :
-			chg->chg_freq.freq_removal);
+	smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
+						chg->chg_freq.freq_removal);
 
 	/* fetch the DPDM regulator */
 	if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
@@ -3171,17 +3147,26 @@
 				smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
 					rc);
 		}
-
-		if (chg->micro_usb_mode) {
-			smblib_update_usb_type(chg);
-			extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
-			smblib_uusb_removal(chg);
-		}
 	}
 
+	if (chg->micro_usb_mode)
+		smblib_micro_usb_plugin(chg, vbus_rising);
+	else
+		smblib_typec_usb_plugin(chg, vbus_rising);
+
 	power_supply_changed(chg->usb_psy);
-	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
-		irq_data->name, vbus_rising ? "attached" : "detached");
+	smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+					vbus_rising ? "attached" : "detached");
+}
+
+irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
+{
+	struct smb_irq_data *irq_data = data;
+	struct smb_charger *chg = irq_data->parent_data;
+
+	mutex_lock(&chg->lock);
+	smblib_usb_plugin_locked(chg);
+	mutex_unlock(&chg->lock);
 	return IRQ_HANDLED;
 }
 
@@ -3350,9 +3335,6 @@
 	if (rising) {
 		vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
 								false, 0);
-		if (get_effective_result(chg->pd_disallowed_votable_indirect))
-			/* could be a legacy cable, try doing hvdcp */
-			try_rerun_apsd_for_hvdcp(chg);
 
 		/* enable HDC and ICL irq for QC2/3 charger */
 		if (qc_charger)
@@ -3387,6 +3369,10 @@
 
 static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
 {
+	/* while PD is active it should have complete ICL control */
+	if (chg->pd_active)
+		return;
+
 	switch (pst) {
 	case POWER_SUPPLY_TYPE_USB:
 		/*
@@ -3426,7 +3412,7 @@
 
 	apsd_result = smblib_update_usb_type(chg);
 
-	if (!chg->pd_active)
+	if (!chg->typec_legacy_valid)
 		smblib_force_legacy_icl(chg, apsd_result->pst);
 
 	switch (apsd_result->bit) {
@@ -3472,6 +3458,17 @@
 	}
 	smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
 
+	if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
+			&& !chg->uusb_apsd_rerun_done) {
+		/*
+		 * Force re-run APSD to handle slow insertion related
+		 * charger-mis-detection.
+		 */
+		chg->uusb_apsd_rerun_done = true;
+		smblib_rerun_apsd(chg);
+		return IRQ_HANDLED;
+	}
+
 	smblib_handle_apsd_done(chg,
 		(bool)(stat & APSD_DTC_STATUS_DONE_BIT));
 
@@ -3505,71 +3502,6 @@
 	return IRQ_HANDLED;
 }
 
-static void typec_source_removal(struct smb_charger *chg)
-{
-	int rc;
-
-	/* reset legacy unknown vote */
-	vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
-
-	/* reset both usbin current and voltage votes */
-	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
-	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
-
-	cancel_delayed_work_sync(&chg->hvdcp_detect_work);
-
-	if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
-		/* re-enable AUTH_IRQ_EN_CFG_BIT */
-		rc = smblib_masked_write(chg,
-				USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
-				AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
-		if (rc < 0)
-			smblib_err(chg,
-				"Couldn't enable QC auth setting rc=%d\n", rc);
-	}
-
-	/* reconfigure allowed voltage for HVDCP */
-	rc = smblib_set_adapter_allowance(chg,
-			USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
-			rc);
-
-	chg->voltage_min_uv = MICRO_5V;
-	chg->voltage_max_uv = MICRO_5V;
-
-	/* clear USB ICL vote for PD_VOTER */
-	rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
-	if (rc < 0)
-		smblib_err(chg, "Couldn't un-vote PD from USB ICL rc=%d\n", rc);
-
-	/* clear USB ICL vote for USB_PSY_VOTER */
-	rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
-	if (rc < 0)
-		smblib_err(chg,
-			"Couldn't un-vote USB_PSY from USB ICL rc=%d\n", rc);
-
-	/* clear USB ICL vote for DCP_VOTER */
-	rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
-	if (rc < 0)
-		smblib_err(chg,
-			"Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
-
-}
-
-static void typec_source_insertion(struct smb_charger *chg)
-{
-	/*
-	 * at any time we want LEGACY_UNKNOWN, PD, or USB_PSY to be voting for
-	 * ICL, so vote LEGACY_UNKNOWN here if none of the above three have
-	 * casted their votes
-	 */
-	if (!is_client_vote_enabled(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER)
-		&& !is_client_vote_enabled(chg->usb_icl_votable, PD_VOTER)
-		&& !is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER))
-		vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
-}
-
 static void typec_sink_insertion(struct smb_charger *chg)
 {
 	/* when a sink is inserted we should not wait on hvdcp timeout to
@@ -3590,30 +3522,50 @@
 {
 	int rc;
 
-	cancel_delayed_work_sync(&chg->pl_enable_work);
-	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
-	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+	chg->cc2_detach_wa_active = false;
 
+	/* reset APSD voters */
+	vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+	vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
+
+	cancel_delayed_work_sync(&chg->pl_enable_work);
+	cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+
+	/* reset input current limit voters */
+	vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
+	vote(chg->usb_icl_votable, PD_VOTER, false, 0);
+	vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+	vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+	vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+
+	/* reset hvdcp voters */
+	vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
+	vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
+
+	/* reset power delivery voters */
+	vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
 	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
 	vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
+
+	/* reset usb irq voters */
 	vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
 	vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
 
-	/* reset votes from vbus_cc_short */
-	vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
-			true, 0);
-	vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
-			true, 0);
-	/*
-	 * cable could be removed during hard reset, remove its vote to
-	 * disable apsd
-	 */
-	vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+	/* reset parallel voters */
+	vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
 
 	chg->vconn_attempts = 0;
 	chg->otg_attempts = 0;
 	chg->pulse_cnt = 0;
 	chg->usb_icl_delta_ua = 0;
+	chg->voltage_min_uv = MICRO_5V;
+	chg->voltage_max_uv = MICRO_5V;
+	chg->pd_active = 0;
+	chg->pd_hard_reset = 0;
+	chg->typec_legacy_valid = false;
 
 	/* enable APSD CC trigger for next insertion */
 	rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
@@ -3621,15 +3573,48 @@
 	if (rc < 0)
 		smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
 
-	smblib_update_usb_type(chg);
-	typec_source_removal(chg);
+	if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
+		/* re-enable AUTH_IRQ_EN_CFG_BIT */
+		rc = smblib_masked_write(chg,
+				USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
+				AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
+		if (rc < 0)
+			smblib_err(chg,
+				"Couldn't enable QC auth setting rc=%d\n", rc);
+	}
+
+	/* reconfigure allowed voltage for HVDCP */
+	rc = smblib_set_adapter_allowance(chg,
+			USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+			rc);
+
+	/* enable DRP */
+	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+				 TYPEC_POWER_ROLE_CMD_MASK, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+
+	/* HW controlled CC_OUT */
+	rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+							TYPEC_SPARE_CFG_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
+
+	/* restore crude sensor */
+	rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
+
 	typec_sink_removal(chg);
+	smblib_update_usb_type(chg);
 }
 
 static void smblib_handle_typec_insertion(struct smb_charger *chg,
-		bool sink_attached, bool legacy_cable)
+							bool sink_attached)
 {
-	int rp, rc;
+	int rc;
 
 	vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
 
@@ -3639,59 +3624,36 @@
 		smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
 									rc);
 
-	if (sink_attached) {
-		typec_source_removal(chg);
+	if (sink_attached)
 		typec_sink_insertion(chg);
-	} else {
-		typec_source_insertion(chg);
+	else
 		typec_sink_removal(chg);
-	}
-
-	rp = smblib_get_prop_ufp_mode(chg);
-	if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH
-			|| rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) {
-		smblib_dbg(chg, PR_MISC, "VBUS & CC could be shorted; keeping HVDCP disabled\n");
-		vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
-								true, 0);
-	} else {
-		vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
-								false, 0);
-	}
 }
 
 static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
-			bool rising, bool sink_attached, bool legacy_cable)
+						bool rising, bool sink_attached)
 {
 	int rc;
 	union power_supply_propval pval = {0, };
 
-	if (rising)
-		smblib_handle_typec_insertion(chg, sink_attached, legacy_cable);
-	else
-		smblib_handle_typec_removal(chg);
+	if (rising) {
+		if (!chg->typec_present) {
+			chg->typec_present = true;
+			smblib_dbg(chg, PR_MISC,  "TypeC insertion\n");
+			smblib_handle_typec_insertion(chg, sink_attached);
+		}
+	} else {
+		if (chg->typec_present) {
+			chg->typec_present = false;
+			smblib_dbg(chg, PR_MISC,  "TypeC removal\n");
+			smblib_handle_typec_removal(chg);
+		}
+	}
 
 	rc = smblib_get_prop_typec_mode(chg, &pval);
 	if (rc < 0)
 		smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
 
-	/*
-	 * HW BUG - after cable is removed, medium or high rd reading
-	 * falls to std. Use it for signal of typec cc detachment in
-	 * software WA.
-	 */
-	if (chg->cc2_sink_detach_flag == CC2_SINK_MEDIUM_HIGH
-		&& pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
-
-		chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
-
-		rc = smblib_masked_write(chg,
-				TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
-				EXIT_SNK_BASED_ON_CC_BIT, 0);
-		if (rc < 0)
-			smblib_err(chg, "Couldn't get prop typec mode rc=%d\n",
-				rc);
-	}
-
 	smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
 		   rising ? "rising" : "falling",
 		   smblib_typec_mode_name[pval.intval]);
@@ -3717,50 +3679,54 @@
 	return IRQ_HANDLED;
 }
 
+static void smblib_usb_typec_change(struct smb_charger *chg)
+{
+	int rc;
+	bool debounce_done, sink_attached;
+
+	rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
+							chg->typec_status, 5);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
+		return;
+	}
+
+	debounce_done =
+		(bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
+	sink_attached =
+		(bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
+
+	smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
+
+	if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
+		smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
+
+	if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
+		schedule_work(&chg->vconn_oc_work);
+
+	power_supply_changed(chg->usb_psy);
+}
+
 irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
 {
 	struct smb_irq_data *irq_data = data;
 	struct smb_charger *chg = irq_data->parent_data;
-	int rc;
-	u8 stat4, stat5;
-	bool debounce_done, sink_attached, legacy_cable;
 
-	if (chg->micro_usb_mode)
-		return smblib_handle_usb_typec_change_for_uusb(chg);
-
-	/* WA - not when PD hard_reset WIP on cc2 in sink mode */
-	if (chg->cc2_sink_detach_flag == CC2_SINK_STD)
-		return IRQ_HANDLED;
-
-	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+	if (chg->micro_usb_mode) {
+		smblib_handle_usb_typec_change_for_uusb(chg);
 		return IRQ_HANDLED;
 	}
 
-	rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
-	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
+	if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
+		smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
+			chg->cc2_detach_wa_active ?
+			"cc2_detach_wa" : "typec_en_dis");
 		return IRQ_HANDLED;
 	}
 
-	debounce_done = (bool)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
-	sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT);
-	legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT);
-
-	smblib_handle_typec_debounce_done(chg,
-			debounce_done, sink_attached, legacy_cable);
-
-	if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT)
-		smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
-			irq_data->name);
-
-	if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT)
-		schedule_work(&chg->vconn_oc_work);
-
-	power_supply_changed(chg->usb_psy);
-	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4);
-	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat5);
+	mutex_lock(&chg->lock);
+	smblib_usb_typec_change(chg);
+	mutex_unlock(&chg->lock);
 	return IRQ_HANDLED;
 }
 
@@ -3788,7 +3754,7 @@
 {
 	struct smb_irq_data *irq_data = data;
 	struct smb_charger *chg = irq_data->parent_data;
-	int rc;
+	int rc, usb_icl;
 	u8 stat;
 
 	if (!(chg->wa_flags & BOOST_BACK_WA))
@@ -3800,8 +3766,9 @@
 		return IRQ_HANDLED;
 	}
 
-	if ((stat & USE_USBIN_BIT) &&
-			get_effective_result(chg->usb_icl_votable) < USBIN_25MA)
+	/* skip suspending input if its already suspended by some other voter */
+	usb_icl = get_effective_result(chg->usb_icl_votable);
+	if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
 		return IRQ_HANDLED;
 
 	if (stat & USE_DCIN_BIT)
@@ -3839,12 +3806,7 @@
 
 	vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
 				false, 0);
-	if (get_effective_result(chg->pd_disallowed_votable_indirect))
-		/* pd is still disabled, try hvdcp */
-		try_rerun_apsd_for_hvdcp(chg);
-	else
-		/* notify pd now that pd is allowed */
-		power_supply_changed(chg->usb_psy);
+	power_supply_changed(chg->usb_psy);
 }
 
 static void bms_update_work(struct work_struct *work)
@@ -3885,11 +3847,13 @@
 static void rdstd_cc2_detach_work(struct work_struct *work)
 {
 	int rc;
-	u8 stat;
-	struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
+	u8 stat4, stat5;
 	struct smb_charger *chg = container_of(work, struct smb_charger,
 						rdstd_cc2_detach_work);
 
+	if (!chg->cc2_detach_wa_active)
+		return;
+
 	/*
 	 * WA steps -
 	 * 1. Enable both UFP and DFP, wait for 10ms.
@@ -3897,7 +3861,7 @@
 	 * 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
 	 *    and TIMER_STAGE bits are gone, otherwise repeat all by
 	 *    work rescheduling.
-	 * Note, work will be cancelled when pd_hard_reset is 0.
+	 * Note, work will be cancelled when USB_PLUGIN rises.
 	 */
 
 	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
@@ -3920,30 +3884,35 @@
 
 	usleep_range(30000, 31000);
 
-	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
 	if (rc < 0) {
-		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
-			rc);
+		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
 		return;
 	}
-	if (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
-		goto rerun;
 
-	rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+	rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
 	if (rc < 0) {
 		smblib_err(chg,
 			"Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
 		return;
 	}
-	if (stat & TIMER_STAGE_2_BIT)
+
+	if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
+			|| (stat5 & TIMER_STAGE_2_BIT)) {
+		smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
+				(int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
+				(int)(stat5 & TIMER_STAGE_2_BIT));
 		goto rerun;
+	}
 
-	/* Bingo, cc2 removal detected */
+	smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
+	chg->cc2_detach_wa_active = false;
+	rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+						EXIT_SNK_BASED_ON_CC_BIT, 0);
 	smblib_reg_block_restore(chg, cc2_detach_settings);
-	chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
-	irq_data.parent_data = chg;
-	smblib_handle_usb_typec_change(0, &irq_data);
-
+	mutex_lock(&chg->lock);
+	smblib_usb_typec_change(chg);
+	mutex_unlock(&chg->lock);
 	return;
 
 rerun:
@@ -4166,6 +4135,56 @@
 	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
 }
 
+static void smblib_legacy_detection_work(struct work_struct *work)
+{
+	struct smb_charger *chg = container_of(work, struct smb_charger,
+							legacy_detection_work);
+	int rc;
+	u8 stat;
+	bool legacy, rp_high;
+
+	mutex_lock(&chg->lock);
+	chg->typec_en_dis_active = 1;
+	smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
+	rc = smblib_masked_write(chg,
+				TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+				TYPEC_DISABLE_CMD_BIT,
+				TYPEC_DISABLE_CMD_BIT);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
+
+	/* wait for the adapter to turn off VBUS */
+	msleep(500);
+
+	rc = smblib_masked_write(chg,
+				TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+				TYPEC_DISABLE_CMD_BIT, 0);
+	if (rc < 0)
+		smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
+
+	/* wait for type-c detection to complete */
+	msleep(100);
+
+	rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+	if (rc < 0) {
+		smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
+		goto unlock;
+	}
+
+	chg->typec_legacy_valid = true;
+	vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
+	legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
+	rp_high = smblib_get_prop_ufp_mode(chg) ==
+						POWER_SUPPLY_TYPEC_SOURCE_HIGH;
+	if (!legacy || !rp_high)
+		vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
+								false, 0);
+
+unlock:
+	chg->typec_en_dis_active = 0;
+	mutex_unlock(&chg->lock);
+}
+
 static int smblib_create_votables(struct smb_charger *chg)
 {
 	int rc = 0;
@@ -4298,6 +4317,15 @@
 		return rc;
 	}
 
+	chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
+					VOTE_SET_ANY,
+					smblib_typec_irq_disable_vote_callback,
+					chg);
+	if (IS_ERR(chg->typec_irq_disable_votable)) {
+		rc = PTR_ERR(chg->typec_irq_disable_votable);
+		return rc;
+	}
+
 	return rc;
 }
 
@@ -4323,6 +4351,8 @@
 		destroy_votable(chg->apsd_disable_votable);
 	if (chg->hvdcp_hw_inov_dis_votable)
 		destroy_votable(chg->hvdcp_hw_inov_dis_votable);
+	if (chg->typec_irq_disable_votable)
+		destroy_votable(chg->typec_irq_disable_votable);
 }
 
 static void smblib_iio_deinit(struct smb_charger *chg)
@@ -4343,6 +4373,7 @@
 {
 	int rc = 0;
 
+	mutex_init(&chg->lock);
 	mutex_init(&chg->write_lock);
 	mutex_init(&chg->otg_oc_lock);
 	INIT_WORK(&chg->bms_update_work, bms_update_work);
@@ -4355,6 +4386,7 @@
 	INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
 	INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
 	INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
+	INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
 	chg->fake_capacity = -EINVAL;
 
 	switch (chg->mode) {
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 49b9d3d..b0d84f0 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -61,6 +61,7 @@
 #define SW_QC3_VOTER			"SW_QC3_VOTER"
 #define AICL_RERUN_VOTER		"AICL_RERUN_VOTER"
 #define LEGACY_UNKNOWN_VOTER		"LEGACY_UNKNOWN_VOTER"
+#define CC2_WA_VOTER			"CC2_WA_VOTER"
 
 #define VCONN_MAX_ATTEMPTS	3
 #define OTG_MAX_ATTEMPTS	3
@@ -71,13 +72,6 @@
 	NUM_MODES,
 };
 
-enum cc2_sink_type {
-	CC2_SINK_NONE = 0,
-	CC2_SINK_STD,
-	CC2_SINK_MEDIUM_HIGH,
-	CC2_SINK_WA_DONE,
-};
-
 enum {
 	QC_CHARGER_DETECTION_WA_BIT	= BIT(0),
 	BOOST_BACK_WA			= BIT(1),
@@ -236,6 +230,7 @@
 	int			smb_version;
 
 	/* locks */
+	struct mutex		lock;
 	struct mutex		write_lock;
 	struct mutex		ps_change_lock;
 	struct mutex		otg_oc_lock;
@@ -276,6 +271,7 @@
 	struct votable		*apsd_disable_votable;
 	struct votable		*hvdcp_hw_inov_dis_votable;
 	struct votable		*usb_irq_enable_votable;
+	struct votable		*typec_irq_disable_votable;
 
 	/* work */
 	struct work_struct	bms_update_work;
@@ -289,6 +285,7 @@
 	struct delayed_work	otg_ss_done_work;
 	struct delayed_work	icl_change_work;
 	struct delayed_work	pl_enable_work;
+	struct work_struct	legacy_detection_work;
 
 	/* cached status */
 	int			voltage_min_uv;
@@ -312,10 +309,16 @@
 	int			vconn_attempts;
 	int			default_icl_ua;
 	int			otg_cl_ua;
+	bool			uusb_apsd_rerun_done;
+	bool			pd_hard_reset;
+	bool			typec_present;
+	u8			typec_status[5];
+	bool			typec_legacy_valid;
 
 	/* workaround flag */
 	u32			wa_flags;
-	enum cc2_sink_type	cc2_sink_detach_flag;
+	bool			cc2_detach_wa_active;
+	bool			typec_en_dis_active;
 	int			boost_current_ua;
 	int			temp_speed_reading_count;
 
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index 167666a..3f260a4 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -1025,4 +1025,14 @@
 /* CHGR FREQ Peripheral registers */
 #define FREQ_CLK_DIV_REG			(CHGR_FREQ_BASE + 0x50)
 
+/* SMB1355 specific registers */
+#define SMB1355_TEMP_COMP_STATUS_REG		(MISC_BASE + 0x07)
+#define SKIN_TEMP_RST_HOT_BIT			BIT(6)
+#define SKIN_TEMP_UB_HOT_BIT			BIT(5)
+#define SKIN_TEMP_LB_HOT_BIT			BIT(4)
+#define DIE_TEMP_TSD_HOT_BIT			BIT(3)
+#define DIE_TEMP_RST_HOT_BIT			BIT(2)
+#define DIE_TEMP_UB_HOT_BIT			BIT(1)
+#define DIE_TEMP_LB_HOT_BIT			BIT(0)
+
 #endif /* __SMB2_CHARGER_REG_H */
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index 0d1f2a6..b92a482 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1655,7 +1655,7 @@
 
 	switch (prop) {
 	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
-		val->intval = !chip->usb_suspended_status;
+		val->intval = !chip->parallel_charger_suspended;
 		break;
 	case POWER_SUPPLY_PROP_CURRENT_MAX:
 		if (!chip->parallel_charger_suspended)
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 83374bb..a29871b 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -104,6 +104,8 @@
 	struct smb_dt_props	dt;
 	struct power_supply	*parallel_psy;
 	u32			wa_flags;
+	struct pmic_revid_data	*pmic_rev_id;
+	char			*name;
 };
 
 static int __debug_mask;
@@ -167,6 +169,14 @@
 	if (rc < 0)
 		chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID;
 
+	/* check that smb1355 is configured to run in mid-mid mode */
+	if (chip->pmic_rev_id->pmic_subtype == SMB1355_SUBTYPE
+		&& chip->dt.pl_mode != POWER_SUPPLY_PL_USBMID_USBMID) {
+		pr_err("Smb1355 can only run in MID-MID mode, saw = %d mode\n",
+				chip->dt.pl_mode);
+		return -EINVAL;
+	}
+
 	chip->dt.suspend_input = of_property_read_bool(node,
 				"qcom,suspend-input");
 
@@ -479,6 +489,30 @@
  * PARALLEL PSY REGISTRATION *
  *****************************/
 
+static int smb1355_get_prop_connector_health(struct smb138x *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	u8 temp;
+	int rc;
+
+	rc = smblib_read(chg, SMB1355_TEMP_COMP_STATUS_REG, &temp);
+	if (rc < 0) {
+		pr_err("Couldn't read comp stat reg rc = %d\n", rc);
+		return POWER_SUPPLY_HEALTH_UNKNOWN;
+	}
+
+	if (temp & SKIN_TEMP_RST_HOT_BIT)
+		return POWER_SUPPLY_HEALTH_OVERHEAT;
+
+	if (temp & SKIN_TEMP_UB_HOT_BIT)
+		return POWER_SUPPLY_HEALTH_HOT;
+
+	if (temp & SKIN_TEMP_LB_HOT_BIT)
+		return POWER_SUPPLY_HEALTH_WARM;
+
+	return POWER_SUPPLY_HEALTH_COOL;
+}
+
 static int smb138x_get_prop_connector_health(struct smb138x *chip)
 {
 	struct smb_charger *chg = &chip->chg;
@@ -536,16 +570,32 @@
 	POWER_SUPPLY_PROP_PIN_ENABLED,
 	POWER_SUPPLY_PROP_INPUT_SUSPEND,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
-	POWER_SUPPLY_PROP_CURRENT_MAX,
 	POWER_SUPPLY_PROP_VOLTAGE_MAX,
 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
-	POWER_SUPPLY_PROP_CURRENT_NOW,
-	POWER_SUPPLY_PROP_CHARGER_TEMP,
-	POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
 	POWER_SUPPLY_PROP_MODEL_NAME,
 	POWER_SUPPLY_PROP_PARALLEL_MODE,
 	POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
 	POWER_SUPPLY_PROP_SET_SHIP_MODE,
+	POWER_SUPPLY_PROP_CHARGER_TEMP,
+	POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static enum power_supply_property smb1355_parallel_props[] = {
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CHARGING_ENABLED,
+	POWER_SUPPLY_PROP_PIN_ENABLED,
+	POWER_SUPPLY_PROP_INPUT_SUSPEND,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_PARALLEL_MODE,
+	POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
+	POWER_SUPPLY_PROP_SET_SHIP_MODE,
+	POWER_SUPPLY_PROP_CHARGER_TEMP,
+	POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
 };
 
 static int smb138x_parallel_get_prop(struct power_supply *psy,
@@ -583,14 +633,6 @@
 		else
 			val->intval = 0;
 		break;
-	case POWER_SUPPLY_PROP_CURRENT_MAX:
-		if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
-		|| (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
-			rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
-				&val->intval);
-		else
-			val->intval = 0;
-		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
 		rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
 		break;
@@ -598,28 +640,46 @@
 		rc = smblib_get_charge_param(chg, &chg->param.fcc,
 					     &val->intval);
 		break;
-	case POWER_SUPPLY_PROP_CURRENT_NOW:
-		rc = smblib_get_prop_slave_current_now(chg, val);
-		break;
-	case POWER_SUPPLY_PROP_CHARGER_TEMP:
-		rc = smb138x_get_prop_charger_temp(chip, val);
-		break;
-	case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
-		rc = smblib_get_prop_charger_temp_max(chg, val);
-		break;
 	case POWER_SUPPLY_PROP_MODEL_NAME:
-		val->strval = "smb138x";
+		val->strval = chip->name;
 		break;
 	case POWER_SUPPLY_PROP_PARALLEL_MODE:
 		val->intval = chip->dt.pl_mode;
 		break;
 	case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
-		val->intval = smb138x_get_prop_connector_health(chip);
+		if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+			val->intval = smb138x_get_prop_connector_health(chip);
+		else
+			val->intval = smb1355_get_prop_connector_health(chip);
 		break;
 	case POWER_SUPPLY_PROP_SET_SHIP_MODE:
 		/* Not in ship mode as long as device is active */
 		val->intval = 0;
 		break;
+	case POWER_SUPPLY_PROP_CHARGER_TEMP:
+		if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+			rc = smb138x_get_prop_charger_temp(chip, val);
+		else
+			rc = smblib_get_prop_charger_temp(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
+		rc = smblib_get_prop_charger_temp_max(chg, val);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+			rc = smblib_get_prop_slave_current_now(chg, val);
+		else
+			rc = -ENODATA;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		if ((chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+		  && ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+		  || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)))
+			rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
+				&val->intval);
+		else
+			rc = -ENODATA;
+		break;
 	default:
 		pr_err("parallel power supply get prop %d not supported\n",
 			prop);
@@ -703,7 +763,7 @@
 	return 0;
 }
 
-static const struct power_supply_desc parallel_psy_desc = {
+static struct power_supply_desc parallel_psy_desc = {
 	.name			= "parallel",
 	.type			= POWER_SUPPLY_TYPE_PARALLEL,
 	.properties		= smb138x_parallel_props,
@@ -731,6 +791,28 @@
 	return 0;
 }
 
+static int smb1355_init_parallel_psy(struct smb138x *chip)
+{
+	struct power_supply_config parallel_cfg = {};
+	struct smb_charger *chg = &chip->chg;
+
+	parallel_cfg.drv_data = chip;
+	parallel_cfg.of_node = chg->dev->of_node;
+
+	/* change to smb1355's property list */
+	parallel_psy_desc.properties = smb1355_parallel_props;
+	parallel_psy_desc.num_properties = ARRAY_SIZE(smb1355_parallel_props);
+	chip->parallel_psy = devm_power_supply_register(chg->dev,
+						   &parallel_psy_desc,
+						   &parallel_cfg);
+	if (IS_ERR(chip->parallel_psy)) {
+		pr_err("Couldn't register parallel power supply\n");
+		return PTR_ERR(chip->parallel_psy);
+	}
+
+	return 0;
+}
+
 /******************************
  * VBUS REGULATOR REGISTRATION *
  ******************************/
@@ -1050,7 +1132,6 @@
 
 static int smb138x_setup_wa_flags(struct smb138x *chip)
 {
-	struct pmic_revid_data *pmic_rev_id;
 	struct device_node *revid_dev_node;
 
 	revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
@@ -1060,8 +1141,8 @@
 		return -EINVAL;
 	}
 
-	pmic_rev_id = get_revid_data(revid_dev_node);
-	if (IS_ERR_OR_NULL(pmic_rev_id)) {
+	chip->pmic_rev_id = get_revid_data(revid_dev_node);
+	if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
 		/*
 		 * the revid peripheral must be registered, any failure
 		 * here only indicates that the rev-id module has not
@@ -1070,14 +1151,14 @@
 		return -EPROBE_DEFER;
 	}
 
-	switch (pmic_rev_id->pmic_subtype) {
+	switch (chip->pmic_rev_id->pmic_subtype) {
 	case SMB1381_SUBTYPE:
-		if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
+		if (chip->pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
 			chip->wa_flags |= OOB_COMP_WA_BIT;
 		break;
 	default:
 		pr_err("PMIC subtype %d not supported\n",
-				pmic_rev_id->pmic_subtype);
+				chip->pmic_rev_id->pmic_subtype);
 		return -EINVAL;
 	}
 
@@ -1375,6 +1456,7 @@
 
 	chg->param = v1_params;
 
+	chip->name = "smb1381";
 	rc = smblib_init(chg);
 	if (rc < 0) {
 		pr_err("Couldn't initialize smblib rc=%d\n", rc);
@@ -1435,7 +1517,7 @@
 	return rc;
 }
 
-static int smb138x_slave_probe(struct smb138x *chip)
+static int smb1355_slave_probe(struct smb138x *chip)
 {
 	struct smb_charger *chg = &chip->chg;
 	int rc = 0;
@@ -1448,6 +1530,55 @@
 		goto cleanup;
 	}
 
+	rc = smb138x_parse_dt(chip);
+	if (rc < 0) {
+		pr_err("Couldn't parse device tree rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb138x_init_slave_hw(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize hardware rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb1355_init_parallel_psy(chip);
+	if (rc < 0) {
+		pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb138x_determine_initial_slave_status(chip);
+	if (rc < 0) {
+		pr_err("Couldn't determine initial status rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	rc = smb138x_request_interrupts(chip);
+	if (rc < 0) {
+		pr_err("Couldn't request interrupts rc=%d\n", rc);
+		goto cleanup;
+	}
+
+	return 0;
+
+cleanup:
+	smblib_deinit(chg);
+	return rc;
+}
+
+static int smb1381_slave_probe(struct smb138x *chip)
+{
+	struct smb_charger *chg = &chip->chg;
+	int rc = 0;
+
+	chg->param = v1_params;
+
+	rc = smblib_init(chg);
+	if (rc < 0) {
+		pr_err("Couldn't initialize smblib rc=%d\n", rc);
+		goto cleanup;
+	}
 	chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max");
 	if (IS_ERR(chg->iio.temp_max_chan)) {
 		rc = PTR_ERR(chg->iio.temp_max_chan);
@@ -1515,25 +1646,71 @@
 		goto cleanup;
 	}
 
-	return rc;
+	return 0;
 
 cleanup:
 	smblib_deinit(chg);
-	if (chip->parallel_psy)
-		power_supply_unregister(chip->parallel_psy);
-	if (chg->vbus_vreg && chg->vbus_vreg->rdev)
-		regulator_unregister(chg->vbus_vreg->rdev);
 	return rc;
 }
 
+static int slave_probe(struct smb138x *chip)
+{
+	struct device_node *revid_dev_node;
+	int rc = 0;
+
+	revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
+					"qcom,pmic-revid", 0);
+	if (!revid_dev_node) {
+		pr_err("Missing qcom,pmic-revid property\n");
+		return -EINVAL;
+	}
+
+	chip->pmic_rev_id = get_revid_data(revid_dev_node);
+	if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
+		/*
+		 * the revid peripheral must be registered, any failure
+		 * here only indicates that the rev-id module has not
+		 * probed yet.
+		 */
+		return -EPROBE_DEFER;
+	}
+
+	switch (chip->pmic_rev_id->pmic_subtype) {
+	case SMB1355_SUBTYPE:
+		chip->name = "smb1355";
+		rc = smb1355_slave_probe(chip);
+		break;
+	case SMB1381_SUBTYPE:
+		chip->name = "smb1381";
+		rc = smb1381_slave_probe(chip);
+		break;
+	default:
+		pr_err("Unsupported pmic subtype = 0x%02x\n",
+				chip->pmic_rev_id->pmic_subtype);
+		rc = -EINVAL;
+	}
+
+	if (rc < 0) {
+		if (rc != -EPROBE_DEFER)
+			pr_err("Couldn't probe SMB138X rc=%d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static const struct of_device_id match_table[] = {
 	{
-		.compatible = "qcom,smb138x-charger",
-		.data = (void *) PARALLEL_MASTER
+		.compatible	= "qcom,smb138x-charger",
+		.data		= (void *) PARALLEL_MASTER,
 	},
 	{
-		.compatible = "qcom,smb138x-parallel-slave",
-		.data = (void *) PARALLEL_SLAVE
+		.compatible	= "qcom,smb138x-parallel-slave",
+		.data		= (void *) PARALLEL_SLAVE,
+	},
+	{
+		.compatible	= "qcom,smb1355-parallel-slave",
+		.data		= (void *) PARALLEL_SLAVE,
 	},
 	{ },
 };
@@ -1580,7 +1757,7 @@
 		rc = smb138x_master_probe(chip);
 		break;
 	case PARALLEL_SLAVE:
-		rc = smb138x_slave_probe(chip);
+		rc = slave_probe(chip);
 		break;
 	default:
 		pr_err("Couldn't find a matching mode %d\n", chip->chg.mode);
@@ -1594,7 +1771,8 @@
 		goto cleanup;
 	}
 
-	pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode);
+	pr_info("%s probed successfully mode=%d pl_mode = %d\n",
+		chip->name, chip->chg.mode, chip->dt.pl_mode);
 	return rc;
 
 cleanup:
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index 9566e24..c45fb0d 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -177,6 +177,7 @@
 #define CPR4_CPR_TIMER_CLAMP_THREAD_AGGREGATION_EN	BIT(27)
 
 #define CPR4_REG_MISC				0x700
+#define CPR4_MISC_RESET_STEP_QUOT_LOOP_EN	BIT(2)
 #define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK	GENMASK(23, 20)
 #define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT	20
 #define CPR4_MISC_TEMP_SENSOR_ID_START_MASK	GENMASK(27, 24)
@@ -723,6 +724,11 @@
 	int thread_id = 0;
 	u64 temp;
 
+	if (ctrl->reset_step_quot_loop_en)
+		cpr3_masked_write(ctrl, CPR4_REG_MISC,
+				CPR4_MISC_RESET_STEP_QUOT_LOOP_EN,
+				CPR4_MISC_RESET_STEP_QUOT_LOOP_EN);
+
 	if (ctrl->supports_hw_closed_loop) {
 		if (ctrl->saw_use_unit_mV)
 			pmic_step_size = ctrl->step_volt / 1000;
@@ -1355,6 +1361,11 @@
 		}
 	}
 
+	if (ctrl->reset_step_quot_loop_en)
+		cpr3_masked_write(ctrl, CPR4_REG_MISC,
+				CPR4_MISC_RESET_STEP_QUOT_LOOP_EN,
+				CPR4_MISC_RESET_STEP_QUOT_LOOP_EN);
+
 	if (ctrl->saw_use_unit_mV)
 		pmic_step_size = ctrl->step_volt / 1000;
 	cpr3_masked_write(ctrl, CPR4_REG_MARGIN_ADJ_CTL,
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index 570ddfc..8535020 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -756,6 +756,12 @@
  * @panic_notifier:	Notifier block registered to global panic notifier list.
  * @support_ldo300_vreg: Boolean value which indicates that this CPR controller
  *			manages an underlying LDO regulator of type LDO300.
+ * @reset_step_quot_loop_en: Boolean value which indicates that this CPR
+ *			controller should be configured to reset step_quot on
+ *			each loop_en = 0 transition. This configuration allows
+ *			the CPR controller to first use the default step_quot
+ *			and then later switch to the run-time calibrated
+ *			step_quot.
  *
  * This structure contains both configuration and runtime state data.  The
  * elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
@@ -866,6 +872,7 @@
 	struct cpr3_panic_regs_info *panic_regs_info;
 	struct notifier_block	panic_notifier;
 	bool			support_ldo300_vreg;
+	bool			reset_step_quot_loop_en;
 };
 
 /* Used for rounding voltages to the closest physically available set point. */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index 648d396..3035155 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -1224,6 +1224,14 @@
 	}
 
 	/*
+	 * Reset step_quot to default on each loop_en = 0 transition is
+	 * optional.
+	 */
+	ctrl->reset_step_quot_loop_en
+		= of_property_read_bool(ctrl->dev->of_node,
+					"qcom,cpr-reset-step-quot-loop-en");
+
+	/*
 	 * Regulator device handles are not necessary for CPRh controllers
 	 * since communication with the regulators is completely managed
 	 * in hardware.
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 69e3032..3311380 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -655,3 +655,11 @@
 	  memory location. These messages provide statistical information about
 	  the low power modes that RPM enters. The drivers outputs the message
 	  via a debugfs node.
+
+config QCOM_FORCE_WDOG_BITE_ON_PANIC
+	bool "QCOM force watchdog bite"
+	depends on QCOM_WATCHDOG_V2
+	help
+	  This forces a watchdog bite when the device restarts due to a
+	  kernel panic. On certain MSM SoCs, this provides us
+	  additional debugging information.
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index 0c2ba4d..5cc04c0 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -241,18 +241,28 @@
 
 static int cmd_db_dev_probe(struct platform_device *pdev)
 {
-	struct resource *res;
+	struct resource res;
+	void __iomem *dict;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
+	dict = of_iomap(pdev->dev.of_node, 0);
+	if (!dict) {
 		cmd_db_status = -ENOMEM;
 		goto failed;
 	}
 
-	start_addr = devm_ioremap_resource(&pdev->dev, res);
+	/*
+	 * Read start address and size of the command DB address from
+	 * shared dictionary location
+	 */
+	res.start = readl_relaxed(dict);
+	res.end = res.start + readl_relaxed(dict + 0x4);
+	res.flags = IORESOURCE_MEM;
+	iounmap(dict);
 
-	cmd_db_header = devm_kzalloc(&pdev->dev, sizeof(*cmd_db_header),
-			GFP_KERNEL);
+	start_addr = devm_ioremap_resource(&pdev->dev, &res);
+
+	cmd_db_header = devm_kzalloc(&pdev->dev,
+			sizeof(*cmd_db_header), GFP_KERNEL);
 
 	if (!cmd_db_header) {
 		cmd_db_status = -ENOMEM;
diff --git a/drivers/soc/qcom/glink_private.h b/drivers/soc/qcom/glink_private.h
index c837bd8..9810207 100644
--- a/drivers/soc/qcom/glink_private.h
+++ b/drivers/soc/qcom/glink_private.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -700,6 +700,7 @@
  * edge:		The G-Link edge name for the channel associated with
  *			this callback data
  * do_cleanup_data:	Structure containing the G-Link SSR do_cleanup message.
+ * cb_kref:		Kref object to maintain cb_data reference.
  */
 struct ssr_notify_data {
 	bool tx_done;
@@ -707,6 +708,7 @@
 	bool responded;
 	const char *edge;
 	struct do_cleanup_msg *do_cleanup_data;
+	struct kref cb_kref;
 };
 
 /**
@@ -741,6 +743,7 @@
 	int notify_list_len;
 	bool link_up;
 	spinlock_t link_up_lock;
+	spinlock_t cb_lock;
 };
 
 /**
diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c
index b24598a..4737288 100644
--- a/drivers/soc/qcom/glink_ssr.c
+++ b/drivers/soc/qcom/glink_ssr.c
@@ -115,6 +115,44 @@
 static atomic_t responses_remaining = ATOMIC_INIT(0);
 static wait_queue_head_t waitqueue;
 
+/**
+ * cb_data_release() - Free cb_data and set to NULL
+ * @kref_ptr:	pointer to kref.
+ *
+ * This function releses cb_data.
+ */
+static inline void cb_data_release(struct kref *kref_ptr)
+{
+	struct ssr_notify_data *cb_data;
+
+	cb_data = container_of(kref_ptr, struct ssr_notify_data, cb_kref);
+	kfree(cb_data);
+}
+
+/**
+ * check_and_get_cb_data() - Try to get reference to kref of cb_data
+ * @ss_info:	pointer to subsystem info structure.
+ *
+ * Return: NULL is cb_data is NULL, pointer to cb_data otherwise
+ */
+static struct ssr_notify_data *check_and_get_cb_data(
+					struct subsys_info *ss_info)
+{
+	struct ssr_notify_data *cb_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ss_info->cb_lock, flags);
+	if (ss_info->cb_data == NULL) {
+		GLINK_SSR_LOG("<SSR> %s: cb_data is NULL\n", __func__);
+		spin_unlock_irqrestore(&ss_info->cb_lock, flags);
+		return 0;
+	}
+	kref_get(&ss_info->cb_data->cb_kref);
+	cb_data = ss_info->cb_data;
+	spin_unlock_irqrestore(&ss_info->cb_lock, flags);
+	return cb_data;
+}
+
 static void rx_done_cb_worker(struct work_struct *work)
 {
 	struct rx_done_ch_work *rx_done_work =
@@ -340,8 +378,10 @@
 
 	if (WARN_ON(!ss_info->cb_data))
 		return;
-	kfree(ss_info->cb_data);
+	spin_lock_irqsave(&ss_info->cb_lock, flags);
+	kref_put(&ss_info->cb_data->cb_kref, cb_data_release);
 	ss_info->cb_data = NULL;
+	spin_unlock_irqrestore(&ss_info->cb_lock, flags);
 	kfree(close_work);
 }
 
@@ -508,13 +548,18 @@
 			return -ENODEV;
 		}
 		handle = ss_info_channel->handle;
-		ss_leaf_entry->cb_data = ss_info_channel->cb_data;
+		ss_leaf_entry->cb_data = check_and_get_cb_data(
+							ss_info_channel);
+		if (!ss_leaf_entry->cb_data) {
+			GLINK_SSR_LOG("<SSR> %s: CB data is NULL\n", __func__);
+			atomic_dec(&responses_remaining);
+			continue;
+		}
 
 		spin_lock_irqsave(&ss_info->link_up_lock, flags);
 		if (IS_ERR_OR_NULL(ss_info_channel->handle) ||
-				!ss_info_channel->cb_data ||
 				!ss_info_channel->link_up ||
-				ss_info_channel->cb_data->event
+				ss_leaf_entry->cb_data->event
 						!= GLINK_CONNECTED) {
 
 			GLINK_SSR_LOG(
@@ -527,6 +572,8 @@
 
 			spin_unlock_irqrestore(&ss_info->link_up_lock, flags);
 			atomic_dec(&responses_remaining);
+			kref_put(&ss_leaf_entry->cb_data->cb_kref,
+							cb_data_release);
 			continue;
 		}
 		spin_unlock_irqrestore(&ss_info->link_up_lock, flags);
@@ -537,6 +584,8 @@
 			GLINK_SSR_ERR(
 				"%s %s: Could not allocate do_cleanup_msg\n",
 				"<SSR>", __func__);
+			kref_put(&ss_leaf_entry->cb_data->cb_kref,
+							cb_data_release);
 			return -ENOMEM;
 		}
 
@@ -568,6 +617,8 @@
 						__func__);
 			}
 			atomic_dec(&responses_remaining);
+			kref_put(&ss_leaf_entry->cb_data->cb_kref,
+							cb_data_release);
 			continue;
 		}
 
@@ -597,10 +648,12 @@
 						__func__);
 			}
 			atomic_dec(&responses_remaining);
+			kref_put(&ss_leaf_entry->cb_data->cb_kref,
+							cb_data_release);
 			continue;
 		}
-
 		sequence_number++;
+		kref_put(&ss_leaf_entry->cb_data->cb_kref, cb_data_release);
 	}
 
 	wait_ret = wait_event_timeout(waitqueue,
@@ -609,6 +662,21 @@
 
 	list_for_each_entry(ss_leaf_entry, &ss_info->notify_list,
 			notify_list_node) {
+		ss_info_channel =
+			get_info_for_subsystem(ss_leaf_entry->ssr_name);
+		if (ss_info_channel == NULL) {
+			GLINK_SSR_ERR(
+				"<SSR> %s: unable to find subsystem name\n",
+					__func__);
+			continue;
+		}
+
+		ss_leaf_entry->cb_data = check_and_get_cb_data(
+							ss_info_channel);
+		if (!ss_leaf_entry->cb_data) {
+			GLINK_SSR_LOG("<SSR> %s: CB data is NULL\n", __func__);
+			continue;
+		}
 		if (!wait_ret && !IS_ERR_OR_NULL(ss_leaf_entry->cb_data)
 				&& !ss_leaf_entry->cb_data->responded) {
 			GLINK_SSR_ERR("%s %s: Subsystem %s %s\n",
@@ -627,6 +695,7 @@
 
 		if (!IS_ERR_OR_NULL(ss_leaf_entry->cb_data))
 			ss_leaf_entry->cb_data->responded = false;
+		kref_put(&ss_leaf_entry->cb_data->cb_kref, cb_data_release);
 	}
 	complete(&notifications_successful_complete);
 	return 0;
@@ -645,6 +714,7 @@
 	struct glink_open_config open_cfg;
 	struct ssr_notify_data *cb_data = NULL;
 	void *handle = NULL;
+	unsigned long flags;
 
 	if (!ss_info) {
 		GLINK_SSR_ERR("<SSR> %s: ss_info structure invalid\n",
@@ -661,7 +731,10 @@
 	cb_data->responded = false;
 	cb_data->event = GLINK_SSR_EVENT_INIT;
 	cb_data->edge = ss_info->edge;
+	spin_lock_irqsave(&ss_info->cb_lock, flags);
 	ss_info->cb_data = cb_data;
+	kref_init(&cb_data->cb_kref);
+	spin_unlock_irqrestore(&ss_info->cb_lock, flags);
 
 	memset(&open_cfg, 0, sizeof(struct glink_open_config));
 
@@ -877,6 +950,7 @@
 	ss_info->link_state_handle = NULL;
 	ss_info->cb_data = NULL;
 	spin_lock_init(&ss_info->link_up_lock);
+	spin_lock_init(&ss_info->cb_lock);
 
 	nb = kmalloc(sizeof(struct restart_notifier_block), GFP_KERNEL);
 	if (!nb) {
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 0b35caa..b759776 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -48,11 +48,6 @@
 #include <soc/qcom/socinfo.h>
 #include <soc/qcom/ramdump.h>
 
-#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
-#include <net/cnss_prealloc.h>
-#endif
-
-
 #include "wlan_firmware_service_v01.h"
 
 #ifdef CONFIG_ICNSS_DEBUG
@@ -1968,8 +1963,6 @@
 	if (ret < 0) {
 		icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
 			     ret, priv->state);
-		wcnss_prealloc_check_memory_leak();
-		wcnss_pre_alloc_reset();
 		goto out;
 	}
 
@@ -2099,8 +2092,6 @@
 	if (ret) {
 		icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
 			     ret, penv->state);
-		wcnss_prealloc_check_memory_leak();
-		wcnss_pre_alloc_reset();
 		goto power_off;
 	}
 
@@ -2126,8 +2117,6 @@
 		penv->ops->remove(&penv->pdev->dev);
 
 	clear_bit(ICNSS_DRIVER_PROBED, &penv->state);
-	wcnss_prealloc_check_memory_leak();
-	wcnss_pre_alloc_reset();
 
 	penv->ops = NULL;
 
@@ -2152,8 +2141,6 @@
 	penv->ops->remove(&priv->pdev->dev);
 
 	clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
-	wcnss_prealloc_check_memory_leak();
-	wcnss_pre_alloc_reset();
 
 	icnss_hw_power_off(penv);
 
diff --git a/drivers/soc/qcom/msm-core.c b/drivers/soc/qcom/msm-core.c
index de2a1ce..4ec791c 100644
--- a/drivers/soc/qcom/msm-core.c
+++ b/drivers/soc/qcom/msm-core.c
@@ -35,6 +35,7 @@
 #include <linux/uaccess.h>
 #include <linux/uio_driver.h>
 #include <asm/smp_plat.h>
+#include <asm/cputype.h>
 #include <stdbool.h>
 #define CREATE_TRACE_POINTS
 #include <trace/events/trace_msm_core.h>
@@ -46,7 +47,6 @@
 #define DEFAULT_TEMP 40
 #define DEFAULT_LOW_HYST_TEMP 10
 #define DEFAULT_HIGH_HYST_TEMP 5
-#define CLUSTER_OFFSET_FOR_MPIDR 8
 #define MAX_CORES_PER_CLUSTER 4
 #define MAX_NUM_OF_CLUSTERS 2
 #define NUM_OF_CORNERS 10
@@ -291,12 +291,11 @@
 	int cpu = -1;
 	struct cpu_activity_info *node;
 	struct cpu_static_info *sp, *clear_sp;
-	int cpumask, cluster, mpidr;
+	int cpumask, cluster;
 	bool pdata_valid[NR_CPUS] = {0};
 
 	get_user(cpumask, &argp->cpumask);
 	get_user(cluster, &argp->cluster);
-	mpidr = cluster << 8;
 
 	pr_debug("%s: cpumask %d, cluster: %d\n", __func__, cpumask,
 					cluster);
@@ -304,10 +303,12 @@
 		if (!(cpumask & 0x01))
 			continue;
 
-		mpidr |= i;
 		for_each_possible_cpu(cpu) {
-			if (cpu_logical_map(cpu) == mpidr)
-				break;
+			if ((cpu_topology[cpu].core_id != i) &&
+				(cpu_topology[cpu].cluster_id != cluster))
+				continue;
+
+			break;
 		}
 	}
 
@@ -348,10 +349,9 @@
 	for (i = 0; i < MAX_CORES_PER_CLUSTER; i++, cpumask >>= 1) {
 		if (!(cpumask & 0x01))
 			continue;
-		mpidr = (cluster << CLUSTER_OFFSET_FOR_MPIDR);
-		mpidr |= i;
 		for_each_possible_cpu(cpu) {
-			if (!(cpu_logical_map(cpu) == mpidr))
+			if (((cpu_topology[cpu].core_id != i) ||
+				(cpu_topology[cpu].cluster_id != cluster)))
 				continue;
 
 			node = &activity[cpu];
@@ -395,14 +395,12 @@
 	struct cpu_activity_info *node = NULL;
 	struct sched_params __user *argp = (struct sched_params __user *)arg;
 	int i, cpu = num_possible_cpus();
-	int mpidr, cluster, cpumask;
+	int cluster, cpumask;
 
 	if (!argp)
 		return -EINVAL;
 
 	get_user(cluster, &argp->cluster);
-	mpidr = (cluster << (MAX_CORES_PER_CLUSTER *
-			MAX_NUM_OF_CLUSTERS));
 	get_user(cpumask, &argp->cpumask);
 
 	switch (cmd) {
@@ -414,8 +412,11 @@
 	case EA_VOLT:
 		for (i = 0; cpumask > 0; i++, cpumask >>= 1) {
 			for_each_possible_cpu(cpu) {
-				if (cpu_logical_map(cpu) == (mpidr | i))
-					break;
+				if (((cpu_topology[cpu].core_id != i) ||
+				(cpu_topology[cpu].cluster_id != cluster)))
+					continue;
+
+				break;
 			}
 		}
 		if (cpu >= num_possible_cpus())
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 91d6349..c950367 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -337,8 +337,8 @@
 			tcs_cmd_gen(cur_bcm, &cmdlist_active[k],
 				cur_bcm->node_vec[ACTIVE_CTX].vec_a,
 				cur_bcm->node_vec[ACTIVE_CTX].vec_b, commit);
-			k++;
 			last_tcs = k;
+			k++;
 			cur_bcm->updated = true;
 		}
 	}
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index fb3d7d9..c5ba279 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -75,6 +75,10 @@
 #define MSS_RESTART_ID			0xA
 
 #define MSS_MAGIC			0XAABADEAD
+
+#define MSS_PDC_OFFSET			8
+#define MSS_PDC_MASK			BIT(MSS_PDC_OFFSET)
+
 enum scm_cmd {
 	PAS_MEM_SETUP_CMD = 2,
 };
@@ -204,6 +208,33 @@
 		clk_disable_unprepare(drv->ahb_clk);
 }
 
+static void pil_mss_pdc_sync(struct q6v5_data *drv, bool pdc_sync)
+{
+	u32 val = 0;
+
+	if (drv->pdc_sync) {
+		val = readl_relaxed(drv->pdc_sync);
+		if (pdc_sync)
+			val |= MSS_PDC_MASK;
+		else
+			val &= ~MSS_PDC_MASK;
+		writel_relaxed(val, drv->pdc_sync);
+		/* Ensure PDC is written before next write */
+		wmb();
+		udelay(2);
+	}
+}
+
+static void pil_mss_alt_reset(struct q6v5_data *drv, u32 val)
+{
+	if (drv->alt_reset) {
+		writel_relaxed(val, drv->alt_reset);
+		/* Ensure alt reset is written before restart reg */
+		wmb();
+		udelay(2);
+	}
+}
+
 static int pil_mss_restart_reg(struct q6v5_data *drv, u32 mss_restart)
 {
 	int ret = 0;
@@ -235,6 +266,32 @@
 	return ret;
 }
 
+static int pil_mss_assert_resets(struct q6v5_data *drv)
+{
+	int ret = 0;
+
+	pil_mss_pdc_sync(drv, 1);
+	pil_mss_alt_reset(drv, 1);
+	ret = pil_mss_restart_reg(drv, true);
+
+	return ret;
+}
+
+static int pil_mss_deassert_resets(struct q6v5_data *drv)
+{
+	int ret = 0;
+
+	ret = pil_mss_restart_reg(drv, 0);
+	if (ret)
+		return ret;
+	/* Wait 6 32kHz sleep cycles for reset */
+	udelay(200);
+	pil_mss_alt_reset(drv, 0);
+	pil_mss_pdc_sync(drv, false);
+
+	return ret;
+}
+
 static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv)
 {
 	struct device *dev = drv->desc.dev;
@@ -304,7 +361,10 @@
 									ret);
 	}
 
-	ret = pil_mss_restart_reg(drv, 1);
+	pil_mss_assert_resets(drv);
+	/* Wait 6 32kHz sleep cycles for reset */
+	udelay(200);
+	ret = pil_mss_deassert_resets(drv);
 
 	if (drv->is_booted) {
 		pil_mss_disable_clks(drv);
@@ -450,6 +510,7 @@
 {
 	struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
 	phys_addr_t start_addr = pil_get_entry_addr(pil);
+	u32 debug_val;
 	int ret;
 
 	if (drv->mba_dp_phys)
@@ -463,15 +524,22 @@
 	if (ret)
 		goto err_power;
 
-	/* Deassert reset to subsystem and wait for propagation */
-	ret = pil_mss_restart_reg(drv, 0);
-	if (ret)
-		goto err_restart;
-
 	ret = pil_mss_enable_clks(drv);
 	if (ret)
 		goto err_clks;
 
+	/* Save state of modem debug register before full reset */
+	debug_val = readl_relaxed(drv->reg_base + QDSP6SS_DBG_CFG);
+
+	/* Assert reset to subsystem */
+	pil_mss_assert_resets(drv);
+	/* Wait 6 32kHz sleep cycles for reset */
+	udelay(200);
+	ret = pil_mss_deassert_resets(drv);
+	if (ret)
+		goto err_restart;
+
+	writel_relaxed(debug_val, drv->reg_base + QDSP6SS_DBG_CFG);
 	if (modem_dbg_cfg)
 		writel_relaxed(modem_dbg_cfg, drv->reg_base + QDSP6SS_DBG_CFG);
 
@@ -519,12 +587,11 @@
 
 err_q6v5_reset:
 	modem_log_rmb_regs(drv->rmb_base);
+err_restart:
 	pil_mss_disable_clks(drv);
 	if (drv->ahb_clk_vote)
 		clk_disable_unprepare(drv->ahb_clk);
 err_clks:
-	pil_mss_restart_reg(drv, 1);
-err_restart:
 	pil_mss_power_down(drv);
 err_power:
 	return ret;
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index bbde4b6..df0c609c 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -284,6 +284,20 @@
 	if (!q6->restart_reg)
 		return -ENOMEM;
 
+	q6->pdc_sync = NULL;
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pdc_sync");
+	if (res) {
+		q6->pdc_sync = devm_ioremap(&pdev->dev,
+						res->start, resource_size(res));
+	}
+
+	q6->alt_reset = NULL;
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "alt_reset");
+	if (res) {
+		q6->alt_reset = devm_ioremap(&pdev->dev,
+						res->start, resource_size(res));
+	}
+
 	q6->vreg = NULL;
 
 	prop = of_find_property(pdev->dev.of_node, "vdd_mss-supply", NULL);
diff --git a/drivers/soc/qcom/pil-q6v5.h b/drivers/soc/qcom/pil-q6v5.h
index 1725253..9b4c811 100644
--- a/drivers/soc/qcom/pil-q6v5.h
+++ b/drivers/soc/qcom/pil-q6v5.h
@@ -44,6 +44,8 @@
 	void __iomem *axi_halt_mss;
 	void __iomem *axi_halt_nc;
 	void __iomem *restart_reg;
+	void __iomem *pdc_sync;
+	void __iomem *alt_reset;
 	struct regulator *vreg;
 	struct regulator *vreg_cx;
 	struct regulator *vreg_mx;
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index b3c1150..e30c159 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -88,8 +88,9 @@
 	struct rpmh_mbox *rpm = rc->rpmh;
 	struct rpmh_msg *msg = NULL;
 	int pos;
+	unsigned long flags;
 
-	spin_lock(&rpm->lock);
+	spin_lock_irqsave(&rpm->lock, flags);
 	pos = find_first_zero_bit(rpm->fast_req, RPMH_MAX_FAST_RES);
 	if (pos != RPMH_MAX_FAST_RES) {
 		bitmap_set(rpm->fast_req, pos, 1);
@@ -98,7 +99,7 @@
 		msg->bit = pos;
 		msg->rc = rc;
 	}
-	spin_unlock(&rpm->lock);
+	spin_unlock_irqrestore(&rpm->lock, flags);
 
 	return msg;
 }
@@ -117,6 +118,7 @@
 	struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
 	atomic_t *wc = rpm_msg->wait_count;
 	wait_queue_head_t *waitq = rpm_msg->waitq;
+	unsigned long flags;
 
 	rpm_msg->err = r;
 
@@ -143,9 +145,9 @@
 
 	/* If we allocated the pool, set it as available */
 	if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
-		spin_lock(&rpm->lock);
+		spin_lock_irqsave(&rpm->lock, flags);
 		bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
-		spin_unlock(&rpm->lock);
+		spin_unlock_irqrestore(&rpm->lock, flags);
 	}
 
 	/* Signal the blocking thread we are done */
@@ -174,8 +176,9 @@
 {
 	struct rpmh_req *req;
 	struct rpmh_mbox *rpm = rc->rpmh;
+	unsigned long flags;
 
-	spin_lock(&rpm->lock);
+	spin_lock_irqsave(&rpm->lock, flags);
 	req = __find_req(rc, cmd->addr);
 	if (req)
 		goto existing;
@@ -210,7 +213,7 @@
 
 unlock:
 	rpm->dirty = true;
-	spin_unlock(&rpm->lock);
+	spin_unlock_irqrestore(&rpm->lock, flags);
 
 	return req;
 }
@@ -566,6 +569,7 @@
 {
 	DEFINE_RPMH_MSG_ONSTACK(rc, 0, NULL, NULL, rpm_msg);
 	struct rpmh_mbox *rpm;
+	unsigned long flags;
 
 	if (IS_ERR_OR_NULL(rc))
 		return -EINVAL;
@@ -577,9 +581,9 @@
 	rpm_msg.msg.invalidate = true;
 	rpm_msg.msg.is_complete = false;
 
-	spin_lock(&rpm->lock);
+	spin_lock_irqsave(&rpm->lock, flags);
 	rpm->dirty = true;
-	spin_unlock(&rpm->lock);
+	spin_unlock_irqrestore(&rpm->lock, flags);
 
 	return mbox_send_controller_data(rc->chan, &rpm_msg.msg);
 }
@@ -667,6 +671,7 @@
 	struct rpmh_req *p;
 	struct rpmh_mbox *rpm = rc->rpmh;
 	int ret;
+	unsigned long flags;
 
 	if (IS_ERR_OR_NULL(rc))
 		return -EINVAL;
@@ -677,13 +682,13 @@
 	if (!mbox_controller_is_idle(rc->chan))
 		return -EBUSY;
 
-	spin_lock(&rpm->lock);
+	spin_lock_irqsave(&rpm->lock, flags);
 	if (!rpm->dirty) {
 		pr_debug("Skipping flush, TCS has latest data.\n");
-		spin_unlock(&rpm->lock);
+		spin_unlock_irqrestore(&rpm->lock, flags);
 		return 0;
 	}
-	spin_unlock(&rpm->lock);
+	spin_unlock_irqrestore(&rpm->lock, flags);
 
 	/*
 	 * Nobody else should be calling this function other than sleep,
@@ -704,9 +709,9 @@
 			return ret;
 	}
 
-	spin_lock(&rpm->lock);
+	spin_lock_irqsave(&rpm->lock, flags);
 	rpm->dirty = false;
-	spin_unlock(&rpm->lock);
+	spin_unlock_irqrestore(&rpm->lock, flags);
 
 	return 0;
 }
diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c
index 2855a15..d8c5a8f 100644
--- a/drivers/soc/qcom/system_pm.c
+++ b/drivers/soc/qcom/system_pm.c
@@ -56,9 +56,13 @@
 	 * Set up the wake up value offset from the current time.
 	 * Convert us to ns to allow div by 19.2 Mhz tick timer.
 	 */
-	sleep_val *= NSEC_PER_USEC;
-	do_div(sleep_val, NSEC_PER_SEC/ARCH_TIMER_HZ);
-	sleep_val += arch_counter_get_cntvct();
+	if (sleep_val) {
+		sleep_val *= NSEC_PER_USEC;
+		do_div(sleep_val, NSEC_PER_SEC/ARCH_TIMER_HZ);
+		sleep_val += arch_counter_get_cntvct();
+	} else {
+		sleep_val = ~0ULL;
+	}
 
 	return setup_wakeup(sleep_val);
 }
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index 74f5ce0..bfaf7c7 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -57,6 +57,7 @@
 #define LIMITS_DOMAIN_MIN           0x444D494E
 
 #define LIMITS_TEMP_DEFAULT         75000
+#define LIMITS_TEMP_HIGH_THRESH_MAX 120000
 #define LIMITS_LOW_THRESHOLD_OFFSET 500
 #define LIMITS_POLLING_DELAY_MS     10
 #define LIMITS_CLUSTER_0_REQ        0x179C1B04
@@ -259,7 +260,7 @@
 	struct limits_dcvs_hw *hw = (struct limits_dcvs_hw *)data;
 	int ret = 0;
 
-	if (high < LIMITS_LOW_THRESHOLD_OFFSET || low < 0) {
+	if (high >= LIMITS_TEMP_HIGH_THRESH_MAX || low < 0) {
 		pr_err("Value out of range low:%d high:%d\n",
 				low, high);
 		return -EINVAL;
diff --git a/drivers/thermal/qpnp-temp-alarm.c b/drivers/thermal/qpnp-temp-alarm.c
index e86a297..09c95e5 100644
--- a/drivers/thermal/qpnp-temp-alarm.c
+++ b/drivers/thermal/qpnp-temp-alarm.c
@@ -28,6 +28,8 @@
 #include <linux/thermal.h>
 #include <linux/qpnp/qpnp-adc.h>
 
+#include "thermal_core.h"
+
 #define QPNP_TM_DRIVER_NAME "qcom,qpnp-temp-alarm"
 
 enum qpnp_tm_registers {
@@ -97,7 +99,6 @@
 	unsigned int			subtype;
 	enum qpnp_tm_adc_type		adc_type;
 	int				temperature;
-	enum thermal_device_mode	mode;
 	unsigned int			thresh;
 	unsigned int			clock_rate;
 	unsigned int			stage;
@@ -105,18 +106,12 @@
 	int				irq;
 	enum qpnp_vadc_channels		adc_channel;
 	u16				base_addr;
-	bool				allow_software_override;
 	struct qpnp_vadc_chip		*vadc_dev;
 };
 
 /* Delay between TEMP_STAT IRQ going high and status value changing in ms. */
 #define STATUS_REGISTER_DELAY_MS       40
 
-enum pmic_thermal_override_mode {
-	SOFTWARE_OVERRIDE_DISABLED = 0,
-	SOFTWARE_OVERRIDE_ENABLED,
-};
-
 /* This array maps from GEN2 alarm state to GEN1 alarm stage */
 const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3};
 
@@ -156,28 +151,6 @@
 	return rc;
 }
 
-
-static inline int qpnp_tm_shutdown_override(struct qpnp_tm_chip *chip,
-			    enum pmic_thermal_override_mode mode)
-{
-	int rc = 0;
-	u8 reg;
-
-	if (chip->allow_software_override) {
-		reg = chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK;
-		reg |= (chip->clock_rate << SHUTDOWN_CTRL1_CLK_RATE_SHIFT)
-			& SHUTDOWN_CTRL1_CLK_RATE_MASK;
-
-		if (mode == SOFTWARE_OVERRIDE_ENABLED)
-			reg |= SHUTDOWN_CTRL1_OVERRIDE_STAGE2
-				| SHUTDOWN_CTRL1_OVERRIDE_STAGE3;
-
-		rc = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, &reg, 1);
-	}
-
-	return rc;
-}
-
 static int qpnp_tm_update_temp(struct qpnp_tm_chip *chip)
 {
 	struct qpnp_vadc_result adc_result;
@@ -274,10 +247,9 @@
 	return 0;
 }
 
-static int qpnp_tz_get_temp_no_adc(struct thermal_zone_device *thermal,
-				     int *temperature)
+static int qpnp_tz_get_temp_no_adc(void *data, int *temperature)
 {
-	struct qpnp_tm_chip *chip = thermal->devdata;
+	struct qpnp_tm_chip *chip = (struct qpnp_tm_chip *)data;
 	int rc;
 
 	if (!temperature)
@@ -292,10 +264,9 @@
 	return 0;
 }
 
-static int qpnp_tz_get_temp_qpnp_adc(struct thermal_zone_device *thermal,
-				      int *temperature)
+static int qpnp_tz_get_temp_qpnp_adc(void *data, int *temperature)
 {
-	struct qpnp_tm_chip *chip = thermal->devdata;
+	struct qpnp_tm_chip *chip = (struct qpnp_tm_chip *)data;
 	int rc;
 
 	if (!temperature)
@@ -314,121 +285,12 @@
 	return 0;
 }
 
-static int qpnp_tz_get_mode(struct thermal_zone_device *thermal,
-			      enum thermal_device_mode *mode)
-{
-	struct qpnp_tm_chip *chip = thermal->devdata;
-
-	if (!mode)
-		return -EINVAL;
-
-	*mode = chip->mode;
-
-	return 0;
-}
-
-static int qpnp_tz_set_mode(struct thermal_zone_device *thermal,
-			      enum thermal_device_mode mode)
-{
-	struct qpnp_tm_chip *chip = thermal->devdata;
-	int rc = 0;
-
-	if (mode != chip->mode) {
-		if (mode == THERMAL_DEVICE_ENABLED)
-			rc = qpnp_tm_shutdown_override(chip,
-				SOFTWARE_OVERRIDE_ENABLED);
-		else
-			rc = qpnp_tm_shutdown_override(chip,
-				SOFTWARE_OVERRIDE_DISABLED);
-
-		chip->mode = mode;
-	}
-
-	return rc;
-}
-
-static int qpnp_tz_get_trip_type(struct thermal_zone_device *thermal,
-				   int trip, enum thermal_trip_type *type)
-{
-	if (trip < 0 || !type)
-		return -EINVAL;
-
-	switch (trip) {
-	case TRIP_STAGE3:
-		*type = THERMAL_TRIP_CRITICAL;
-		break;
-	case TRIP_STAGE2:
-		*type = THERMAL_TRIP_HOT;
-		break;
-	case TRIP_STAGE1:
-		*type = THERMAL_TRIP_HOT;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int qpnp_tz_get_trip_temp(struct thermal_zone_device *thermal,
-				   int trip, int *temperature)
-{
-	struct qpnp_tm_chip *chip = thermal->devdata;
-	int thresh_temperature;
-
-	if (trip < 0 || !temperature)
-		return -EINVAL;
-
-	thresh_temperature = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN;
-
-	switch (trip) {
-	case TRIP_STAGE3:
-		thresh_temperature += 2 * TEMP_STAGE_STEP;
-		break;
-	case TRIP_STAGE2:
-		thresh_temperature += TEMP_STAGE_STEP;
-		break;
-	case TRIP_STAGE1:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	*temperature = thresh_temperature;
-
-	return 0;
-}
-
-static int qpnp_tz_get_crit_temp(struct thermal_zone_device *thermal,
-				   int *temperature)
-{
-	struct qpnp_tm_chip *chip = thermal->devdata;
-
-	if (!temperature)
-		return -EINVAL;
-
-	*temperature = chip->thresh * TEMP_THRESH_STEP + TEMP_THRESH_MIN +
-		2 * TEMP_STAGE_STEP;
-
-	return 0;
-}
-
-static struct thermal_zone_device_ops qpnp_thermal_zone_ops_no_adc = {
+static struct thermal_zone_of_device_ops qpnp_thermal_zone_ops_no_adc = {
 	.get_temp = qpnp_tz_get_temp_no_adc,
-	.get_mode = qpnp_tz_get_mode,
-	.set_mode = qpnp_tz_set_mode,
-	.get_trip_type = qpnp_tz_get_trip_type,
-	.get_trip_temp = qpnp_tz_get_trip_temp,
-	.get_crit_temp = qpnp_tz_get_crit_temp,
 };
 
-static struct thermal_zone_device_ops qpnp_thermal_zone_ops_qpnp_adc = {
+static struct thermal_zone_of_device_ops qpnp_thermal_zone_ops_qpnp_adc = {
 	.get_temp = qpnp_tz_get_temp_qpnp_adc,
-	.get_mode = qpnp_tz_get_mode,
-	.set_mode = qpnp_tz_set_mode,
-	.get_trip_type = qpnp_tz_get_trip_type,
-	.get_trip_temp = qpnp_tz_get_trip_temp,
-	.get_crit_temp = qpnp_tz_get_crit_temp,
 };
 
 static void qpnp_tm_work(struct work_struct *work)
@@ -474,11 +336,7 @@
 				chip->tm_name, stage_new, chip->stage,
 				chip->thresh, chip->temperature);
 
-		thermal_zone_device_update(chip->tz_dev,
-						THERMAL_EVENT_UNSPECIFIED);
-
-		/* Notify user space */
-		sysfs_notify(&chip->tz_dev->device.kobj, NULL, "type");
+		of_thermal_handle_trip(chip->tz_dev);
 	}
 
 bail:
@@ -539,7 +397,7 @@
 	struct device_node *node;
 	unsigned int base;
 	struct qpnp_tm_chip *chip;
-	struct thermal_zone_device_ops *tz_ops;
+	struct thermal_zone_of_device_ops *tz_ops;
 	char *tm_name;
 	u32 default_temperature;
 	int rc = 0;
@@ -640,9 +498,6 @@
 	else
 		tz_ops = &qpnp_thermal_zone_ops_no_adc;
 
-	chip->allow_software_override
-		= of_property_read_bool(node, "qcom,allow-override");
-
 	default_temperature = DEFAULT_NO_ADC_TEMP;
 	rc = of_property_read_u32(node, "qcom,default-temp",
 					&default_temperature);
@@ -686,18 +541,8 @@
 		}
 	}
 
-	/* Start in HW control; switch to SW control when user changes mode. */
-	chip->mode = THERMAL_DEVICE_DISABLED;
-	rc = qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
-	if (rc) {
-		dev_err(&pdev->dev,
-			"%s: qpnp_tm_shutdown_override() failed, rc=%d\n",
-			__func__, rc);
-		goto err_cancel_work;
-	}
-
-	chip->tz_dev = thermal_zone_device_register(tm_name, TRIP_NUM, 0, chip,
-			tz_ops, NULL, 0, 0);
+	chip->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0, chip,
+							tz_ops);
 	if (chip->tz_dev == NULL) {
 		dev_err(&pdev->dev,
 			"%s: thermal_zone_device_register() failed.\n",
@@ -717,7 +562,7 @@
 	return 0;
 
 err_free_tz:
-	thermal_zone_device_unregister(chip->tz_dev);
+	thermal_zone_of_sensor_unregister(&pdev->dev, chip->tz_dev);
 err_cancel_work:
 	cancel_delayed_work_sync(&chip->irq_work);
 	kfree(chip->tm_name);
@@ -731,10 +576,9 @@
 {
 	struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev);
 
+	thermal_zone_of_sensor_unregister(&pdev->dev, chip->tz_dev);
 	dev_set_drvdata(&pdev->dev, NULL);
-	thermal_zone_device_unregister(chip->tz_dev);
 	kfree(chip->tm_name);
-	qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
 	free_irq(chip->irq, chip);
 	cancel_delayed_work_sync(&chip->irq_work);
 	kfree(chip);
@@ -742,38 +586,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_PM
-static int qpnp_tm_suspend(struct device *dev)
-{
-	struct qpnp_tm_chip *chip = dev_get_drvdata(dev);
-
-	/* Clear override bits in suspend to allow hardware control */
-	qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
-
-	return 0;
-}
-
-static int qpnp_tm_resume(struct device *dev)
-{
-	struct qpnp_tm_chip *chip = dev_get_drvdata(dev);
-
-	/* Override hardware actions so software can control */
-	if (chip->mode == THERMAL_DEVICE_ENABLED)
-		qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_ENABLED);
-
-	return 0;
-}
-
-static const struct dev_pm_ops qpnp_tm_pm_ops = {
-	.suspend = qpnp_tm_suspend,
-	.resume = qpnp_tm_resume,
-};
-
-#define QPNP_TM_PM_OPS	(&qpnp_tm_pm_ops)
-#else
-#define QPNP_TM_PM_OPS	NULL
-#endif
-
 static const struct of_device_id qpnp_tm_match_table[] = {
 	{ .compatible = QPNP_TM_DRIVER_NAME, },
 	{}
@@ -789,7 +601,6 @@
 		.name		= QPNP_TM_DRIVER_NAME,
 		.of_match_table	= qpnp_tm_match_table,
 		.owner		= THIS_MODULE,
-		.pm		= QPNP_TM_PM_OPS,
 	},
 	.probe	  = qpnp_tm_probe,
 	.remove	  = qpnp_tm_remove,
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index df9be34..da1a0e6 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -94,8 +94,10 @@
 
 #define UART_OVERSAMPLING	(32)
 #define STALE_TIMEOUT		(16)
+#define DEFAULT_BITS_PER_CHAR	(10)
 #define GENI_UART_NR_PORTS	(15)
 #define DEF_FIFO_DEPTH_WORDS	(16)
+#define DEF_TX_WM		(2)
 #define DEF_FIFO_WIDTH_BITS	(32)
 #define UART_CORE2X_VOTE	(10000)
 #define DEFAULT_SE_CLK		(19200000)
@@ -134,6 +136,7 @@
 			unsigned int rx_fifo_wc,
 			unsigned int rx_last_byte_valid,
 			unsigned int rx_last);
+static unsigned int msm_geni_serial_tx_empty(struct uart_port *port);
 
 static atomic_t uart_line_id = ATOMIC_INIT(0);
 
@@ -232,7 +235,7 @@
 }
 
 static void msm_geni_serial_setup_tx(struct uart_port *uport,
-					unsigned int xmit_size)
+				unsigned int xmit_size)
 {
 	u32 m_cmd = 0;
 
@@ -324,7 +327,6 @@
 	int b = (int) c;
 	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
 
-	se_config_packing(uport->membase, 8, 1, false);
 	geni_write_reg_nolog(port->tx_wm, uport->membase,
 					SE_GENI_TX_WATERMARK_REG);
 	msm_geni_serial_setup_tx(uport, 1);
@@ -358,10 +360,11 @@
 __msm_geni_serial_console_write(struct uart_port *uport, const char *s,
 				unsigned int count)
 {
-	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
 	int new_line = 0;
 	int i;
 	int bytes_to_send = count;
+	int fifo_depth = DEF_FIFO_DEPTH_WORDS;
+	int tx_wm = DEF_TX_WM;
 
 	for (i = 0; i < count; i++) {
 		if (s[i] == '\n')
@@ -369,14 +372,13 @@
 	}
 
 	bytes_to_send += new_line;
-	se_config_packing(uport->membase, 8, 1, false);
-	geni_write_reg_nolog(port->tx_wm, uport->membase,
+	geni_write_reg_nolog(tx_wm, uport->membase,
 					SE_GENI_TX_WATERMARK_REG);
 	msm_geni_serial_setup_tx(uport, bytes_to_send);
 	i = 0;
 	while (i < count) {
 		u32 chars_to_write = 0;
-		u32 avail_fifo_bytes = (port->tx_fifo_depth - port->tx_wm);
+		u32 avail_fifo_bytes = (fifo_depth - tx_wm);
 		/*
 		 * If the WM bit never set, then the Tx state machine is not
 		 * in a valid state, so break, cancel/abort any existing
@@ -473,10 +475,12 @@
 	unsigned int geni_m_irq_en;
 	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
 
+	if (!msm_geni_serial_tx_empty(uport))
+		return;
+
 	geni_m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN);
 	geni_m_irq_en |= M_TX_FIFO_WATERMARK_EN;
 
-	se_config_packing(uport->membase, 8, 4, false);
 	geni_write_reg_nolog(port->tx_wm, uport->membase,
 						SE_GENI_TX_WATERMARK_REG);
 	geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
@@ -516,6 +520,8 @@
 {
 	unsigned int geni_s_irq_en;
 	unsigned int geni_m_irq_en;
+	unsigned long cfg0, cfg1;
+	unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
 
 	msm_geni_serial_abort_rx(uport);
 	geni_s_irq_en = geni_read_reg_nolog(uport->membase,
@@ -524,7 +530,10 @@
 						SE_GENI_M_IRQ_EN);
 	geni_s_irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN;
 	geni_m_irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
-
+	se_get_packing_config(8, 4, false, &cfg0, &cfg1);
+	geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_RX_PACKING_CFG0);
+	geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_RX_PACKING_CFG1);
+	geni_write_reg_nolog(rxstale, uport->membase, SE_UART_RX_STALE_CNT);
 	geni_setup_s_cmd(uport->membase, UART_START_READ, 0);
 	geni_write_reg_nolog(geni_s_irq_en, uport->membase, SE_GENI_S_IRQ_EN);
 	geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN);
@@ -622,7 +631,8 @@
 	int i = 0;
 	unsigned int tx_fifo_status;
 	unsigned int xmit_size;
-	unsigned int fifo_width_bytes = msm_port->tx_fifo_width >> 3;
+	unsigned int fifo_width_bytes =
+		(uart_console(uport) ? 1 : (msm_port->tx_fifo_width >> 3));
 
 	tx_fifo_status = geni_read_reg_nolog(uport->membase,
 					SE_GENI_TX_FIFO_STATUS);
@@ -664,6 +674,8 @@
 		wmb();
 	}
 	msm_geni_serial_poll_cancel_tx(uport);
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(uport);
 exit_handle_tx:
 	return ret;
 }
@@ -765,17 +777,32 @@
 {
 	int ret = 0;
 	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+	unsigned long cfg0, cfg1;
 
-	/* For now only assume FIFO mode. */
-	msm_port->xfer_mode = FIFO_MODE;
-	set_rfr_wm(msm_port);
-	ret = geni_se_init(uport->membase, msm_port->xfer_mode,
+
+	if (!uart_console(uport)) {
+		/* For now only assume FIFO mode. */
+		msm_port->xfer_mode = FIFO_MODE;
+		set_rfr_wm(msm_port);
+		ret = geni_se_init(uport->membase, msm_port->xfer_mode,
 					msm_port->rx_wm, msm_port->rx_rfr);
-	if (ret) {
-		dev_err(uport->dev, "%s: Fail\n", __func__);
-		goto exit_portsetup;
+		if (ret) {
+			dev_err(uport->dev, "%s: Fail\n", __func__);
+			goto exit_portsetup;
+		}
+		se_get_packing_config(8, 4, false, &cfg0, &cfg1);
+		geni_write_reg_nolog(cfg0, uport->membase,
+						SE_GENI_TX_PACKING_CFG0);
+		geni_write_reg_nolog(cfg1, uport->membase,
+						SE_GENI_TX_PACKING_CFG1);
+	} else {
+		set_rfr_wm(msm_port);
+		se_get_packing_config(8, 1, false, &cfg0, &cfg1);
+		geni_write_reg_nolog(cfg0, uport->membase,
+						SE_GENI_TX_PACKING_CFG0);
+		geni_write_reg_nolog(cfg1, uport->membase,
+						SE_GENI_TX_PACKING_CFG1);
 	}
-
 	msm_port->port_setup = true;
 	/*
 	 * Ensure Port setup related IO completes before returning to
@@ -848,7 +875,7 @@
 static void geni_serial_write_term_regs(struct uart_port *uport, u32 loopback,
 		u32 tx_trans_cfg, u32 tx_parity_cfg, u32 rx_trans_cfg,
 		u32 rx_parity_cfg, u32 bits_per_char, u32 stop_bit_len,
-		u32 rxstale, u32 s_clk_cfg)
+		u32 s_clk_cfg)
 {
 	geni_write_reg_nolog(loopback, uport->membase, SE_UART_LOOPBACK_CFG);
 	geni_write_reg_nolog(tx_trans_cfg, uport->membase,
@@ -865,7 +892,6 @@
 							SE_UART_RX_WORD_LEN);
 	geni_write_reg_nolog(stop_bit_len, uport->membase,
 						SE_UART_TX_STOP_BIT_LEN);
-	geni_write_reg_nolog(rxstale, uport->membase, SE_UART_RX_STALE_CNT);
 	geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_M_CLK_CFG);
 	geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_S_CLK_CFG);
 }
@@ -901,7 +927,6 @@
 	unsigned int rx_trans_cfg;
 	unsigned int rx_parity_cfg;
 	unsigned int stop_bit_len;
-	unsigned int rxstale;
 	unsigned int clk_div;
 	unsigned long ser_clk_cfg = 0;
 	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
@@ -966,8 +991,6 @@
 		break;
 	}
 
-	/* stale timer, set this to 16 characters. */
-	rxstale = bits_per_char * STALE_TIMEOUT;
 
 	/* stop bits */
 	if (termios->c_cflag & CSTOPB)
@@ -984,7 +1007,7 @@
 
 	geni_serial_write_term_regs(uport, port->loopback, tx_trans_cfg,
 		tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
-		stop_bit_len, rxstale, ser_clk_cfg);
+		stop_bit_len, ser_clk_cfg);
 exit_set_termios:
 	return;
 
@@ -1066,7 +1089,6 @@
 {
 	struct uart_port *uport = &dev->port;
 	int ret = 0;
-	struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
 	u32 tx_trans_cfg = 0;
 	u32 tx_parity_cfg = 0;
 	u32 rx_trans_cfg = 0;
@@ -1078,6 +1100,7 @@
 	u32 baud = 115200;
 	u32 clk_div;
 	unsigned long clk_rate;
+	unsigned long cfg0, cfg1;
 
 	if (!uport->membase) {
 		ret = -ENOMEM;
@@ -1089,13 +1112,8 @@
 		goto exit_geni_serial_earlyconsetup;
 	}
 
-	msm_port->xfer_mode = FIFO_MODE;
-	set_rfr_wm(msm_port);
-	msm_port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
-	msm_port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
-	msm_port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
-	geni_se_init(uport->membase, msm_port->xfer_mode, msm_port->rx_wm,
-							msm_port->rx_rfr);
+	geni_se_init(uport->membase, FIFO_MODE, (DEF_FIFO_DEPTH_WORDS >> 1),
+						(DEF_FIFO_DEPTH_WORDS - 2));
 	/*
 	 * Ignore Flow control.
 	 * Disable Tx Parity.
@@ -1120,6 +1138,9 @@
 
 	s_clk_cfg |= SER_CLK_EN;
 	s_clk_cfg |= (clk_div << CLK_DIV_SHFT);
+	se_get_packing_config(8, 1, false, &cfg0, &cfg1);
+	geni_write_reg_nolog(cfg0, uport->membase, SE_GENI_TX_PACKING_CFG0);
+	geni_write_reg_nolog(cfg1, uport->membase, SE_GENI_TX_PACKING_CFG1);
 
 	/*
 	 * Make an unconditional cancel on the main sequencer to reset
@@ -1128,7 +1149,7 @@
 	msm_geni_serial_poll_cancel_tx(uport);
 	geni_serial_write_term_regs(uport, 0, tx_trans_cfg,
 		tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
-		stop_bit, rx_stale, s_clk_cfg);
+		stop_bit, s_clk_cfg);
 
 	dev->con->write = msm_geni_serial_early_console_write;
 	dev->con->setup = NULL;
@@ -1435,9 +1456,11 @@
 	struct msm_geni_serial_port *port = platform_get_drvdata(pdev);
 	struct uart_port *uport = &port->uport;
 
-	if (uart_console(uport))
+	if (uart_console(uport)) {
+		se_geni_resources_on(&port->serial_rsc);
 		uart_resume_port((struct uart_driver *)uport->private_data,
 									uport);
+	}
 	return 0;
 }
 #else
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 203287f..94661cf 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -930,7 +930,6 @@
 	bool use_persistent:1; /* use persistent instead of durable handles */
 #ifdef CONFIG_CIFS_SMB2
 	bool print:1;		/* set if connection to printer share */
-	bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
 	__le32 capabilities;
 	__u32 share_flags;
 	__u32 maximal_access;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index fc537c2..87b87e0 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -1015,6 +1015,15 @@
 	return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
 }
 
+static bool
+cifs_can_echo(struct TCP_Server_Info *server)
+{
+	if (server->tcpStatus == CifsGood)
+		return true;
+
+	return false;
+}
+
 struct smb_version_operations smb1_operations = {
 	.send_cancel = send_nt_cancel,
 	.compare_fids = cifs_compare_fids,
@@ -1049,6 +1058,7 @@
 	.get_dfs_refer = CIFSGetDFSRefer,
 	.qfs_tcon = cifs_qfs_tcon,
 	.is_path_accessible = cifs_is_path_accessible,
+	.can_echo = cifs_can_echo,
 	.query_path_info = cifs_query_path_info,
 	.query_file_info = cifs_query_file_info,
 	.get_srv_inum = cifs_get_srv_inum,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 7080dac..8021853 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1084,9 +1084,6 @@
 	else
 		return -EIO;
 
-	if (tcon && tcon->bad_network_name)
-		return -ENOENT;
-
 	if ((tcon && tcon->seal) &&
 	    ((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) {
 		cifs_dbg(VFS, "encryption requested but no server support");
@@ -1188,8 +1185,6 @@
 tcon_error_exit:
 	if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
 		cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
-		if (tcon)
-			tcon->bad_network_name = true;
 	}
 	goto tcon_exit;
 }
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index ca16c5d..87ab02e 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -622,6 +622,11 @@
 		return err;
 
 	lock_2_inodes(dir, inode);
+
+	/* Handle O_TMPFILE corner case, it is allowed to link a O_TMPFILE. */
+	if (inode->i_nlink == 0)
+		ubifs_delete_orphan(c, inode->i_ino);
+
 	inc_nlink(inode);
 	ihold(inode);
 	inode->i_ctime = ubifs_current_time(inode);
@@ -641,6 +646,8 @@
 	dir->i_size -= sz_change;
 	dir_ui->ui_size = dir->i_size;
 	drop_nlink(inode);
+	if (inode->i_nlink == 0)
+		ubifs_add_orphan(c, inode->i_ino);
 	unlock_2_inodes(dir, inode);
 	ubifs_release_budget(c, &req);
 	iput(inode);
@@ -1088,9 +1095,6 @@
 	struct timespec time;
 	unsigned int uninitialized_var(saved_nlink);
 
-	if (flags & ~RENAME_NOREPLACE)
-		return -EINVAL;
-
 	/*
 	 * Budget request settings: deletion direntry, new direntry, removing
 	 * the old inode, and changing old and new parent directory inodes.
diff --git a/include/dt-bindings/clock/qcom,camcc-sdm845.h b/include/dt-bindings/clock/qcom,camcc-sdm845.h
index e169172..0d9d9f6 100644
--- a/include/dt-bindings/clock/qcom,camcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,camcc-sdm845.h
@@ -34,71 +34,70 @@
 #define CAM_CC_CSIPHY0_CLK					17
 #define CAM_CC_CSIPHY1_CLK					18
 #define CAM_CC_CSIPHY2_CLK					19
-#define CAM_CC_DEBUG_CLK					20
-#define CAM_CC_FAST_AHB_CLK_SRC					21
-#define CAM_CC_FD_CORE_CLK					22
-#define CAM_CC_FD_CORE_CLK_SRC					23
-#define CAM_CC_FD_CORE_UAR_CLK					24
-#define CAM_CC_ICP_APB_CLK					25
-#define CAM_CC_ICP_ATB_CLK					26
-#define CAM_CC_ICP_CLK						27
-#define CAM_CC_ICP_CLK_SRC					28
-#define CAM_CC_ICP_CTI_CLK					29
-#define CAM_CC_ICP_TS_CLK					30
-#define CAM_CC_IFE_0_AXI_CLK					31
-#define CAM_CC_IFE_0_CLK					32
-#define CAM_CC_IFE_0_CLK_SRC					33
-#define CAM_CC_IFE_0_CPHY_RX_CLK				34
-#define CAM_CC_IFE_0_CSID_CLK					35
-#define CAM_CC_IFE_0_CSID_CLK_SRC				36
-#define CAM_CC_IFE_0_DSP_CLK					37
-#define CAM_CC_IFE_1_AXI_CLK					38
-#define CAM_CC_IFE_1_CLK					39
-#define CAM_CC_IFE_1_CLK_SRC					40
-#define CAM_CC_IFE_1_CPHY_RX_CLK				41
-#define CAM_CC_IFE_1_CSID_CLK					42
-#define CAM_CC_IFE_1_CSID_CLK_SRC				43
-#define CAM_CC_IFE_1_DSP_CLK					44
-#define CAM_CC_IFE_LITE_CLK					45
-#define CAM_CC_IFE_LITE_CLK_SRC					46
-#define CAM_CC_IFE_LITE_CPHY_RX_CLK				47
-#define CAM_CC_IFE_LITE_CSID_CLK				48
-#define CAM_CC_IFE_LITE_CSID_CLK_SRC				49
-#define CAM_CC_IPE_0_AHB_CLK					50
-#define CAM_CC_IPE_0_AREG_CLK					51
-#define CAM_CC_IPE_0_AXI_CLK					52
-#define CAM_CC_IPE_0_CLK					53
-#define CAM_CC_IPE_0_CLK_SRC					54
-#define CAM_CC_IPE_1_AHB_CLK					55
-#define CAM_CC_IPE_1_AREG_CLK					56
-#define CAM_CC_IPE_1_AXI_CLK					57
-#define CAM_CC_IPE_1_CLK					58
-#define CAM_CC_IPE_1_CLK_SRC					59
-#define CAM_CC_JPEG_CLK						60
-#define CAM_CC_JPEG_CLK_SRC					61
-#define CAM_CC_LRME_CLK						62
-#define CAM_CC_LRME_CLK_SRC					63
-#define CAM_CC_MCLK0_CLK					64
-#define CAM_CC_MCLK0_CLK_SRC					65
-#define CAM_CC_MCLK1_CLK					66
-#define CAM_CC_MCLK1_CLK_SRC					67
-#define CAM_CC_MCLK2_CLK					68
-#define CAM_CC_MCLK2_CLK_SRC					69
-#define CAM_CC_MCLK3_CLK					70
-#define CAM_CC_MCLK3_CLK_SRC					71
-#define CAM_CC_PLL0						72
-#define CAM_CC_PLL0_OUT_EVEN					73
-#define CAM_CC_PLL1						74
-#define CAM_CC_PLL1_OUT_EVEN					75
-#define CAM_CC_PLL2						76
-#define CAM_CC_PLL2_OUT_EVEN					77
-#define CAM_CC_PLL2_OUT_ODD					78
-#define CAM_CC_PLL3						79
-#define CAM_CC_PLL3_OUT_EVEN					80
-#define CAM_CC_PLL_TEST_CLK					81
-#define CAM_CC_SLOW_AHB_CLK_SRC					82
-#define CAM_CC_SOC_AHB_CLK					83
-#define CAM_CC_SYS_TMR_CLK					84
+#define CAM_CC_FAST_AHB_CLK_SRC					20
+#define CAM_CC_FD_CORE_CLK					21
+#define CAM_CC_FD_CORE_CLK_SRC					22
+#define CAM_CC_FD_CORE_UAR_CLK					23
+#define CAM_CC_ICP_APB_CLK					24
+#define CAM_CC_ICP_ATB_CLK					25
+#define CAM_CC_ICP_CLK						26
+#define CAM_CC_ICP_CLK_SRC					27
+#define CAM_CC_ICP_CTI_CLK					28
+#define CAM_CC_ICP_TS_CLK					29
+#define CAM_CC_IFE_0_AXI_CLK					30
+#define CAM_CC_IFE_0_CLK					31
+#define CAM_CC_IFE_0_CLK_SRC					32
+#define CAM_CC_IFE_0_CPHY_RX_CLK				33
+#define CAM_CC_IFE_0_CSID_CLK					34
+#define CAM_CC_IFE_0_CSID_CLK_SRC				35
+#define CAM_CC_IFE_0_DSP_CLK					36
+#define CAM_CC_IFE_1_AXI_CLK					37
+#define CAM_CC_IFE_1_CLK					38
+#define CAM_CC_IFE_1_CLK_SRC					39
+#define CAM_CC_IFE_1_CPHY_RX_CLK				40
+#define CAM_CC_IFE_1_CSID_CLK					41
+#define CAM_CC_IFE_1_CSID_CLK_SRC				42
+#define CAM_CC_IFE_1_DSP_CLK					43
+#define CAM_CC_IFE_LITE_CLK					44
+#define CAM_CC_IFE_LITE_CLK_SRC					45
+#define CAM_CC_IFE_LITE_CPHY_RX_CLK				46
+#define CAM_CC_IFE_LITE_CSID_CLK				47
+#define CAM_CC_IFE_LITE_CSID_CLK_SRC				48
+#define CAM_CC_IPE_0_AHB_CLK					49
+#define CAM_CC_IPE_0_AREG_CLK					50
+#define CAM_CC_IPE_0_AXI_CLK					51
+#define CAM_CC_IPE_0_CLK					52
+#define CAM_CC_IPE_0_CLK_SRC					53
+#define CAM_CC_IPE_1_AHB_CLK					54
+#define CAM_CC_IPE_1_AREG_CLK					55
+#define CAM_CC_IPE_1_AXI_CLK					56
+#define CAM_CC_IPE_1_CLK					57
+#define CAM_CC_IPE_1_CLK_SRC					58
+#define CAM_CC_JPEG_CLK						59
+#define CAM_CC_JPEG_CLK_SRC					60
+#define CAM_CC_LRME_CLK						61
+#define CAM_CC_LRME_CLK_SRC					62
+#define CAM_CC_MCLK0_CLK					63
+#define CAM_CC_MCLK0_CLK_SRC					64
+#define CAM_CC_MCLK1_CLK					65
+#define CAM_CC_MCLK1_CLK_SRC					66
+#define CAM_CC_MCLK2_CLK					67
+#define CAM_CC_MCLK2_CLK_SRC					68
+#define CAM_CC_MCLK3_CLK					69
+#define CAM_CC_MCLK3_CLK_SRC					70
+#define CAM_CC_PLL0						71
+#define CAM_CC_PLL0_OUT_EVEN					72
+#define CAM_CC_PLL1						73
+#define CAM_CC_PLL1_OUT_EVEN					74
+#define CAM_CC_PLL2						75
+#define CAM_CC_PLL2_OUT_EVEN					76
+#define CAM_CC_PLL2_OUT_ODD					77
+#define CAM_CC_PLL3						78
+#define CAM_CC_PLL3_OUT_EVEN					79
+#define CAM_CC_PLL_TEST_CLK					80
+#define CAM_CC_SLOW_AHB_CLK_SRC					81
+#define CAM_CC_SOC_AHB_CLK					82
+#define CAM_CC_SYS_TMR_CLK					83
 
 #define TITAN_CAM_CC_BPS_BCR					0
 #define TITAN_CAM_CC_CAMNOC_BCR					1
diff --git a/include/dt-bindings/clock/qcom,dispcc-sdm845.h b/include/dt-bindings/clock/qcom,dispcc-sdm845.h
index b1988e4..24dd11e 100644
--- a/include/dt-bindings/clock/qcom,dispcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,dispcc-sdm845.h
@@ -14,49 +14,48 @@
 #ifndef _DT_BINDINGS_CLK_MSM_DISP_CC_SDM845_H
 #define _DT_BINDINGS_CLK_MSM_DISP_CC_SDM845_H
 
-#define DISP_CC_DEBUG_CLK					0
-#define DISP_CC_MDSS_AHB_CLK					1
-#define DISP_CC_MDSS_AXI_CLK					2
-#define DISP_CC_MDSS_BYTE0_CLK					3
-#define DISP_CC_MDSS_BYTE0_CLK_SRC				4
-#define DISP_CC_MDSS_BYTE0_INTF_CLK				5
-#define DISP_CC_MDSS_BYTE1_CLK					6
-#define DISP_CC_MDSS_BYTE1_CLK_SRC				7
-#define DISP_CC_MDSS_BYTE1_INTF_CLK				8
-#define DISP_CC_MDSS_DP_AUX_CLK					9
-#define DISP_CC_MDSS_DP_AUX_CLK_SRC				10
-#define DISP_CC_MDSS_DP_CRYPTO_CLK				11
-#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC				12
-#define DISP_CC_MDSS_DP_LINK_CLK				13
-#define DISP_CC_MDSS_DP_LINK_CLK_SRC				14
-#define DISP_CC_MDSS_DP_LINK_INTF_CLK				15
-#define DISP_CC_MDSS_DP_PIXEL1_CLK				16
-#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC				17
-#define DISP_CC_MDSS_DP_PIXEL_CLK				18
-#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC				19
-#define DISP_CC_MDSS_ESC0_CLK					20
-#define DISP_CC_MDSS_ESC0_CLK_SRC				21
-#define DISP_CC_MDSS_ESC1_CLK					22
-#define DISP_CC_MDSS_ESC1_CLK_SRC				23
-#define DISP_CC_MDSS_MDP_CLK					24
-#define DISP_CC_MDSS_MDP_CLK_SRC				25
-#define DISP_CC_MDSS_MDP_LUT_CLK				26
-#define DISP_CC_MDSS_PCLK0_CLK					27
-#define DISP_CC_MDSS_PCLK0_CLK_SRC				28
-#define DISP_CC_MDSS_PCLK1_CLK					29
-#define DISP_CC_MDSS_PCLK1_CLK_SRC				30
-#define DISP_CC_MDSS_QDSS_AT_CLK				31
-#define DISP_CC_MDSS_QDSS_TSCTR_DIV8_CLK			32
-#define DISP_CC_MDSS_ROT_CLK					33
-#define DISP_CC_MDSS_ROT_CLK_SRC				34
-#define DISP_CC_MDSS_RSCC_AHB_CLK				35
-#define DISP_CC_MDSS_RSCC_VSYNC_CLK				36
-#define DISP_CC_MDSS_VSYNC_CLK					37
-#define DISP_CC_MDSS_VSYNC_CLK_SRC				38
-#define DISP_CC_PLL0						39
-#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC				40
-#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC				41
-#define DISP_CC_MDSS_DP_LINK_DIV_CLK_SRC			42
+#define DISP_CC_MDSS_AHB_CLK					0
+#define DISP_CC_MDSS_AXI_CLK					1
+#define DISP_CC_MDSS_BYTE0_CLK					2
+#define DISP_CC_MDSS_BYTE0_CLK_SRC				3
+#define DISP_CC_MDSS_BYTE0_INTF_CLK				4
+#define DISP_CC_MDSS_BYTE1_CLK					5
+#define DISP_CC_MDSS_BYTE1_CLK_SRC				6
+#define DISP_CC_MDSS_BYTE1_INTF_CLK				7
+#define DISP_CC_MDSS_DP_AUX_CLK					8
+#define DISP_CC_MDSS_DP_AUX_CLK_SRC				9
+#define DISP_CC_MDSS_DP_CRYPTO_CLK				10
+#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC				11
+#define DISP_CC_MDSS_DP_LINK_CLK				12
+#define DISP_CC_MDSS_DP_LINK_CLK_SRC				13
+#define DISP_CC_MDSS_DP_LINK_INTF_CLK				14
+#define DISP_CC_MDSS_DP_PIXEL1_CLK				15
+#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC				16
+#define DISP_CC_MDSS_DP_PIXEL_CLK				17
+#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC				18
+#define DISP_CC_MDSS_ESC0_CLK					19
+#define DISP_CC_MDSS_ESC0_CLK_SRC				20
+#define DISP_CC_MDSS_ESC1_CLK					21
+#define DISP_CC_MDSS_ESC1_CLK_SRC				22
+#define DISP_CC_MDSS_MDP_CLK					23
+#define DISP_CC_MDSS_MDP_CLK_SRC				24
+#define DISP_CC_MDSS_MDP_LUT_CLK				25
+#define DISP_CC_MDSS_PCLK0_CLK					26
+#define DISP_CC_MDSS_PCLK0_CLK_SRC				27
+#define DISP_CC_MDSS_PCLK1_CLK					28
+#define DISP_CC_MDSS_PCLK1_CLK_SRC				29
+#define DISP_CC_MDSS_QDSS_AT_CLK				30
+#define DISP_CC_MDSS_QDSS_TSCTR_DIV8_CLK			31
+#define DISP_CC_MDSS_ROT_CLK					32
+#define DISP_CC_MDSS_ROT_CLK_SRC				33
+#define DISP_CC_MDSS_RSCC_AHB_CLK				34
+#define DISP_CC_MDSS_RSCC_VSYNC_CLK				35
+#define DISP_CC_MDSS_VSYNC_CLK					36
+#define DISP_CC_MDSS_VSYNC_CLK_SRC				37
+#define DISP_CC_PLL0						38
+#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC				39
+#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC				40
+#define DISP_CC_MDSS_DP_LINK_DIV_CLK_SRC			41
 
 #define DISP_CC_MDSS_CORE_BCR					0
 #define DISP_CC_MDSS_GCC_CLOCKS_BCR				1
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index f7a6978..73a8c0b 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -35,161 +35,158 @@
 #define GCC_CPUSS_GNOC_CLK					17
 #define GCC_CPUSS_RBCPR_CLK					18
 #define GCC_CPUSS_RBCPR_CLK_SRC					19
-#define GCC_CXO_TX1_CLKREF_CLK					20
-#define GCC_DDRSS_GPU_AXI_CLK					21
-#define GCC_DISP_AHB_CLK					22
-#define GCC_DISP_AXI_CLK					23
-#define GCC_DISP_GPLL0_CLK_SRC					24
-#define GCC_DISP_GPLL0_DIV_CLK_SRC				25
-#define GCC_DISP_XO_CLK						26
-#define GCC_GP1_CLK						27
-#define GCC_GP1_CLK_SRC						28
-#define GCC_GP2_CLK						29
-#define GCC_GP2_CLK_SRC						30
-#define GCC_GP3_CLK						31
-#define GCC_GP3_CLK_SRC						32
-#define GCC_GPU_CFG_AHB_CLK					33
-#define GCC_GPU_GPLL0_CLK_SRC					34
-#define GCC_GPU_GPLL0_DIV_CLK_SRC				35
-#define GCC_GPU_MEMNOC_GFX_CLK					36
-#define GCC_GPU_SNOC_DVM_GFX_CLK				37
-#define GCC_MSS_AXIS2_CLK					38
-#define GCC_MSS_CFG_AHB_CLK					39
-#define GCC_MSS_GPLL0_DIV_CLK_SRC				40
-#define GCC_MSS_MFAB_AXIS_CLK					41
-#define GCC_MSS_Q6_MEMNOC_AXI_CLK				42
-#define GCC_MSS_SNOC_AXI_CLK					43
-#define GCC_PCIE_0_AUX_CLK					44
-#define GCC_PCIE_0_AUX_CLK_SRC					45
-#define GCC_PCIE_0_CFG_AHB_CLK					46
-#define GCC_PCIE_0_CLKREF_CLK					47
-#define GCC_PCIE_0_MSTR_AXI_CLK					48
-#define GCC_PCIE_0_PIPE_CLK					49
-#define GCC_PCIE_0_SLV_AXI_CLK					50
-#define GCC_PCIE_0_SLV_Q2A_AXI_CLK				51
-#define GCC_PCIE_1_AUX_CLK					52
-#define GCC_PCIE_1_AUX_CLK_SRC					53
-#define GCC_PCIE_1_CFG_AHB_CLK					54
-#define GCC_PCIE_1_CLKREF_CLK					55
-#define GCC_PCIE_1_MSTR_AXI_CLK					56
-#define GCC_PCIE_1_PIPE_CLK					57
-#define GCC_PCIE_1_SLV_AXI_CLK					58
-#define GCC_PCIE_1_SLV_Q2A_AXI_CLK				59
-#define GCC_PCIE_PHY_AUX_CLK					60
-#define GCC_PCIE_PHY_REFGEN_CLK					61
-#define GCC_PCIE_PHY_REFGEN_CLK_SRC				62
-#define GCC_PDM2_CLK						63
-#define GCC_PDM2_CLK_SRC					64
-#define GCC_PDM_AHB_CLK						65
-#define GCC_PDM_XO4_CLK						66
-#define GCC_PRNG_AHB_CLK					67
-#define GCC_QMIP_CAMERA_AHB_CLK					68
-#define GCC_QMIP_DISP_AHB_CLK					69
-#define GCC_QMIP_VIDEO_AHB_CLK					70
-#define GCC_QUPV3_WRAP0_S0_CLK					71
-#define GCC_QUPV3_WRAP0_S0_CLK_SRC				72
-#define GCC_QUPV3_WRAP0_S1_CLK					73
-#define GCC_QUPV3_WRAP0_S1_CLK_SRC				74
-#define GCC_QUPV3_WRAP0_S2_CLK					75
-#define GCC_QUPV3_WRAP0_S2_CLK_SRC				76
-#define GCC_QUPV3_WRAP0_S3_CLK					77
-#define GCC_QUPV3_WRAP0_S3_CLK_SRC				78
-#define GCC_QUPV3_WRAP0_S4_CLK					79
-#define GCC_QUPV3_WRAP0_S4_CLK_SRC				80
-#define GCC_QUPV3_WRAP0_S5_CLK					81
-#define GCC_QUPV3_WRAP0_S5_CLK_SRC				82
-#define GCC_QUPV3_WRAP0_S6_CLK					83
-#define GCC_QUPV3_WRAP0_S6_CLK_SRC				84
-#define GCC_QUPV3_WRAP0_S7_CLK					85
-#define GCC_QUPV3_WRAP0_S7_CLK_SRC				86
-#define GCC_QUPV3_WRAP1_S0_CLK					87
-#define GCC_QUPV3_WRAP1_S0_CLK_SRC				88
-#define GCC_QUPV3_WRAP1_S1_CLK					89
-#define GCC_QUPV3_WRAP1_S1_CLK_SRC				90
-#define GCC_QUPV3_WRAP1_S2_CLK					91
-#define GCC_QUPV3_WRAP1_S2_CLK_SRC				92
-#define GCC_QUPV3_WRAP1_S3_CLK					93
-#define GCC_QUPV3_WRAP1_S3_CLK_SRC				94
-#define GCC_QUPV3_WRAP1_S4_CLK					95
-#define GCC_QUPV3_WRAP1_S4_CLK_SRC				96
-#define GCC_QUPV3_WRAP1_S5_CLK					97
-#define GCC_QUPV3_WRAP1_S5_CLK_SRC				98
-#define GCC_QUPV3_WRAP1_S6_CLK					99
-#define GCC_QUPV3_WRAP1_S6_CLK_SRC				100
-#define GCC_QUPV3_WRAP1_S7_CLK					101
-#define GCC_QUPV3_WRAP1_S7_CLK_SRC				102
-#define GCC_QUPV3_WRAP_0_M_AHB_CLK				103
-#define GCC_QUPV3_WRAP_0_S_AHB_CLK				104
-#define GCC_QUPV3_WRAP_1_M_AHB_CLK				105
-#define GCC_QUPV3_WRAP_1_S_AHB_CLK				106
-#define GCC_RX1_USB2_CLKREF_CLK					107
-#define GCC_RX2_QLINK_CLKREF_CLK				108
-#define GCC_SDCC2_AHB_CLK					109
-#define GCC_SDCC2_APPS_CLK					110
-#define GCC_SDCC2_APPS_CLK_SRC					111
-#define GCC_SDCC4_AHB_CLK					112
-#define GCC_SDCC4_APPS_CLK					113
-#define GCC_SDCC4_APPS_CLK_SRC					114
-#define GCC_SYS_NOC_CPUSS_AHB_CLK				115
-#define GCC_TSIF_AHB_CLK					116
-#define GCC_TSIF_INACTIVITY_TIMERS_CLK				117
-#define GCC_TSIF_REF_CLK					118
-#define GCC_TSIF_REF_CLK_SRC					119
-#define GCC_UFS_CARD_AHB_CLK					120
-#define GCC_UFS_CARD_AXI_CLK					121
-#define GCC_UFS_CARD_AXI_CLK_SRC				122
-#define GCC_UFS_CARD_CLKREF_CLK					123
-#define GCC_UFS_CARD_ICE_CORE_CLK				124
-#define GCC_UFS_CARD_ICE_CORE_CLK_SRC				125
-#define GCC_UFS_CARD_PHY_AUX_CLK				126
-#define GCC_UFS_CARD_PHY_AUX_CLK_SRC				127
-#define GCC_UFS_CARD_RX_SYMBOL_0_CLK				128
-#define GCC_UFS_CARD_RX_SYMBOL_1_CLK				129
-#define GCC_UFS_CARD_TX_SYMBOL_0_CLK				130
-#define GCC_UFS_CARD_UNIPRO_CORE_CLK				131
-#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC			132
-#define GCC_UFS_MEM_CLKREF_CLK					133
-#define GCC_UFS_PHY_AHB_CLK					134
-#define GCC_UFS_PHY_AXI_CLK					135
-#define GCC_UFS_PHY_AXI_CLK_SRC					136
-#define GCC_UFS_PHY_ICE_CORE_CLK				137
-#define GCC_UFS_PHY_ICE_CORE_CLK_SRC				138
-#define GCC_UFS_PHY_PHY_AUX_CLK					139
-#define GCC_UFS_PHY_PHY_AUX_CLK_SRC				140
-#define GCC_UFS_PHY_RX_SYMBOL_0_CLK				141
-#define GCC_UFS_PHY_RX_SYMBOL_1_CLK				142
-#define GCC_UFS_PHY_TX_SYMBOL_0_CLK				143
-#define GCC_UFS_PHY_UNIPRO_CORE_CLK				144
-#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC				145
-#define GCC_USB30_PRIM_MASTER_CLK				146
-#define GCC_USB30_PRIM_MASTER_CLK_SRC				147
-#define GCC_USB30_PRIM_MOCK_UTMI_CLK				148
-#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC			149
-#define GCC_USB30_PRIM_SLEEP_CLK				150
-#define GCC_USB30_SEC_MASTER_CLK				151
-#define GCC_USB30_SEC_MASTER_CLK_SRC				152
-#define GCC_USB30_SEC_MOCK_UTMI_CLK				153
-#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC				154
-#define GCC_USB30_SEC_SLEEP_CLK					155
-#define GCC_USB3_PRIM_CLKREF_CLK				156
-#define GCC_USB3_PRIM_PHY_AUX_CLK				157
-#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC				158
-#define GCC_USB3_PRIM_PHY_COM_AUX_CLK				159
-#define GCC_USB3_PRIM_PHY_PIPE_CLK				160
-#define GCC_USB3_SEC_CLKREF_CLK					161
-#define GCC_USB3_SEC_PHY_AUX_CLK				162
-#define GCC_USB3_SEC_PHY_AUX_CLK_SRC				163
-#define GCC_USB3_SEC_PHY_COM_AUX_CLK				164
-#define GCC_USB3_SEC_PHY_PIPE_CLK				165
-#define GCC_USB_PHY_CFG_AHB2PHY_CLK				166
-#define GCC_VIDEO_AHB_CLK					167
-#define GCC_VIDEO_AXI_CLK					168
-#define GCC_VIDEO_XO_CLK					169
-#define GPLL0							170
-#define GPLL0_OUT_EVEN						171
-#define GPLL0_OUT_MAIN						172
-#define GPLL1							173
-#define GPLL1_OUT_MAIN						174
+#define GCC_DDRSS_GPU_AXI_CLK					20
+#define GCC_DISP_AHB_CLK					21
+#define GCC_DISP_AXI_CLK					22
+#define GCC_DISP_GPLL0_CLK_SRC					23
+#define GCC_DISP_GPLL0_DIV_CLK_SRC				24
+#define GCC_DISP_XO_CLK						25
+#define GCC_GP1_CLK						26
+#define GCC_GP1_CLK_SRC						27
+#define GCC_GP2_CLK						28
+#define GCC_GP2_CLK_SRC						29
+#define GCC_GP3_CLK						30
+#define GCC_GP3_CLK_SRC						31
+#define GCC_GPU_CFG_AHB_CLK					32
+#define GCC_GPU_GPLL0_CLK_SRC					33
+#define GCC_GPU_GPLL0_DIV_CLK_SRC				34
+#define GCC_GPU_MEMNOC_GFX_CLK					35
+#define GCC_GPU_SNOC_DVM_GFX_CLK				36
+#define GCC_MSS_AXIS2_CLK					37
+#define GCC_MSS_CFG_AHB_CLK					38
+#define GCC_MSS_GPLL0_DIV_CLK_SRC				39
+#define GCC_MSS_MFAB_AXIS_CLK					40
+#define GCC_MSS_Q6_MEMNOC_AXI_CLK				41
+#define GCC_MSS_SNOC_AXI_CLK					42
+#define GCC_PCIE_0_AUX_CLK					43
+#define GCC_PCIE_0_AUX_CLK_SRC					44
+#define GCC_PCIE_0_CFG_AHB_CLK					45
+#define GCC_PCIE_0_CLKREF_CLK					46
+#define GCC_PCIE_0_MSTR_AXI_CLK					47
+#define GCC_PCIE_0_PIPE_CLK					48
+#define GCC_PCIE_0_SLV_AXI_CLK					49
+#define GCC_PCIE_0_SLV_Q2A_AXI_CLK				50
+#define GCC_PCIE_1_AUX_CLK					51
+#define GCC_PCIE_1_AUX_CLK_SRC					52
+#define GCC_PCIE_1_CFG_AHB_CLK					53
+#define GCC_PCIE_1_CLKREF_CLK					54
+#define GCC_PCIE_1_MSTR_AXI_CLK					55
+#define GCC_PCIE_1_PIPE_CLK					56
+#define GCC_PCIE_1_SLV_AXI_CLK					57
+#define GCC_PCIE_1_SLV_Q2A_AXI_CLK				58
+#define GCC_PCIE_PHY_AUX_CLK					59
+#define GCC_PCIE_PHY_REFGEN_CLK					60
+#define GCC_PCIE_PHY_REFGEN_CLK_SRC				61
+#define GCC_PDM2_CLK						62
+#define GCC_PDM2_CLK_SRC					63
+#define GCC_PDM_AHB_CLK						64
+#define GCC_PDM_XO4_CLK						65
+#define GCC_PRNG_AHB_CLK					66
+#define GCC_QMIP_CAMERA_AHB_CLK					67
+#define GCC_QMIP_DISP_AHB_CLK					68
+#define GCC_QMIP_VIDEO_AHB_CLK					69
+#define GCC_QUPV3_WRAP0_S0_CLK					70
+#define GCC_QUPV3_WRAP0_S0_CLK_SRC				71
+#define GCC_QUPV3_WRAP0_S1_CLK					72
+#define GCC_QUPV3_WRAP0_S1_CLK_SRC				73
+#define GCC_QUPV3_WRAP0_S2_CLK					74
+#define GCC_QUPV3_WRAP0_S2_CLK_SRC				75
+#define GCC_QUPV3_WRAP0_S3_CLK					76
+#define GCC_QUPV3_WRAP0_S3_CLK_SRC				77
+#define GCC_QUPV3_WRAP0_S4_CLK					78
+#define GCC_QUPV3_WRAP0_S4_CLK_SRC				79
+#define GCC_QUPV3_WRAP0_S5_CLK					80
+#define GCC_QUPV3_WRAP0_S5_CLK_SRC				81
+#define GCC_QUPV3_WRAP0_S6_CLK					82
+#define GCC_QUPV3_WRAP0_S6_CLK_SRC				83
+#define GCC_QUPV3_WRAP0_S7_CLK					84
+#define GCC_QUPV3_WRAP0_S7_CLK_SRC				85
+#define GCC_QUPV3_WRAP1_S0_CLK					86
+#define GCC_QUPV3_WRAP1_S0_CLK_SRC				87
+#define GCC_QUPV3_WRAP1_S1_CLK					88
+#define GCC_QUPV3_WRAP1_S1_CLK_SRC				89
+#define GCC_QUPV3_WRAP1_S2_CLK					90
+#define GCC_QUPV3_WRAP1_S2_CLK_SRC				91
+#define GCC_QUPV3_WRAP1_S3_CLK					92
+#define GCC_QUPV3_WRAP1_S3_CLK_SRC				93
+#define GCC_QUPV3_WRAP1_S4_CLK					94
+#define GCC_QUPV3_WRAP1_S4_CLK_SRC				95
+#define GCC_QUPV3_WRAP1_S5_CLK					96
+#define GCC_QUPV3_WRAP1_S5_CLK_SRC				97
+#define GCC_QUPV3_WRAP1_S6_CLK					98
+#define GCC_QUPV3_WRAP1_S6_CLK_SRC				99
+#define GCC_QUPV3_WRAP1_S7_CLK					100
+#define GCC_QUPV3_WRAP1_S7_CLK_SRC				101
+#define GCC_QUPV3_WRAP_0_M_AHB_CLK				102
+#define GCC_QUPV3_WRAP_0_S_AHB_CLK				103
+#define GCC_QUPV3_WRAP_1_M_AHB_CLK				104
+#define GCC_QUPV3_WRAP_1_S_AHB_CLK				105
+#define GCC_SDCC2_AHB_CLK					106
+#define GCC_SDCC2_APPS_CLK					107
+#define GCC_SDCC2_APPS_CLK_SRC					108
+#define GCC_SDCC4_AHB_CLK					109
+#define GCC_SDCC4_APPS_CLK					110
+#define GCC_SDCC4_APPS_CLK_SRC					111
+#define GCC_SYS_NOC_CPUSS_AHB_CLK				112
+#define GCC_TSIF_AHB_CLK					113
+#define GCC_TSIF_INACTIVITY_TIMERS_CLK				114
+#define GCC_TSIF_REF_CLK					115
+#define GCC_TSIF_REF_CLK_SRC					116
+#define GCC_UFS_CARD_AHB_CLK					117
+#define GCC_UFS_CARD_AXI_CLK					118
+#define GCC_UFS_CARD_AXI_CLK_SRC				119
+#define GCC_UFS_CARD_CLKREF_CLK					120
+#define GCC_UFS_CARD_ICE_CORE_CLK				121
+#define GCC_UFS_CARD_ICE_CORE_CLK_SRC				122
+#define GCC_UFS_CARD_PHY_AUX_CLK				123
+#define GCC_UFS_CARD_PHY_AUX_CLK_SRC				124
+#define GCC_UFS_CARD_RX_SYMBOL_0_CLK				125
+#define GCC_UFS_CARD_RX_SYMBOL_1_CLK				126
+#define GCC_UFS_CARD_TX_SYMBOL_0_CLK				127
+#define GCC_UFS_CARD_UNIPRO_CORE_CLK				128
+#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC			129
+#define GCC_UFS_MEM_CLKREF_CLK					130
+#define GCC_UFS_PHY_AHB_CLK					131
+#define GCC_UFS_PHY_AXI_CLK					132
+#define GCC_UFS_PHY_AXI_CLK_SRC					133
+#define GCC_UFS_PHY_ICE_CORE_CLK				134
+#define GCC_UFS_PHY_ICE_CORE_CLK_SRC				135
+#define GCC_UFS_PHY_PHY_AUX_CLK					136
+#define GCC_UFS_PHY_PHY_AUX_CLK_SRC				137
+#define GCC_UFS_PHY_RX_SYMBOL_0_CLK				138
+#define GCC_UFS_PHY_RX_SYMBOL_1_CLK				139
+#define GCC_UFS_PHY_TX_SYMBOL_0_CLK				140
+#define GCC_UFS_PHY_UNIPRO_CORE_CLK				141
+#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC				142
+#define GCC_USB30_PRIM_MASTER_CLK				143
+#define GCC_USB30_PRIM_MASTER_CLK_SRC				144
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK				145
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC			146
+#define GCC_USB30_PRIM_SLEEP_CLK				147
+#define GCC_USB30_SEC_MASTER_CLK				148
+#define GCC_USB30_SEC_MASTER_CLK_SRC				149
+#define GCC_USB30_SEC_MOCK_UTMI_CLK				150
+#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC				151
+#define GCC_USB30_SEC_SLEEP_CLK					152
+#define GCC_USB3_PRIM_CLKREF_CLK				153
+#define GCC_USB3_PRIM_PHY_AUX_CLK				154
+#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC				155
+#define GCC_USB3_PRIM_PHY_COM_AUX_CLK				156
+#define GCC_USB3_PRIM_PHY_PIPE_CLK				157
+#define GCC_USB3_SEC_CLKREF_CLK					158
+#define GCC_USB3_SEC_PHY_AUX_CLK				159
+#define GCC_USB3_SEC_PHY_AUX_CLK_SRC				160
+#define GCC_USB3_SEC_PHY_COM_AUX_CLK				161
+#define GCC_USB3_SEC_PHY_PIPE_CLK				162
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK				163
+#define GCC_VIDEO_AHB_CLK					164
+#define GCC_VIDEO_AXI_CLK					165
+#define GCC_VIDEO_XO_CLK					166
+#define GPLL0							167
+#define GPLL0_OUT_EVEN						168
+#define GPLL0_OUT_MAIN						169
+#define GPLL1							170
+#define GPLL1_OUT_MAIN						171
 
 /* GCC reset clocks */
 #define GCC_GPU_BCR						0
@@ -217,6 +214,8 @@
 #define GCC_USB3PHY_PHY_SEC_BCR					22
 #define GCC_USB3_DP_PHY_SEC_BCR					23
 #define GCC_USB_PHY_CFG_AHB2PHY_BCR				24
+#define GCC_PCIE_0_PHY_BCR					25
+#define GCC_PCIE_1_PHY_BCR					26
 
 /* Dummy clocks for rate measurement */
 #define MEASURE_ONLY_SNOC_CLK					0
diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
index 13de1e1..c43a9f8 100644
--- a/include/dt-bindings/clock/qcom,gpucc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
@@ -17,37 +17,36 @@
 /* GPUCC clock registers */
 #define GPU_CC_ACD_AHB_CLK					0
 #define GPU_CC_ACD_CXO_CLK					1
-#define GPU_CC_AHB_CLK					2
+#define GPU_CC_AHB_CLK						2
 #define GPU_CC_CRC_AHB_CLK					3
 #define GPU_CC_CX_APB_CLK					4
 #define GPU_CC_CX_GMU_CLK					5
 #define GPU_CC_CX_QDSS_AT_CLK					6
 #define GPU_CC_CX_QDSS_TRIG_CLK					7
-#define GPU_CC_CX_QDSS_TSCTR_CLK					8
-#define GPU_CC_CX_SNOC_DVM_CLK						9
+#define GPU_CC_CX_QDSS_TSCTR_CLK				8
+#define GPU_CC_CX_SNOC_DVM_CLK					9
 #define GPU_CC_CXO_AON_CLK					10
-#define GPU_CC_CXO_CLK					11
-#define GPU_CC_DEBUG_CLK					12
-#define GPU_CC_GX_CXO_CLK					13
-#define GPU_CC_GX_GMU_CLK					14
-#define GPU_CC_GX_QDSS_TSCTR_CLK					15
-#define GPU_CC_GX_VSENSE_CLK					16
-#define GPU_CC_PLL0_OUT_MAIN					 17
-#define GPU_CC_PLL0_OUT_ODD						18
-#define GPU_CC_PLL0_OUT_TEST					19
-#define GPU_CC_PLL1						20
-#define GPU_CC_PLL1_OUT_EVEN					21
-#define GPU_CC_PLL1_OUT_MAIN					22
-#define GPU_CC_PLL1_OUT_ODD					23
-#define GPU_CC_PLL1_OUT_TEST					24
-#define GPU_CC_PLL_TEST_CLK					25
-#define GPU_CC_RBCPR_AHB_CLK					26
-#define GPU_CC_RBCPR_CLK					27
-#define GPU_CC_RBCPR_CLK_SRC					28
-#define GPU_CC_SLEEP_CLK					29
-#define GPU_CC_GMU_CLK_SRC					30
-#define GPU_CC_CX_GFX3D_CLK					31
-#define GPU_CC_CX_GFX3D_SLV_CLK					32
+#define GPU_CC_CXO_CLK						11
+#define GPU_CC_GX_CXO_CLK					12
+#define GPU_CC_GX_GMU_CLK					13
+#define GPU_CC_GX_QDSS_TSCTR_CLK				14
+#define GPU_CC_GX_VSENSE_CLK					15
+#define GPU_CC_PLL0_OUT_MAIN					16
+#define GPU_CC_PLL0_OUT_ODD					17
+#define GPU_CC_PLL0_OUT_TEST					18
+#define GPU_CC_PLL1						19
+#define GPU_CC_PLL1_OUT_EVEN					20
+#define GPU_CC_PLL1_OUT_MAIN					21
+#define GPU_CC_PLL1_OUT_ODD					22
+#define GPU_CC_PLL1_OUT_TEST					23
+#define GPU_CC_PLL_TEST_CLK					24
+#define GPU_CC_RBCPR_AHB_CLK					25
+#define GPU_CC_RBCPR_CLK					26
+#define GPU_CC_RBCPR_CLK_SRC					27
+#define GPU_CC_SLEEP_CLK					28
+#define GPU_CC_GMU_CLK_SRC					29
+#define GPU_CC_CX_GFX3D_CLK					30
+#define GPU_CC_CX_GFX3D_SLV_CLK					31
 
 /* GPUCC reset clock registers */
 #define GPUCC_GPU_CC_ACD_BCR					0
@@ -63,5 +62,5 @@
 #define GPU_CC_PLL0						0
 #define GPU_CC_PLL0_OUT_EVEN					1
 #define GPU_CC_GX_GFX3D_CLK_SRC					2
-#define GPU_CC_GX_GFX3D_CLK						3
+#define GPU_CC_GX_GFX3D_CLK					3
 #endif
diff --git a/include/dt-bindings/clock/qcom,videocc-sdm845.h b/include/dt-bindings/clock/qcom,videocc-sdm845.h
index 723d2e0..b362852d 100644
--- a/include/dt-bindings/clock/qcom,videocc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,videocc-sdm845.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -16,18 +16,17 @@
 
 #define VIDEO_CC_APB_CLK					0
 #define VIDEO_CC_AT_CLK						1
-#define VIDEO_CC_DEBUG_CLK					2
-#define VIDEO_CC_QDSS_TRIG_CLK					3
-#define VIDEO_CC_QDSS_TSCTR_DIV8_CLK				4
-#define VIDEO_CC_VCODEC0_AXI_CLK				5
-#define VIDEO_CC_VCODEC0_CORE_CLK				6
-#define VIDEO_CC_VCODEC1_AXI_CLK				7
-#define VIDEO_CC_VCODEC1_CORE_CLK				8
-#define VIDEO_CC_VENUS_AHB_CLK					9
-#define VIDEO_CC_VENUS_CLK_SRC					10
-#define VIDEO_CC_VENUS_CTL_AXI_CLK				11
-#define VIDEO_CC_VENUS_CTL_CORE_CLK				12
-#define VIDEO_PLL0						13
+#define VIDEO_CC_QDSS_TRIG_CLK					2
+#define VIDEO_CC_QDSS_TSCTR_DIV8_CLK				3
+#define VIDEO_CC_VCODEC0_AXI_CLK				4
+#define VIDEO_CC_VCODEC0_CORE_CLK				5
+#define VIDEO_CC_VCODEC1_AXI_CLK				6
+#define VIDEO_CC_VCODEC1_CORE_CLK				7
+#define VIDEO_CC_VENUS_AHB_CLK					8
+#define VIDEO_CC_VENUS_CLK_SRC					9
+#define VIDEO_CC_VENUS_CTL_AXI_CLK				10
+#define VIDEO_CC_VENUS_CTL_CORE_CLK				11
+#define VIDEO_PLL0						12
 
 #define VIDEO_CC_INTERFACE_BCR					0
 #define VIDEO_CC_VCODEC0_BCR					1
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index bda14ef..744ea4f 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -125,6 +125,7 @@
  * BVEC_POOL_IDX()
  */
 #define BIO_RESET_BITS	10
+#define BIO_INLINECRYPT 15
 
 /*
  * We support 6 different bvec pools, the last one is magic in that it
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5d3a4cd..1f6892c 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -435,6 +435,7 @@
 		      const struct iommu_ops *ops);
 void iommu_fwspec_free(struct device *dev);
 int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
+int iommu_fwspec_get_id(struct device *dev, u32 *id);
 
 #else /* CONFIG_IOMMU_API */
 
@@ -705,6 +706,11 @@
 	return -ENODEV;
 }
 
+static inline int iommu_fwspec_get_id(struct device *dev, u32 *id)
+{
+	return -ENODEV;
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index cb4387d..5a10db5 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -479,11 +479,11 @@
 	return rx_fifo_depth;
 }
 
-static inline void se_config_packing(void __iomem *base, int bpw,
-				int pack_words, bool msb_to_lsb)
+static inline void se_get_packing_config(int bpw, int pack_words,
+					bool msb_to_lsb, unsigned long *cfg0,
+					unsigned long *cfg1)
 {
 	u32 cfg[4] = {0};
-	unsigned long cfg0, cfg1;
 	int len = ((bpw < 8) ? (bpw - 1) : 7);
 	int idx = ((msb_to_lsb == 1) ? len : 0);
 	int iter = (bpw * pack_words) >> 3;
@@ -495,8 +495,16 @@
 		if (i == iter - 1)
 			cfg[i] |= 1;
 	}
-	cfg0 = cfg[0] | (cfg[1] << 10);
-	cfg1 = cfg[2] | (cfg[3] << 10);
+	*cfg0 = cfg[0] | (cfg[1] << 10);
+	*cfg1 = cfg[2] | (cfg[3] << 10);
+}
+
+static inline void se_config_packing(void __iomem *base, int bpw,
+				int pack_words, bool msb_to_lsb)
+{
+	unsigned long cfg0, cfg1;
+
+	se_get_packing_config(bpw, pack_words, msb_to_lsb, &cfg0, &cfg1);
 	geni_write_reg(cfg0, base, SE_GENI_TX_PACKING_CFG0);
 	geni_write_reg(cfg1, base, SE_GENI_TX_PACKING_CFG1);
 	geni_write_reg(cfg0, base, SE_GENI_RX_PACKING_CFG0);
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index a0e2283..7fca674 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -208,6 +208,12 @@
 #define PM660_V1P1_REV3		0x01
 #define PM660_V1P1_REV4		0x01
 
+/* PM660L REV_ID */
+#define PM660L_V1P1_REV1	0x00
+#define PM660L_V1P1_REV2	0x00
+#define PM660L_V1P1_REV3	0x01
+#define PM660L_V1P1_REV4	0x01
+
 /* PMI8998 FAB_ID */
 #define PMI8998_FAB_ID_SMIC	0x11
 #define PMI8998_FAB_ID_GF	0x30
@@ -229,6 +235,9 @@
 /* SMB1381 */
 #define SMB1381_SUBTYPE		0x17
 
+/* SMB1355 */
+#define SMB1355_SUBTYPE		0x1C
+
 struct pmic_revid_data {
 	u8		rev1;
 	u8		rev2;
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
index 60cc768..f3fa9e6 100644
--- a/include/linux/sde_rsc.h
+++ b/include/linux/sde_rsc.h
@@ -79,6 +79,7 @@
  * @current_state:   current client state
  * @crtc_id:		crtc_id associated with this rsc client.
  * @rsc_index:	rsc index of a client - only index "0" valid.
+ * @id:		Index of client. It will be assigned during client_create call
  * @list:	list to attach client master list
  */
 struct sde_rsc_client {
@@ -86,6 +87,7 @@
 	short current_state;
 	int crtc_id;
 	u32 rsc_index;
+	u32 id;
 	struct list_head list;
 };
 
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index 262fa64..0583431 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -103,6 +103,7 @@
 int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
 int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
+int msm_vidc_g_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
 int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
 int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
 int msm_vidc_release_buffer(void *instance, int buffer_type,
diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h
index 7586072..ad19e73 100644
--- a/include/trace/events/clk.h
+++ b/include/trace/events/clk.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -192,6 +192,42 @@
 	TP_ARGS(core, phase)
 );
 
+DECLARE_EVENT_CLASS(clk_state_dump,
+
+	TP_PROTO(const char *name, unsigned int prepare_count,
+	unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
+
+	TP_ARGS(name, prepare_count, enable_count, rate, vdd_level),
+
+	TP_STRUCT__entry(
+		__string(name,			name)
+		__field(unsigned int,		prepare_count)
+		__field(unsigned int,		enable_count)
+		__field(unsigned long,		rate)
+		__field(unsigned int,		vdd_level)
+	),
+
+	TP_fast_assign(
+		__assign_str(name, name);
+		__entry->prepare_count = prepare_count;
+		__entry->enable_count = enable_count;
+		__entry->rate = rate;
+		__entry->vdd_level = vdd_level;
+	),
+
+	TP_printk("%s\tprepare:enable cnt [%u:%u]\trate: vdd_level [%lu:%u]",
+		__get_str(name), __entry->prepare_count, __entry->enable_count,
+		__entry->rate, __entry->vdd_level)
+);
+
+DEFINE_EVENT(clk_state_dump, clk_state,
+
+	TP_PROTO(const char *name, unsigned int prepare_count,
+	unsigned int enable_count, unsigned long rate, unsigned int vdd_level),
+
+	TP_ARGS(name, prepare_count, enable_count, rate, vdd_level)
+);
+
 #endif /* _TRACE_CLK_H */
 
 /* This part must be outside protection */
diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h
index c190446..f05155b 100644
--- a/include/uapi/linux/msm_kgsl.h
+++ b/include/uapi/linux/msm_kgsl.h
@@ -67,6 +67,8 @@
 #define KGSL_CONTEXT_TYPE_RS		4
 #define KGSL_CONTEXT_TYPE_UNKNOWN	0x1E
 
+#define KGSL_CONTEXT_INVALIDATE_ON_FAULT 0x10000000
+
 #define KGSL_CONTEXT_INVALID 0xffffffff
 
 /*
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index a62870e..cf96ac1 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -1061,6 +1061,8 @@
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 106)
 #define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX \
 		(V4L2_CID_MPEG_MSM_VIDC_BASE + 107)
+#define V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK \
+		(V4L2_CID_MPEG_MSM_VIDC_BASE + 108)
 
 enum v4l2_mpeg_vidc_video_venc_iframesize_type {
 	V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT,
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 68db5e1..b736755 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -190,9 +190,6 @@
 #define CAM_REQ_MGR_MAP_BUF                     (CAM_COMMON_OPCODE_MAX + 10)
 #define CAM_REQ_MGR_RELEASE_BUF                 (CAM_COMMON_OPCODE_MAX + 11)
 #define CAM_REQ_MGR_CACHE_OPS                   (CAM_COMMON_OPCODE_MAX + 12)
-#define CAM_REQ_MGR_GET_MMU_HDLS_DEBUG          (CAM_COMMON_OPCODE_MAX + 13)
-#define CAM_REQ_MGR_GET_IO_BUF_DEBUG            (CAM_COMMON_OPCODE_MAX + 14)
-#define CAM_REQ_MGR_GET_KMD_BUF_DEBUG           (CAM_COMMON_OPCODE_MAX + 15)
 /* end of cam_req_mgr opcodes */
 
 #define CAM_MEM_FLAG_HW_READ_WRITE              (1<<0)
@@ -206,6 +203,7 @@
 #define CAM_MEM_FLAG_STATS_BUF_TYPE             (1<<8)
 #define CAM_MEM_FLAG_PACKET_BUF_TYPE            (1<<9)
 #define CAM_MEM_FLAG_CACHE                      (1<<10)
+#define CAM_MEM_FLAG_HW_SHARED_ACCESS           (1<<11)
 
 #define CAM_MEM_MMU_MAX_HANDLE                  16
 
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 9d1ed58..6670008 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2877,7 +2877,7 @@
 	if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
 	    !uid_eq(cred->euid, tcred->uid) &&
 	    !uid_eq(cred->euid, tcred->suid) &&
-	    !ns_capable(tcred->user_ns, CAP_SYS_RESOURCE))
+	    !ns_capable(tcred->user_ns, CAP_SYS_NICE))
 		ret = -EACCES;
 
 	if (!ret && cgroup_on_dfl(dst_cgrp)) {
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 69e0689..27d96e2 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -12,11 +12,14 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/cpufreq.h>
+#include <linux/kthread.h>
 #include <linux/slab.h>
 #include <trace/events/power.h>
 
 #include "sched.h"
 
+#define SUGOV_KTHREAD_PRIORITY	50
+
 struct sugov_tunables {
 	struct gov_attr_set attr_set;
 	unsigned int rate_limit_us;
@@ -32,11 +35,14 @@
 	u64 last_freq_update_time;
 	s64 freq_update_delay_ns;
 	unsigned int next_freq;
+	unsigned int cached_raw_freq;
 
 	/* The next fields are only needed if fast switch cannot be used. */
 	struct irq_work irq_work;
-	struct work_struct work;
+	struct kthread_work work;
 	struct mutex work_lock;
+	struct kthread_worker worker;
+	struct task_struct *thread;
 	bool work_in_progress;
 
 	bool need_freq_update;
@@ -46,7 +52,6 @@
 	struct update_util_data update_util;
 	struct sugov_policy *sg_policy;
 
-	unsigned int cached_raw_freq;
 	unsigned long iowait_boost;
 	unsigned long iowait_boost_max;
 	u64 last_update;
@@ -110,7 +115,7 @@
 
 /**
  * get_next_freq - Compute a new frequency for a given cpufreq policy.
- * @sg_cpu: schedutil cpu object to compute the new frequency for.
+ * @sg_policy: schedutil policy object to compute the new frequency for.
  * @util: Current CPU utilization.
  * @max: CPU capacity.
  *
@@ -130,19 +135,18 @@
  * next_freq (as calculated above) is returned, subject to policy min/max and
  * cpufreq driver limitations.
  */
-static unsigned int get_next_freq(struct sugov_cpu *sg_cpu, unsigned long util,
-				  unsigned long max)
+static unsigned int get_next_freq(struct sugov_policy *sg_policy,
+				  unsigned long util, unsigned long max)
 {
-	struct sugov_policy *sg_policy = sg_cpu->sg_policy;
 	struct cpufreq_policy *policy = sg_policy->policy;
 	unsigned int freq = arch_scale_freq_invariant() ?
 				policy->cpuinfo.max_freq : policy->cur;
 
 	freq = (freq + (freq >> 2)) * util / max;
 
-	if (freq == sg_cpu->cached_raw_freq && sg_policy->next_freq != UINT_MAX)
+	if (freq == sg_policy->cached_raw_freq && sg_policy->next_freq != UINT_MAX)
 		return sg_policy->next_freq;
-	sg_cpu->cached_raw_freq = freq;
+	sg_policy->cached_raw_freq = freq;
 	return cpufreq_driver_resolve_freq(policy, freq);
 }
 
@@ -207,7 +211,7 @@
 	} else {
 		sugov_get_util(&util, &max);
 		sugov_iowait_boost(sg_cpu, &util, &max);
-		next_f = get_next_freq(sg_cpu, util, max);
+		next_f = get_next_freq(sg_policy, util, max);
 	}
 	sugov_update_commit(sg_policy, time, next_f);
 }
@@ -261,7 +265,7 @@
 		sugov_iowait_boost(j_sg_cpu, &util, &max);
 	}
 
-	return get_next_freq(sg_cpu, util, max);
+	return get_next_freq(sg_policy, util, max);
 }
 
 static void sugov_update_shared(struct update_util_data *hook, u64 time,
@@ -291,7 +295,7 @@
 	raw_spin_unlock(&sg_policy->update_lock);
 }
 
-static void sugov_work(struct work_struct *work)
+static void sugov_work(struct kthread_work *work)
 {
 	struct sugov_policy *sg_policy = container_of(work, struct sugov_policy, work);
 
@@ -308,7 +312,21 @@
 	struct sugov_policy *sg_policy;
 
 	sg_policy = container_of(irq_work, struct sugov_policy, irq_work);
-	schedule_work_on(smp_processor_id(), &sg_policy->work);
+
+	/*
+	 * For RT and deadline tasks, the schedutil governor shoots the
+	 * frequency to maximum. Special care must be taken to ensure that this
+	 * kthread doesn't result in the same behavior.
+	 *
+	 * This is (mostly) guaranteed by the work_in_progress flag. The flag is
+	 * updated only at the end of the sugov_work() function and before that
+	 * the schedutil governor rejects all other frequency scaling requests.
+	 *
+	 * There is a very rare case though, where the RT thread yields right
+	 * after the work_in_progress flag is cleared. The effects of that are
+	 * neglected for now.
+	 */
+	kthread_queue_work(&sg_policy->worker, &sg_policy->work);
 }
 
 /************************** sysfs interface ************************/
@@ -371,19 +389,64 @@
 		return NULL;
 
 	sg_policy->policy = policy;
-	init_irq_work(&sg_policy->irq_work, sugov_irq_work);
-	INIT_WORK(&sg_policy->work, sugov_work);
-	mutex_init(&sg_policy->work_lock);
 	raw_spin_lock_init(&sg_policy->update_lock);
 	return sg_policy;
 }
 
 static void sugov_policy_free(struct sugov_policy *sg_policy)
 {
-	mutex_destroy(&sg_policy->work_lock);
 	kfree(sg_policy);
 }
 
+static int sugov_kthread_create(struct sugov_policy *sg_policy)
+{
+	struct task_struct *thread;
+	struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO / 2 };
+	struct cpufreq_policy *policy = sg_policy->policy;
+	int ret;
+
+	/* kthread only required for slow path */
+	if (policy->fast_switch_enabled)
+		return 0;
+
+	kthread_init_work(&sg_policy->work, sugov_work);
+	kthread_init_worker(&sg_policy->worker);
+	thread = kthread_create(kthread_worker_fn, &sg_policy->worker,
+				"sugov:%d",
+				cpumask_first(policy->related_cpus));
+	if (IS_ERR(thread)) {
+		pr_err("failed to create sugov thread: %ld\n", PTR_ERR(thread));
+		return PTR_ERR(thread);
+	}
+
+	ret = sched_setscheduler_nocheck(thread, SCHED_FIFO, &param);
+	if (ret) {
+		kthread_stop(thread);
+		pr_warn("%s: failed to set SCHED_FIFO\n", __func__);
+		return ret;
+	}
+
+	sg_policy->thread = thread;
+	kthread_bind_mask(thread, policy->related_cpus);
+	init_irq_work(&sg_policy->irq_work, sugov_irq_work);
+	mutex_init(&sg_policy->work_lock);
+
+	wake_up_process(thread);
+
+	return 0;
+}
+
+static void sugov_kthread_stop(struct sugov_policy *sg_policy)
+{
+	/* kthread only required for slow path */
+	if (sg_policy->policy->fast_switch_enabled)
+		return;
+
+	kthread_flush_worker(&sg_policy->worker);
+	kthread_stop(sg_policy->thread);
+	mutex_destroy(&sg_policy->work_lock);
+}
+
 static struct sugov_tunables *sugov_tunables_alloc(struct sugov_policy *sg_policy)
 {
 	struct sugov_tunables *tunables;
@@ -416,16 +479,24 @@
 	if (policy->governor_data)
 		return -EBUSY;
 
+	cpufreq_enable_fast_switch(policy);
+
 	sg_policy = sugov_policy_alloc(policy);
-	if (!sg_policy)
-		return -ENOMEM;
+	if (!sg_policy) {
+		ret = -ENOMEM;
+		goto disable_fast_switch;
+	}
+
+	ret = sugov_kthread_create(sg_policy);
+	if (ret)
+		goto free_sg_policy;
 
 	mutex_lock(&global_tunables_lock);
 
 	if (global_tunables) {
 		if (WARN_ON(have_governor_per_policy())) {
 			ret = -EINVAL;
-			goto free_sg_policy;
+			goto stop_kthread;
 		}
 		policy->governor_data = sg_policy;
 		sg_policy->tunables = global_tunables;
@@ -437,7 +508,7 @@
 	tunables = sugov_tunables_alloc(sg_policy);
 	if (!tunables) {
 		ret = -ENOMEM;
-		goto free_sg_policy;
+		goto stop_kthread;
 	}
 
 	tunables->rate_limit_us = LATENCY_MULTIPLIER;
@@ -454,20 +525,25 @@
 	if (ret)
 		goto fail;
 
- out:
+out:
 	mutex_unlock(&global_tunables_lock);
-
-	cpufreq_enable_fast_switch(policy);
 	return 0;
 
- fail:
+fail:
 	policy->governor_data = NULL;
 	sugov_tunables_free(tunables);
 
- free_sg_policy:
+stop_kthread:
+	sugov_kthread_stop(sg_policy);
+
+free_sg_policy:
 	mutex_unlock(&global_tunables_lock);
 
 	sugov_policy_free(sg_policy);
+
+disable_fast_switch:
+	cpufreq_disable_fast_switch(policy);
+
 	pr_err("initialization failed (error %d)\n", ret);
 	return ret;
 }
@@ -478,8 +554,6 @@
 	struct sugov_tunables *tunables = sg_policy->tunables;
 	unsigned int count;
 
-	cpufreq_disable_fast_switch(policy);
-
 	mutex_lock(&global_tunables_lock);
 
 	count = gov_attr_set_put(&tunables->attr_set, &sg_policy->tunables_hook);
@@ -489,7 +563,9 @@
 
 	mutex_unlock(&global_tunables_lock);
 
+	sugov_kthread_stop(sg_policy);
 	sugov_policy_free(sg_policy);
+	cpufreq_disable_fast_switch(policy);
 }
 
 static int sugov_start(struct cpufreq_policy *policy)
@@ -502,25 +578,19 @@
 	sg_policy->next_freq = UINT_MAX;
 	sg_policy->work_in_progress = false;
 	sg_policy->need_freq_update = false;
+	sg_policy->cached_raw_freq = 0;
 
 	for_each_cpu(cpu, policy->cpus) {
 		struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
 
+		memset(sg_cpu, 0, sizeof(*sg_cpu));
 		sg_cpu->sg_policy = sg_policy;
-		if (policy_is_shared(policy)) {
-			sg_cpu->util = 0;
-			sg_cpu->max = 0;
-			sg_cpu->flags = SCHED_CPUFREQ_RT;
-			sg_cpu->last_update = 0;
-			sg_cpu->cached_raw_freq = 0;
-			sg_cpu->iowait_boost = 0;
-			sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
-			cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
-						     sugov_update_shared);
-		} else {
-			cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
-						     sugov_update_single);
-		}
+		sg_cpu->flags = SCHED_CPUFREQ_RT;
+		sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
+		cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
+					     policy_is_shared(policy) ?
+							sugov_update_shared :
+							sugov_update_single);
 	}
 	return 0;
 }
@@ -535,8 +605,10 @@
 
 	synchronize_sched();
 
-	irq_work_sync(&sg_policy->irq_work);
-	cancel_work_sync(&sg_policy->work);
+	if (!policy->fast_switch_enabled) {
+		irq_work_sync(&sg_policy->irq_work);
+		kthread_cancel_work_sync(&sg_policy->work);
+	}
 }
 
 static void sugov_limits(struct cpufreq_policy *policy)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index f30847a..f5c016e 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -3435,11 +3435,23 @@
 int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
 {
 	struct ring_buffer_per_cpu *cpu_buffer;
+	struct buffer_page *reader;
+	struct buffer_page *head_page;
+	struct buffer_page *commit_page;
+	unsigned commit;
 
 	cpu_buffer = iter->cpu_buffer;
 
-	return iter->head_page == cpu_buffer->commit_page &&
-		iter->head == rb_commit_index(cpu_buffer);
+	/* Remember, trace recording is off when iterator is in use */
+	reader = cpu_buffer->reader_page;
+	head_page = cpu_buffer->head_page;
+	commit_page = cpu_buffer->commit_page;
+	commit = rb_page_commit(commit_page);
+
+	return ((iter->head_page == commit_page && iter->head == commit) ||
+		(iter->head_page == reader && commit_page == head_page &&
+		 head_page->read == commit &&
+		 iter->head == rb_page_commit(cpu_buffer->reader_page)));
 }
 EXPORT_SYMBOL_GPL(ring_buffer_iter_empty);
 
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 63c6d28..ebf9498 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6576,11 +6576,13 @@
 		return ret;
 
  out_reg:
+	ret = alloc_snapshot(&global_trace);
+	if (ret < 0)
+		goto out;
+
 	ret = register_ftrace_function_probe(glob, ops, count);
 
-	if (ret >= 0)
-		alloc_snapshot(&global_trace);
-
+ out:
 	return ret < 0 ? ret : 0;
 }
 
diff --git a/mm/Kconfig b/mm/Kconfig
index 0183305..eb10c90 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -720,3 +720,13 @@
 	bool
 config ARCH_HAS_PKEYS
 	bool
+
+config FORCE_ALLOC_FROM_DMA_ZONE
+	bool "Force certain memory allocators to always return ZONE_DMA memory"
+	depends on ZONE_DMA
+	help
+	  Ensure certain memory allocators always return memory from ZONE_DMA.
+	  This option helps ensure that clients who require ZONE_DMA memory are
+	  always using ZONE_DMA memory.
+
+	  If unsure, say "n".
diff --git a/mm/migrate.c b/mm/migrate.c
index f49de3cf..435f674 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -183,9 +183,9 @@
 			unlock_page(page);
 			put_page(page);
 		} else {
-			putback_lru_page(page);
 			dec_node_page_state(page, NR_ISOLATED_ANON +
 					page_is_file_cache(page));
+			putback_lru_page(page);
 		}
 	}
 }
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9d3f6d3..b4d398b 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2595,16 +2595,23 @@
 				    sc->nr_scanned - nr_scanned,
 				    node_lru_pages);
 
+		/*
+		 * Record the subtree's reclaim efficiency. The reclaimed
+		 * pages from slab is excluded here because the corresponding
+		 * scanned pages is not accounted. Moreover, freeing a page
+		 * by slab shrinking depends on each slab's object population,
+		 * making the cost model (i.e. scan:free) different from that
+		 * of LRU.
+		 */
+		vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
+			   sc->nr_scanned - nr_scanned,
+			   sc->nr_reclaimed - nr_reclaimed);
+
 		if (reclaim_state) {
 			sc->nr_reclaimed += reclaim_state->reclaimed_slab;
 			reclaim_state->reclaimed_slab = 0;
 		}
 
-		/* Record the subtree's reclaim efficiency */
-		vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
-			   sc->nr_scanned - nr_scanned,
-			   sc->nr_reclaimed - nr_reclaimed);
-
 		if (sc->nr_reclaimed - nr_reclaimed)
 			reclaimable = true;
 
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index f0f462c..8de6707 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -209,6 +209,9 @@
 	u8 *data;
 	bool pfmemalloc;
 
+	if (IS_ENABLED(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE))
+		gfp_mask |= GFP_DMA;
+
 	cache = (flags & SKB_ALLOC_FCLONE)
 		? skbuff_fclone_cache : skbuff_head_cache;
 
@@ -367,6 +370,9 @@
 	unsigned long flags;
 	void *data;
 
+	if (IS_ENABLED(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE))
+		gfp_mask |= GFP_DMA;
+
 	local_irq_save(flags);
 	nc = this_cpu_ptr(&netdev_alloc_cache);
 	data = __alloc_page_frag(nc, fragsz, gfp_mask);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a697ddf..acaaf61 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -208,6 +208,51 @@
 	return len;
 }
 
+static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata,
+					 struct sk_buff *skb,
+					 int rtap_vendor_space)
+{
+	struct {
+		struct ieee80211_hdr_3addr hdr;
+		u8 category;
+		u8 action_code;
+	} __packed action;
+
+	if (!sdata)
+		return;
+
+	BUILD_BUG_ON(sizeof(action) != IEEE80211_MIN_ACTION_SIZE + 1);
+
+	if (skb->len < rtap_vendor_space + sizeof(action) +
+		       VHT_MUMIMO_GROUPS_DATA_LEN)
+		return;
+
+	if (!is_valid_ether_addr(sdata->u.mntr.mu_follow_addr))
+		return;
+
+	skb_copy_bits(skb, rtap_vendor_space, &action, sizeof(action));
+
+	if (!ieee80211_is_action(action.hdr.frame_control))
+		return;
+
+	if (action.category != WLAN_CATEGORY_VHT)
+		return;
+
+	if (action.action_code != WLAN_VHT_ACTION_GROUPID_MGMT)
+		return;
+
+	if (!ether_addr_equal(action.hdr.addr1, sdata->u.mntr.mu_follow_addr))
+		return;
+
+	skb = skb_copy(skb, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+	skb_queue_tail(&sdata->skb_queue, skb);
+	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+}
+
 /*
  * ieee80211_add_rx_radiotap_header - add radiotap header
  *
@@ -515,7 +560,6 @@
 	struct net_device *prev_dev = NULL;
 	int present_fcs_len = 0;
 	unsigned int rtap_vendor_space = 0;
-	struct ieee80211_mgmt *mgmt;
 	struct ieee80211_sub_if_data *monitor_sdata =
 		rcu_dereference(local->monitor_sdata);
 
@@ -553,6 +597,8 @@
 		return remove_monitor_info(local, origskb, rtap_vendor_space);
 	}
 
+	ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_vendor_space);
+
 	/* room for the radiotap header based on driver features */
 	rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, origskb);
 	needed_headroom = rt_hdrlen - rtap_vendor_space;
@@ -618,23 +664,6 @@
 		ieee80211_rx_stats(sdata->dev, skb->len);
 	}
 
-	mgmt = (void *)skb->data;
-	if (monitor_sdata &&
-	    skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + VHT_MUMIMO_GROUPS_DATA_LEN &&
-	    ieee80211_is_action(mgmt->frame_control) &&
-	    mgmt->u.action.category == WLAN_CATEGORY_VHT &&
-	    mgmt->u.action.u.vht_group_notif.action_code == WLAN_VHT_ACTION_GROUPID_MGMT &&
-	    is_valid_ether_addr(monitor_sdata->u.mntr.mu_follow_addr) &&
-	    ether_addr_equal(mgmt->da, monitor_sdata->u.mntr.mu_follow_addr)) {
-		struct sk_buff *mu_skb = skb_copy(skb, GFP_ATOMIC);
-
-		if (mu_skb) {
-			mu_skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
-			skb_queue_tail(&monitor_sdata->skb_queue, mu_skb);
-			ieee80211_queue_work(&local->hw, &monitor_sdata->work);
-		}
-	}
-
 	if (prev_dev) {
 		skb->dev = prev_dev;
 		netif_receive_skb(skb);
@@ -3617,6 +3646,27 @@
 			    !ether_addr_equal(bssid, hdr->addr1))
 				return false;
 		}
+
+		/*
+		 * 802.11-2016 Table 9-26 says that for data frames, A1 must be
+		 * the BSSID - we've checked that already but may have accepted
+		 * the wildcard (ff:ff:ff:ff:ff:ff).
+		 *
+		 * It also says:
+		 *	The BSSID of the Data frame is determined as follows:
+		 *	a) If the STA is contained within an AP or is associated
+		 *	   with an AP, the BSSID is the address currently in use
+		 *	   by the STA contained in the AP.
+		 *
+		 * So we should not accept data frames with an address that's
+		 * multicast.
+		 *
+		 * Accepting it also opens a security problem because stations
+		 * could encrypt it with the GTK and inject traffic that way.
+		 */
+		if (ieee80211_is_data(hdr->frame_control) && multicast)
+			return false;
+
 		return true;
 	case NL80211_IFTYPE_WDS:
 		if (bssid || !ieee80211_is_data(hdr->frame_control))
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e318878..35ad69f 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -70,7 +70,7 @@
 MODULE_PARM_DESC(bss_entries_limit,
                  "limit to number of scan BSS entries (per wiphy, default 1000)");
 
-#define IEEE80211_SCAN_RESULT_EXPIRE	(7 * HZ)
+#define IEEE80211_SCAN_RESULT_EXPIRE	(30 * HZ)
 
 static void bss_free(struct cfg80211_internal_bss *bss)
 {
diff --git a/scripts/build-all.py b/scripts/build-all.py
index d36e96f..bd468cd 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -307,10 +307,12 @@
         r'qsd*_defconfig',
         r'mpq*_defconfig',
         r'sdm[0-9]*_defconfig',
+        r'sdx*_defconfig',
         )
     arch64_pats = (
         r'msm*_defconfig',
         r'sdm[0-9]*_defconfig',
+        r'sdx*_defconfig',
         )
     for p in arch_pats:
         for n in glob.glob('arch/arm/configs/' + p):
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index f93db0e..a0d45ef 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2438,15 +2438,6 @@
 						     $herecurr);
 					}
 					$shorttext = AFTER_SHORTTEXT;
-				} elsif (length($line) > (SHORTTEXT_LIMIT +
-							  $shorttext_exspc)
-					 && $line !~ /^:([0-7]{6}\s){2}
-						      ([[:xdigit:]]+\.*
-						       \s){2}\w+\s\w+/xms) {
-					WARN("LONG_COMMIT_TEXT",
-					     "commit text line over " .
-					     SHORTTEXT_LIMIT .
-					     " characters\n" . $herecurr);
 				} elsif ($line=~/^\s*change-id:/i ||
 					 $line=~/^\s*signed-off-by:/i ||
 					 $line=~/^\s*crs-fixed:/i ||
diff --git a/security/keys/gc.c b/security/keys/gc.c
index addf060..9cb4fe4 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -46,7 +46,7 @@
  * immediately unlinked.
  */
 struct key_type key_type_dead = {
-	.name = "dead",
+	.name = ".dead",
 };
 
 /*
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index d580ad0..dbbfd77 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -271,7 +271,8 @@
  * Create and join an anonymous session keyring or join a named session
  * keyring, creating it if necessary.  A named session keyring must have Search
  * permission for it to be joined.  Session keyrings without this permit will
- * be skipped over.
+ * be skipped over.  It is not permitted for userspace to create or join
+ * keyrings whose name begin with a dot.
  *
  * If successful, the ID of the joined session keyring will be returned.
  */
@@ -288,12 +289,16 @@
 			ret = PTR_ERR(name);
 			goto error;
 		}
+
+		ret = -EPERM;
+		if (name[0] == '.')
+			goto error_name;
 	}
 
 	/* join the session */
 	ret = join_session_keyring(name);
+error_name:
 	kfree(name);
-
 error:
 	return ret;
 }
@@ -1251,8 +1256,8 @@
  * Read or set the default keyring in which request_key() will cache keys and
  * return the old setting.
  *
- * If a process keyring is specified then this will be created if it doesn't
- * yet exist.  The old setting will be returned if successful.
+ * If a thread or process keyring is specified then it will be created if it
+ * doesn't yet exist.  The old setting will be returned if successful.
  */
 long keyctl_set_reqkey_keyring(int reqkey_defl)
 {
@@ -1277,11 +1282,8 @@
 
 	case KEY_REQKEY_DEFL_PROCESS_KEYRING:
 		ret = install_process_keyring_to_cred(new);
-		if (ret < 0) {
-			if (ret != -EEXIST)
-				goto error;
-			ret = 0;
-		}
+		if (ret < 0)
+			goto error;
 		goto set;
 
 	case KEY_REQKEY_DEFL_DEFAULT:
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 40a8852..45536c6 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -127,13 +127,18 @@
 }
 
 /*
- * Install a fresh thread keyring directly to new credentials.  This keyring is
- * allowed to overrun the quota.
+ * Install a thread keyring to the given credentials struct if it didn't have
+ * one already.  This is allowed to overrun the quota.
+ *
+ * Return: 0 if a thread keyring is now present; -errno on failure.
  */
 int install_thread_keyring_to_cred(struct cred *new)
 {
 	struct key *keyring;
 
+	if (new->thread_keyring)
+		return 0;
+
 	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
 				KEY_POS_ALL | KEY_USR_VIEW,
 				KEY_ALLOC_QUOTA_OVERRUN,
@@ -146,7 +151,9 @@
 }
 
 /*
- * Install a fresh thread keyring, discarding the old one.
+ * Install a thread keyring to the current task if it didn't have one already.
+ *
+ * Return: 0 if a thread keyring is now present; -errno on failure.
  */
 static int install_thread_keyring(void)
 {
@@ -157,8 +164,6 @@
 	if (!new)
 		return -ENOMEM;
 
-	BUG_ON(new->thread_keyring);
-
 	ret = install_thread_keyring_to_cred(new);
 	if (ret < 0) {
 		abort_creds(new);
@@ -169,17 +174,17 @@
 }
 
 /*
- * Install a process keyring directly to a credentials struct.
+ * Install a process keyring to the given credentials struct if it didn't have
+ * one already.  This is allowed to overrun the quota.
  *
- * Returns -EEXIST if there was already a process keyring, 0 if one installed,
- * and other value on any other error
+ * Return: 0 if a process keyring is now present; -errno on failure.
  */
 int install_process_keyring_to_cred(struct cred *new)
 {
 	struct key *keyring;
 
 	if (new->process_keyring)
-		return -EEXIST;
+		return 0;
 
 	keyring = keyring_alloc("_pid", new->uid, new->gid, new,
 				KEY_POS_ALL | KEY_USR_VIEW,
@@ -193,11 +198,9 @@
 }
 
 /*
- * Make sure a process keyring is installed for the current process.  The
- * existing process keyring is not replaced.
+ * Install a process keyring to the current task if it didn't have one already.
  *
- * Returns 0 if there is a process keyring by the end of this function, some
- * error otherwise.
+ * Return: 0 if a process keyring is now present; -errno on failure.
  */
 static int install_process_keyring(void)
 {
@@ -211,14 +214,18 @@
 	ret = install_process_keyring_to_cred(new);
 	if (ret < 0) {
 		abort_creds(new);
-		return ret != -EEXIST ? ret : 0;
+		return ret;
 	}
 
 	return commit_creds(new);
 }
 
 /*
- * Install a session keyring directly to a credentials struct.
+ * Install the given keyring as the session keyring of the given credentials
+ * struct, replacing the existing one if any.  If the given keyring is NULL,
+ * then install a new anonymous session keyring.
+ *
+ * Return: 0 on success; -errno on failure.
  */
 int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
 {
@@ -253,8 +260,11 @@
 }
 
 /*
- * Install a session keyring, discarding the old one.  If a keyring is not
- * supplied, an empty one is invented.
+ * Install the given keyring as the session keyring of the current task,
+ * replacing the existing one if any.  If the given keyring is NULL, then
+ * install a new anonymous session keyring.
+ *
+ * Return: 0 on success; -errno on failure.
  */
 static int install_session_keyring(struct key *keyring)
 {
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 51c27b7..b75ba98 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -5247,7 +5247,6 @@
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
 		.dpcm_playback = 1,
-		.dpcm_capture = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			    SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
index f64074d..1c03d8c 100644
--- a/sound/soc/msm/sdm660-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.c
@@ -335,7 +335,6 @@
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
 		.dpcm_playback = 1,
-		.dpcm_capture = 1,
 		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
 			    SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 96f3f85..304bf47 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -155,6 +155,21 @@
 	u32 index;
 };
 
+enum pinctrl_pin_state {
+	STATE_DISABLE = 0, /* All pins are in sleep state */
+	STATE_MI2S_ACTIVE,  /* IS2 = active, TDM = sleep */
+	STATE_TDM_ACTIVE,  /* IS2 = sleep, TDM = active */
+};
+
+struct msm_pinctrl_info {
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *mi2s_disable;
+	struct pinctrl_state *tdm_disable;
+	struct pinctrl_state *mi2s_active;
+	struct pinctrl_state *tdm_active;
+	enum pinctrl_pin_state curr_state;
+};
+
 struct msm_asoc_mach_data {
 	u32 mclk_freq;
 	int us_euro_gpio; /* used by gpio driver API */
@@ -162,6 +177,7 @@
 	struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
 	struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
 	struct snd_info_entry *codec_root;
+	struct msm_pinctrl_info pinctrl_info;
 };
 
 struct msm_asoc_wcd93xx_codec {
@@ -170,6 +186,9 @@
 	void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
 };
 
+static const char *const pin_states[] = {"sleep", "i2s-active",
+					 "tdm-active"};
+
 enum {
 	TDM_0 = 0,
 	TDM_1,
@@ -397,7 +416,8 @@
 					"KHZ_88P2", "KHZ_96", "KHZ_176P4",
 					"KHZ_192", "KHZ_352P8", "KHZ_384"};
 static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
-						  "KHZ_192"};
+						"KHZ_192", "KHZ_32", "KHZ_44P1",
+						"KHZ_88P2", "KHZ_176P4"	};
 static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
 				    "Five", "Six", "Seven", "Eight"};
 static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
@@ -508,6 +528,7 @@
 	.key_code[7] = 0,
 	.linein_th = 5000,
 	.moisture_en = true,
+	.mbhc_micbias = MIC_BIAS_2,
 	.anc_micbias = MIC_BIAS_2,
 	.enable_anc_mic_detect = false,
 };
@@ -1466,6 +1487,22 @@
 		return idx;
 
 	switch (ext_disp_rx_cfg[idx].sample_rate) {
+	case SAMPLING_RATE_176P4KHZ:
+		sample_rate_val = 6;
+		break;
+
+	case SAMPLING_RATE_88P2KHZ:
+		sample_rate_val = 5;
+		break;
+
+	case SAMPLING_RATE_44P1KHZ:
+		sample_rate_val = 4;
+		break;
+
+	case SAMPLING_RATE_32KHZ:
+		sample_rate_val = 3;
+		break;
+
 	case SAMPLING_RATE_192KHZ:
 		sample_rate_val = 2;
 		break;
@@ -1496,6 +1533,18 @@
 		return idx;
 
 	switch (ucontrol->value.integer.value[0]) {
+	case 6:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_176P4KHZ;
+		break;
+	case 5:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_88P2KHZ;
+		break;
+	case 4:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_44P1KHZ;
+		break;
+	case 3:
+		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_32KHZ;
+		break;
 	case 2:
 		ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
 		break;
@@ -3773,6 +3822,275 @@
 	return ret;
 }
 
+static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info,
+				enum pinctrl_pin_state new_state)
+{
+	int ret = 0;
+	int curr_state = 0;
+
+	if (pinctrl_info == NULL) {
+		pr_err("%s: pinctrl_info is NULL\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+	curr_state = pinctrl_info->curr_state;
+	pinctrl_info->curr_state = new_state;
+	pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
+		 pin_states[curr_state], pin_states[pinctrl_info->curr_state]);
+
+	if (curr_state == pinctrl_info->curr_state) {
+		pr_debug("%s: Already in same state\n", __func__);
+		goto err;
+	}
+
+	if (curr_state != STATE_DISABLE &&
+		pinctrl_info->curr_state != STATE_DISABLE) {
+		pr_debug("%s: state already active cannot switch\n", __func__);
+		ret = -EIO;
+		goto err;
+	}
+
+	switch (pinctrl_info->curr_state) {
+	case STATE_MI2S_ACTIVE:
+		ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->mi2s_active);
+		if (ret) {
+			pr_err("%s: MI2S state select failed with %d\n",
+				__func__, ret);
+			ret = -EIO;
+			goto err;
+		}
+		break;
+	case STATE_TDM_ACTIVE:
+		ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->tdm_active);
+		if (ret) {
+			pr_err("%s: TDM state select failed with %d\n",
+				__func__, ret);
+			ret = -EIO;
+			goto err;
+		}
+		break;
+	case STATE_DISABLE:
+		if (curr_state == STATE_MI2S_ACTIVE) {
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->mi2s_disable);
+		} else {
+			ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->tdm_disable);
+		}
+		if (ret) {
+			pr_err("%s:  state disable failed with %d\n",
+				__func__, ret);
+			ret = -EIO;
+			goto err;
+		}
+		break;
+	default:
+		pr_err("%s: TLMM pin state is invalid\n", __func__);
+		return -EINVAL;
+	}
+
+err:
+	return ret;
+}
+
+static void msm_release_pinctrl(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+	if (pinctrl_info->pinctrl) {
+		devm_pinctrl_put(pinctrl_info->pinctrl);
+		pinctrl_info->pinctrl = NULL;
+	}
+}
+
+static int msm_get_pinctrl(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = NULL;
+	struct pinctrl *pinctrl;
+	int ret;
+
+	pinctrl_info = &pdata->pinctrl_info;
+
+	if (pinctrl_info == NULL) {
+		pr_err("%s: pinctrl_info is NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR_OR_NULL(pinctrl)) {
+		pr_err("%s: Unable to get pinctrl handle\n", __func__);
+		return -EINVAL;
+	}
+	pinctrl_info->pinctrl = pinctrl;
+
+	/* get all the states handles from Device Tree */
+	pinctrl_info->mi2s_disable = pinctrl_lookup_state(pinctrl,
+						"quat-mi2s-sleep");
+	if (IS_ERR(pinctrl_info->mi2s_disable)) {
+		pr_err("%s: could not get mi2s_disable pinstate\n", __func__);
+		goto err;
+	}
+	pinctrl_info->mi2s_active = pinctrl_lookup_state(pinctrl,
+						"quat-mi2s-active");
+	if (IS_ERR(pinctrl_info->mi2s_active)) {
+		pr_err("%s: could not get mi2s_active pinstate\n", __func__);
+		goto err;
+	}
+	pinctrl_info->tdm_disable = pinctrl_lookup_state(pinctrl,
+						"quat-tdm-sleep");
+	if (IS_ERR(pinctrl_info->tdm_disable)) {
+		pr_err("%s: could not get tdm_disable pinstate\n", __func__);
+		goto err;
+	}
+	pinctrl_info->tdm_active = pinctrl_lookup_state(pinctrl,
+						"quat-tdm-active");
+	if (IS_ERR(pinctrl_info->tdm_active)) {
+		pr_err("%s: could not get tdm_active pinstate\n",
+			__func__);
+		goto err;
+	}
+	/* Reset the TLMM pins to a default state */
+	ret = pinctrl_select_state(pinctrl_info->pinctrl,
+					pinctrl_info->mi2s_disable);
+	if (ret != 0) {
+		pr_err("%s: Disable TLMM pins failed with %d\n",
+			__func__, ret);
+		ret = -EIO;
+		goto err;
+	}
+	pinctrl_info->curr_state = STATE_DISABLE;
+
+	return 0;
+
+err:
+	devm_pinctrl_put(pinctrl);
+	pinctrl_info->pinctrl = NULL;
+	return -EINVAL;
+}
+
+static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				      struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) {
+		channels->min = channels->max =
+				tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+		rate->min = rate->max =
+				tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+	} else if (cpu_dai->id == AFE_PORT_ID_SECONDARY_TDM_RX) {
+		channels->min = channels->max =
+				tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			       tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+		rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+	} else {
+		pr_err("%s: dai id 0x%x not supported\n",
+			__func__, cpu_dai->id);
+		return -EINVAL;
+	}
+
+	pr_debug("%s: dai id = 0x%x channels = %d rate = %d format = 0x%x\n",
+		__func__, cpu_dai->id, channels->max, rate->max,
+		params_format(params));
+
+	return 0;
+}
+
+static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+	int channels, slot_width, slots;
+	unsigned int slot_mask;
+	unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+
+	pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+	slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+	/*2 slot config - bits 0 and 1 set for the first two slots */
+	slot_mask = 0x0000FFFF >> (16-slots);
+	slot_width = 32;
+	channels = slots;
+
+	pr_debug("%s: slot_width %d slots %d\n", __func__, slot_width, slots);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		pr_debug("%s: slot_width %d\n", __func__, slot_width);
+		ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+			slots, slot_width);
+		if (ret < 0) {
+			pr_err("%s: failed to set tdm slot, err:%d\n",
+				__func__, ret);
+			goto end;
+		}
+
+		ret = snd_soc_dai_set_channel_map(cpu_dai,
+			0, NULL, channels, slot_offset);
+		if (ret < 0) {
+			pr_err("%s: failed to set channel map, err:%d\n",
+				__func__, ret);
+			goto end;
+		}
+	} else {
+		pr_err("%s: invalid use case, err:%d\n",
+			__func__, ret);
+	}
+
+end:
+	return ret;
+}
+
+static int sdm845_tdm_snd_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+	ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
+	if (ret)
+		pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static void sdm845_tdm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+	ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+	if (ret)
+		pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+			__func__, ret);
+
+}
+
+static struct snd_soc_ops sdm845_tdm_be_ops = {
+	.hw_params = sdm845_tdm_snd_hw_params,
+	.startup = sdm845_tdm_snd_startup,
+	.shutdown = sdm845_tdm_snd_shutdown
+};
+
 static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
 {
 	int ret = 0;
@@ -3780,6 +4098,9 @@
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int index = cpu_dai->id;
 	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
 
 	dev_dbg(rtd->card->dev,
 		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
@@ -3793,6 +4114,14 @@
 			__func__, cpu_dai->id);
 		goto err;
 	}
+	if (index == QUAT_MI2S) {
+		ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+		if (ret) {
+			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+				__func__, ret);
+			goto err;
+		}
+	}
 	/*
 	 * Muxtex protection in case the same MI2S
 	 * interface using for both TX and RX  so
@@ -3845,6 +4174,9 @@
 	int ret;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	int index = rtd->cpu_dai->id;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+	struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
 
 	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
 		 substream->name, substream->stream);
@@ -3863,6 +4195,13 @@
 		}
 	}
 	mutex_unlock(&mi2s_intf_conf[index].lock);
+
+	if (index == QUAT_MI2S) {
+		ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+		if (ret)
+			pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+				__func__, ret);
+	}
 }
 
 static struct snd_soc_ops msm_mi2s_be_ops = {
@@ -4900,8 +5239,8 @@
 		.no_pcm = 1,
 		.dpcm_playback = 1,
 		.id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
-		.be_hw_params_fixup = msm_be_hw_params_fixup,
-		.ops = &msm_tdm_be_ops,
+		.be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+		.ops = &sdm845_tdm_be_ops,
 		.ignore_suspend = 1,
 	},
 	{
@@ -6267,6 +6606,17 @@
 		dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
 			ret);
 
+	/* Parse pinctrl info from devicetree */
+	ret = msm_get_pinctrl(pdev);
+	if (!ret) {
+		pr_debug("%s: pinctrl parsing successful\n", __func__);
+	} else {
+		dev_dbg(&pdev->dev,
+			"%s: Parsing pinctrl failed with %d. Cannot use Ports\n",
+			__func__, ret);
+		ret = 0;
+	}
+
 	msm_i2s_auxpcm_init(pdev);
 
 	is_initial_boot = true;
@@ -6278,6 +6628,7 @@
 
 	return 0;
 err:
+	msm_release_pinctrl(pdev);
 	devm_kfree(&pdev->dev, pdata);
 	return ret;
 }
@@ -6294,6 +6645,7 @@
 	}
 	msm_i2s_auxpcm_deinit();
 
+	msm_release_pinctrl(pdev);
 	snd_soc_unregister_card(card);
 	return 0;
 }