Merge "msm: vidc: Update platform data for sdm670"
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
index 7496f4d..64154590 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
@@ -21,27 +21,27 @@
 	Usage:      required
 	Value type: <stringlist>
 	Definition: Address names. Must be "osm_l3_base", "osm_pwrcl_base",
-		    "osm_perfcl_base", and "cpr_rc".
+		    "osm_perfcl_base".
 		    Must be specified in the same order as the corresponding
 		    addresses are specified in the reg property.
 
-- vdd_l3_mx_ao-supply
-	Usage:      required
-	Value type: <phandle>
-	Definition: Phandle to the MX active-only regulator device.
-
-- vdd_pwrcl_mx_ao-supply
-	Usage:      required
-	Value type: <phandle>
-	Definition: Phandle to the MX active-only regulator device.
-
 - qcom,mx-turbo-freq
-	Usage:      required
+	Usage:      optional
 	Value type: <array>
 	Definition: List of frequencies for the 3 clock domains (following the
 		    order of L3, power, and performance clusters) that denote
 		    the lowest rate that requires a TURBO vote on the MX rail.
 
+- vdd_l3_mx_ao-supply
+	Usage:      required if qcom,mx-turbo-freq is specified
+	Value type: <phandle>
+	Definition: Phandle to the MX active-only regulator device.
+
+- vdd_pwrcl_mx_ao-supply
+	Usage:      required if qcom,mx-turbo-freq is specified
+	Value type: <phandle>
+	Definition: Phandle to the MX active-only regulator device.
+
 - l3-devs
 	Usage: optional
 	Value type: <phandle>
@@ -63,10 +63,8 @@
 		compatible = "qcom,clk-cpu-osm";
 		reg = <0x17d41000 0x1400>,
 			<0x17d43000 0x1400>,
-			<0x17d45800 0x1400>,
-			<0x784248 0x4>;
-		reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
-							"cpr_rc";
+			<0x17d45800 0x1400>;
+		reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base";
 		vdd_l3_mx_ao-supply = <&pm8998_s6_level_ao>;
 		vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>;
 
diff --git a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
new file mode 100644
index 0000000..ccefc98
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
@@ -0,0 +1,328 @@
+Qualcomm RPM Regulators
+
+rpm-regulator-smd is a regulator driver which supports regulators inside of
+PMICs which are controlled by the RPM processor.  Communication with the RPM
+processor takes place over SMD.
+
+Required structure:
+- RPM regulators must be described in two levels of devices nodes.  The first
+	level describes the interface with the RPM.  The second level describes
+	properties of one regulator framework interface (of potentially many) to
+	the regulator.
+
+[First Level Nodes]
+
+Required properties:
+- compatible:          Must be "qcom,rpm-smd-regulator-resource"
+- qcom,resource-name:  Resource name string for this regulator to be used in RPM
+			transactions.  Length is 4 characters max.
+- qcom,resource-id:    Resource instance ID for this regulator to be used in RPM
+			transactions.
+- qcom,regulator-type: Type of this regulator.  Supported values are:
+				0 = LDO
+				1 = SMPS
+				2 = VS
+				3 = NCP
+				4 = Buck or Boost (BoB)
+
+Optional properties:
+- qcom,allow-atomic:   Flag specifying if atomic access is allowed for this
+			regulator.  Supported values are:
+				0 or not present = mutex locks used
+				1 = spinlocks used
+- qcom,enable-time:    Time in us to delay after enabling the regulator
+- qcom,hpm-min-load:   Load current in uA which corresponds to the minimum load
+			which requires the regulator to be in high power mode.
+- qcom,apps-only:      Flag which indicates that the regulator only has
+			consumers on the application processor. If this flag
+			is specified, then voltage and current updates are
+			only sent to the RPM if the regulator is enabled.
+- qcom,always-wait-for-ack:   Flag which indicates that the application
+			processor must wait for an ACK or a NACK from the RPM
+			for every request sent for this regulator including
+			those which are for a strictly lower power state.
+
+[Second Level Nodes]
+
+Required properties:
+- compatible:          Must be "qcom,rpm-smd-regulator"
+- regulator-name:      A string used as a descriptive name for regulator outputs
+- qcom,set:            Specifies which sets that requests made with this
+			regulator interface should be sent to.  Regulator
+			requests sent in the active set take effect immediately.
+			Requests sent in the sleep set take effect when the Apps
+			processor transitions into RPM assisted power collapse.
+			Supported values are:
+				1 = Active set only
+				2 = Sleep set only
+				3 = Both active and sleep sets
+
+
+
+Optional properties:
+- parent-supply:               phandle to the parent supply/regulator node
+- qcom,system-load:            Load in uA present on regulator that is not
+				captured by any consumer request
+- qcom,use-voltage-corner:     Flag that signifies if regulator_set_voltage
+				calls should modify the corner parameter instead
+				of the voltage parameter.  When used, voltages
+				specified inside of the regulator framework
+				represent corners that have been incremented by
+				1.  This value shift is necessary to work around
+				limitations in the regulator framework which
+				treat 0 uV as an error.
+- qcom,use-voltage-floor-corner:  Flag that signifies if regulator_set_voltage
+				calls should modify the floor corner parameter
+				instead of the voltage parameter.  When used,
+				voltages specified inside of the regulator
+				framework represent corners that have been
+				incremented by 1.  The properties
+				qcom,use-voltage-corner and
+				qcom,use-voltage-floor-corner are mutually
+				exclusive.  Only one may be specified for a
+				given regulator.
+- qcom,use-voltage-level:      Flag that signifies if regulator_set_voltage
+				calls should modify the level parameter instead
+				of the voltage parameter.
+- qcom,use-voltage-floor-level:   Flag that signifies if regulator_set_voltage
+				calls should modify the floor level parameter
+				instead of the voltage parameter.
+				The properties qcom,use-voltage-level and
+				qcom,use-voltage-floor-level are mutually
+				exclusive.  Only one may be specified for a
+				given regulator.
+- qcom,use-pin-ctrl-voltage1:  Flag which indicates that updates to voltage
+				should be sent to the pin control voltage 1
+				parameter. Only one pin may be specified per
+				regulator. This property only applies to BoB
+				type regulators.
+- qcom,use-pin-ctrl-voltage2:  Flag which indicates that updates to voltage
+				should be sent to the pin control voltage 2
+				parameter. Only one pin may be specified per
+				regulator. This property only applies to BoB
+				type regulators.
+- qcom,use-pin-ctrl-voltage3:  Flag which indicates that updates to voltage
+				should be sent to the pin control voltage 3
+				parameter. Only one pin may be specified per
+				regulator. This property only applies to BoB
+				type regulators.
+- qcom,always-send-voltage:    Flag which indicates that updates to the
+				voltage, voltage corner or voltage level set
+				point should always be sent immediately to the
+				RPM. If this flag is not specified, then
+				voltage set point updates are only sent if the
+				given regulator has also been enabled by a
+				Linux consumer.
+- qcom,always-send-current:    Flag which indicates that updates to the load
+				current should always be sent immediately to the
+				RPM.  If this flag is not specified, then load
+				current updates are only sent if the given
+				regulator has also been enabled by a Linux
+				consumer.
+- qcom,send-defaults:          Boolean flag which indicates that the initial
+				parameter values should be sent to the RPM
+				before consumers make their own requests.  If
+				this flag is not specified, then initial
+				parameters values will only be sent after some
+				consumer makes a request.
+- qcom,enable-with-pin-ctrl:   Double in which the first element corresponds to
+				the pin control enable parameter value to send
+				when all consumers have requested the regulator
+				to be disabled.  The second element corresponds
+				to the pin control enable parameter value to
+				send when any consumer has requested the
+				regulator to be enabled.  Each element supports
+				the same set of values as the
+				qcom,init-pin-ctrl-enable property listed below.
+
+The following properties specify initial values for parameters to be sent to the
+RPM in regulator requests.
+- qcom,init-enable:            0 = regulator disabled
+			       1 = regulator enabled
+- qcom,init-voltage:           Voltage in uV
+- qcom,init-current:           Current in mA
+- qcom,init-ldo-mode:          Operating mode to be used with LDO regulators
+				Supported values are:
+					0 = mode determined by current requests
+					1 = force HPM (NPM)
+- qcom,init-smps-mode:         Operating mode to be used with SMPS regulators
+				Supported values are:
+					0 = auto; hardware determines mode
+					1 = mode determined by current requests
+					2 = force HPM (PWM)
+- qcom,init-bob-mode:          Operating mode to be used with BoB regulators
+				Supported values are:
+					0 = pass; use priority order
+					1 = force PFM
+					2 = auto; hardware determines mode
+					3 = force PWM
+- qcom,init-pin-ctrl-enable:   Bit mask specifying which hardware pins should be
+				used to enable the regulator, if any; supported
+				bits are:
+					0 = ignore all hardware enable signals
+					BIT(0) = follow HW0_EN signal
+					BIT(1) = follow HW1_EN signal
+					BIT(2) = follow HW2_EN signal
+					BIT(3) = follow HW3_EN signal
+- qcom,init-pin-ctrl-mode:     Bit mask specifying which hardware pins should be
+				used to force the regulator into high power
+				mode, if any.  Supported bits are:
+					0 = ignore all hardware enable signals
+					BIT(0) = follow HW0_EN signal
+					BIT(1) = follow HW1_EN signal
+					BIT(2) = follow HW2_EN signal
+					BIT(3) = follow HW3_EN signal
+					BIT(4) = follow PMIC awake state
+- qcom,init-pin-ctrl-voltage1: Minimum voltage in micro-volts to use while pin
+				control 1 is enabled. This property only
+				applies to BoB type regulators.
+- qcom,init-pin-ctrl-voltage2: Minimum voltage in micro-volts to use while pin
+				control 2 is enabled. This property only
+				applies to BoB type regulators.
+- qcom,init-pin-ctrl-voltage3: Minimum voltage in micro-volts to use while pin
+				control 3 is enabled. This property only
+				applies to BoB type regulators.
+- qcom,init-frequency:         Switching frequency divisor for SMPS regulators.
+				Supported values are n = 0 to 31 where
+				freq = 19.2 MHz / (n + 1).
+- qcom,init-head-room:         Voltage head room in mV required for the
+				regulator.  This head room value should be used
+				in situations where the device connected to the
+				output of the regulator has low noise tolerance.
+				Note that the RPM independently enforces a
+				safety head room value for subregulated LDOs
+				which is sufficient to account for LDO drop-out
+				voltage.
+- qcom,init-quiet-mode:        Specify that quiet mode is needed for an SMPS
+				regulator in order to have lower output noise.
+				Supported values are:
+					0 = No quiet mode
+					1 = Quiet mode
+					2 = Super quiet mode
+- qcom,init-freq-reason:       Consumer requiring specified frequency for an
+				SMPS regulator.  Supported values are:
+					0 = None
+					1 = Bluetooth
+					2 = GPS
+					4 = WLAN
+					8 = WAN
+- qcom,init-voltage-corner:    Performance corner to use in order to determine
+				voltage set point.  This value corresponds to
+				the actual value that will be sent and is not
+				incremented by 1 like the values used inside of
+				the regulator framework.  The meaning of corner
+				values is set by the RPM.  It is possible that
+				different regulators on a given platform or
+				similar regulators on different platforms will
+				utilize different corner values.  These are
+				corner values supported on MSM8974 for PMIC
+				PM8841 SMPS 2 (VDD_Dig); nominal voltages for
+				these corners are also shown:
+					0 = None         (don't care)
+					1 = Retention    (0.5000 V)
+					2 = SVS Krait    (0.7250 V)
+					3 = SVS SOC      (0.8125 V)
+					4 = Normal       (0.9000 V)
+					5 = Turbo        (0.9875 V)
+					6 = Super Turbo  (1.0500 V)
+- qcom,init-disallow-bypass:   Specify that bypass mode should not be used for a
+				given LDO regulator.  When in bypass mode, an
+				LDO performs no regulation and acts as a simple
+				switch.  The RPM can utilize this mode for an
+				LDO that is subregulated from an SMPS when it is
+				possible to reduce the SMPS voltage to the
+				desired LDO output level.  Bypass mode may be
+				disallowed if lower LDO output noise is
+				required.  Supported values are:
+					0 = Allow RPM to utilize LDO bypass mode
+						if possible
+					1 = Disallow LDO bypass mode
+- qcom,init-voltage-floor-corner:  Minimum performance corner to use if any
+				processor in the system is awake.  This property
+				supports the same values as
+				qcom,init-voltage-corner.
+- qcom,init-voltage-level:     Performance level to use in order to determine
+				voltage set point. The meaning of level
+				values is set by the RPM. It is possible that
+				different regulators on a given platform or
+				similar regulators on different platforms will
+				utilize different level values. These are
+				level values supported on MSM8952 for PMIC
+				PM8952 SMPS 2 (VDD_Dig); nominal voltages for
+				these level are also shown:
+					16  = Retention    (0.5000 V)
+					128 = SVS          (1.0500 V)
+					192 = SVS+         (1.1550 V)
+					256 = Normal       (1.2250 V)
+					320 = Normal+      (1.2875 V)
+					384 = Turbo        (1.3500 V)
+- qcom,init-voltage-floor-level:   Minimum performance level to use if any
+				processor in the system is awake. This property
+				supports the same values as
+				qcom,init-voltage-level.
+
+All properties specified within the core regulator framework can also be used in
+second level nodes.  These bindings can be found in:
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+Examples:
+
+rpm-regulator-smpb1 {
+	qcom,resource-name = "smpb";
+	qcom,resource-id = <1>;
+	qcom,regulator-type = <1>;
+	qcom,hpm-min-load = <100000>;
+	compatible = "qcom,rpm-smd-regulator-resource";
+	status = "disabled";
+
+	pm8841_s1: regulator-s1 {
+		regulator-name = "8841_s1";
+		qcom,set = <3>;
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <1150000>;
+		qcom,init-voltage = <1150000>;
+		compatible = "qcom,rpm-smd-regulator";
+	};
+	pm8841_s1_ao: regulator-s1-ao {
+		regulator-name = "8841_s1_ao";
+		qcom,set = <1>;
+		regulator-min-microvolt = <900000>;
+		regulator-max-microvolt = <1150000>;
+		compatible = "qcom,rpm-smd-regulator";
+	};
+	pm8841_s1_corner: regulator-s1-corner {
+		regulator-name = "8841_s1_corner";
+		qcom,set = <3>;
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <6>;
+		qcom,init-voltage-corner = <3>;
+		qcom,use-voltage-corner;
+		compatible = "qcom,rpm-smd-regulator";
+	};
+};
+
+rpm-regulator-ldoa2 {
+	qcom,resource-name = "ldoa";
+	qcom,resource-id = <2>;
+	qcom,regulator-type = <0>;
+	qcom,hpm-min-load = <10000>;
+	compatible = "qcom,rpm-smd-regulator-resource";
+
+	regulator-l2 {
+		compatible = "qcom,rpm-smd-regulator";
+		regulator-name = "8941_l2";
+		qcom,set = <3>;
+		regulator-min-microvolt = <1225000>;
+		regulator-max-microvolt = <1225000>;
+		qcom,init-voltage = <1225000>;
+	};
+	regulator-l2-pin-ctrl {
+		compatible = "qcom,rpm-smd-regulator";
+		regulator-name = "8941_l2_pin_ctrl";
+		qcom,set = <3>;
+		regulator-min-microvolt = <1225000>;
+		regulator-max-microvolt = <1225000>;
+		qcom,init-voltage = <1225000>;
+		qcom,enable-with-pin-ctrl = <0 1>;
+	};
+};
diff --git a/Documentation/devicetree/bindings/regulator/spm-regulator.txt b/Documentation/devicetree/bindings/regulator/spm-regulator.txt
new file mode 100644
index 0000000..c324157
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/spm-regulator.txt
@@ -0,0 +1,61 @@
+Qualcomm Technologies Inc. SPM Regulators
+
+spm-regulator is a regulator device which supports PMIC processor supply
+regulators via the SPM module.
+
+Required properties:
+- compatible:      Must be "qcom,spm-regulator"
+- reg:             Specifies the SPMI address and size for this regulator device
+- regulator-name:  A string used as a descriptive name for the regulator
+
+Required structure:
+- A qcom,spm-regulator node must be a child of an SPMI node that has specified
+	the spmi-slave-container property
+
+Optional properties:
+- qcom,mode:       A string which specifies the mode to use for the regulator.
+		    Supported values are "pwm" and "auto".  PWM mode is more
+		    robust, but draws more current than auto mode.  If this
+		    property is not specified, then the regulator will remain
+		    in whatever mode hardware or bootloaders set it to.
+- qcom,cpu-num:    Specifies which CPU this regulator powers.  This property is
+		    not need when the SPM regulator is shared between all CPUs.
+- qcom,bypass-spm: Boolean flag which indicates that voltage control should not
+		    be managed by an SPM.  Instead, the voltage should be
+		    controlled via SPMI.
+- qcom,max-voltage-step:  Maximum single voltage step size in microvolts.
+- qcom,recal-mask: Bit mask of the APSS clusters to recalibrate after each
+		    voltage change.  Bit 0 corresponds to the first cluster,
+		    bit 1 corresponds to the second cluster, and so on.
+
+Optional structure:
+- A child node may be specified within a qcom,spm-regulator node which defines
+	an additional regulator which controls the AVS minimum and maximum
+	voltage limits.
+- The AVS child node must contain these properties defined in regulator.txt:
+	regulator-name, regulator-min-microvolt, regulator-max-microvolt.
+
+All properties specified within the core regulator framework can also be used.
+These bindings can be found in regulator.txt.
+
+Example:
+	qcom,spmi@fc4c0000 {
+
+		qcom,pm8226@1 {
+			spmi-slave-container;
+
+			spm-regulator@1700 {
+				compatible = "qcom,spm-regulator";
+				regulator-name = "8226_s2";
+				reg = <0x1700 0x100>;
+				regulator-min-microvolt = <900000>;
+				regulator-max-microvolt = <1275000>;
+
+				avs-limit-regulator {
+					regulator-name = "8226_s2_avs_limit";
+					regulator-min-microvolt = <900000>;
+					regulator-max-microvolt = <1275000>;
+				}
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index 9ee2cc6..6716785 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -176,6 +176,8 @@
  - qcom,hold-reset: Indicates that hold QUSB PHY into reset state.
  - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided.
  - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0
+ - pinctrl-names/pinctrl-0/1: The GPIOs configured as output function. Names represents "active"
+   state when attached in host mode and "suspend" state when detached.
 
 Example:
 	qusb_phy: qusb@f9b39000 {
diff --git a/arch/Kconfig b/arch/Kconfig
index babac73..a364ece 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -224,6 +224,14 @@
 	  An architecture should select this when it can successfully
 	  build and run with CONFIG_FORTIFY_SOURCE.
 
+config FORTIFY_COMPILE_CHECK
+	depends on ARCH_HAS_FORTIFY_SOURCE
+	bool
+	help
+	  Disable compile time size check for string routines as part
+	  of fortify source. Selecting this option will not enforce compile
+	  time size check for string functions.
+
 # Select if arch init_task initializer is different to init/init_task.c
 config ARCH_INIT_TASK
        bool
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
index d1d44ec..7819d26 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
@@ -59,7 +59,7 @@
 		bcm_ip0: bcm-ip0 {
 			cell-id = <MSM_BUS_BCM_IP0>;
 			label = "IP0";
-			qcom,bcm-name = "CE";
+			qcom,bcm-name = "IP0";
 			qcom,rscs = <&rsc_apps>;
 			qcom,bcm-dev;
 		};
@@ -240,8 +240,8 @@
 			label = "fab-system_noc";
 			qcom,fab-dev;
 			qcom,base-name = "system_noc-base";
-			qcom,qos-off = <0>;
-			qcom,base-offset = <0>;
+			qcom,qos-off = <4096>;
+			qcom,base-offset = <45056>;
 			qcom,bypass-qos-prg;
 			qcom,bus-type = <1>;
 			clocks = <>;
@@ -261,7 +261,7 @@
 		mas_llcc_mc: mas-llcc-mc {
 			cell-id = <MSM_BUS_MASTER_LLCC>;
 			label = "mas-llcc-mc";
-			qcom,buswidth = <16>;
+			qcom,buswidth = <4>;
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_ebi>;
 			qcom,bus-dev = <&fab_mc_virt>;
@@ -277,7 +277,7 @@
 			qcom,bus-dev = <&fab_mem_noc>;
 			qcom,bcms = <&bcm_sh1>;
 			qcom,ap-owned;
-			qcom,prio = <0>;
+			qcom,prio = <6>;
 		};
 
 		mas_qnm_snoc_gc: mas-qnm-snoc-gc {
@@ -290,6 +290,7 @@
 			qcom,bus-dev = <&fab_mem_noc>;
 			qcom,ap-owned;
 			qcom,prio = <0>;
+			qcom,forwarding;
 		};
 
 		mas_xm_apps_rdwr: mas-xm-apps-rdwr {
@@ -310,9 +311,12 @@
 			label = "mas-qhm-audio";
 			qcom,buswidth = <4>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <9>;
 			qcom,connections = <&slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_pn2>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_qhm_blsp1: mas-qhm-blsp1 {
@@ -320,9 +324,12 @@
 			label = "mas-qhm-blsp1";
 			qcom,buswidth = <4>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <10>;
 			qcom,connections = <&slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_pn3>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_qhm_qdss_bam: mas-qhm-qdss-bam {
@@ -330,20 +337,22 @@
 			label = "mas-qhm-qdss-bam";
 			qcom,buswidth = <4>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <11>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
-				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
-				 &slv_qhs_pdm &slv_qns_snoc_memnoc
-				 &slv_qhs_tcsr &slv_qhs_qpic
-				 &slv_qxs_imem &slv_qhs_ipa
-				 &slv_qhs_usb3_phy &slv_qhs_aop
-				 &slv_qhs_blsp1 &slv_qhs_sdc1
-				 &slv_qhs_pcie_parf &slv_qhs_audio
-				 &slv_qhs_tlmm &slv_qhs_prng
-				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
-				 &slv_qhs_usb3>;
+				&slv_qhs_pdm &slv_qhs_pcie_parf
+				 &slv_qhs_tlmm &slv_qhs_spmi_fetcher
+				 &slv_qhs_prng &slv_qhs_qpic
+				 &slv_qxs_imem &slv_qhs_snoc_cfg
+				 &slv_qhs_audio &slv_qhs_sdc1
+				 &slv_qhs_aoss &slv_qhs_ipa
+				 &slv_qns_snoc_memnoc &slv_qhs_usb3_phy
+				 &slv_qhs_aop &slv_qhs_tcsr
+				 &slv_qhs_blsp1 &slv_xs_sys_tcu_cfg
+				 &slv_qhs_usb3 &slv_qhs_clk_ctl>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn8>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_qhm_qpic: mas-qhm-qpic {
@@ -381,18 +390,17 @@
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
+				&slv_qhs_snoc_cfg &slv_qhs_sdc1
 				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
 				 &slv_qhs_pdm &slv_qns_snoc_memnoc
 				 &slv_qhs_tcsr &slv_xs_qdss_stm
 				 &slv_qhs_qpic &slv_qxs_imem
 				 &slv_qhs_ipa &slv_qhs_usb3_phy
 				 &slv_qhs_aop &slv_qhs_blsp1
-				 &slv_qhs_sdc1 &slv_qhs_pcie_parf
-				 &slv_qhs_audio &slv_qxs_pcie
-				 &slv_qhs_tlmm &slv_qhs_prng
-				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
-				 &slv_qhs_usb3>;
+				 &slv_qhs_pcie_parf &slv_qhs_audio
+				 &slv_qxs_pcie &slv_qhs_tlmm
+				 &slv_qhs_prng &slv_xs_sys_tcu_cfg
+				 &slv_qhs_clk_ctl &slv_qhs_usb3>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn7>;
 		};
@@ -403,17 +411,17 @@
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
+				&slv_qhs_snoc_cfg &slv_qhs_sdc1
 				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
 				 &slv_qhs_pdm &slv_qns_snoc_memnoc
 				 &slv_qhs_tcsr &slv_xs_qdss_stm
 				 &slv_qhs_qpic &slv_qxs_imem
 				 &slv_qhs_ipa &slv_qhs_usb3_phy
 				 &slv_qhs_aop &slv_qhs_blsp1
-				 &slv_qhs_sdc1 &slv_qhs_pcie_parf
-				 &slv_qhs_audio &slv_qhs_tlmm
-				 &slv_qhs_prng &slv_xs_sys_tcu_cfg
-				 &slv_qhs_clk_ctl &slv_qhs_usb3>;
+				 &slv_qhs_pcie_parf &slv_qhs_audio
+				 &slv_qhs_tlmm &slv_qhs_prng
+				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
+				 &slv_qhs_usb3>;
 			qcom,bus-dev = <&fab_system_noc>;
 		};
 
@@ -423,17 +431,16 @@
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
-				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
-				 &slv_qhs_pdm &slv_qhs_tcsr
-				 &slv_xs_qdss_stm &slv_qhs_qpic
-				 &slv_qxs_imem &slv_qhs_ipa
+				&slv_qhs_pdm &slv_qhs_pcie_parf
+				 &slv_qhs_tlmm &slv_qhs_spmi_fetcher
+				 &slv_qhs_prng &slv_qhs_qpic
+				 &slv_qxs_imem &slv_qhs_snoc_cfg
+				 &slv_qhs_audio &slv_qhs_sdc1
+				 &slv_qhs_aoss &slv_qhs_ipa
 				 &slv_qhs_usb3_phy &slv_qhs_aop
-				 &slv_qhs_blsp1 &slv_qhs_sdc1
-				 &slv_qhs_pcie_parf &slv_qhs_audio
-				 &slv_qhs_tlmm &slv_qhs_prng
-				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
-				 &slv_qhs_usb3>;
+				 &slv_qhs_tcsr &slv_qhs_blsp1
+				 &slv_xs_sys_tcu_cfg &slv_qhs_usb3
+				 &slv_xs_qdss_stm &slv_qhs_clk_ctl>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn9>;
 		};
@@ -443,9 +450,12 @@
 			label = "mas-qxm-crypto";
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <1>;
 			qcom,connections = <&slv_qhs_aoss &slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
-			qcom,bcms = <&bcm_ce>;
+			qcom,bcms = <&bcm_ce>, <&bcm_pn5>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_qxm_ipa: mas-qxm-ipa {
@@ -453,9 +463,25 @@
 			label = "mas-qxm-ipa";
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <5>;
 			qcom,connections = <&slv_qns_aggre_noc_ipa>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn11>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
+			qcom,forwarding;
+		};
+
+		mas_qxm_ipa2pcie_slv: mas-qxm-ipa2pcie-slv {
+			cell-id = <MSM_BUS_MASTER_IPA_PCIE>;
+			label = "mas-qxm-ipa2pcie-slv";
+			qcom,buswidth = <8>;
+			qcom,agg-ports = <1>;
+			qcom,qport = <6>;
+			qcom,connections = <&slv_qxs_pcie>;
+			qcom,bus-dev = <&fab_system_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		mas_xm_emac: mas-xm-emac {
@@ -463,8 +489,11 @@
 			label = "mas-xm-emac";
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <7>;
 			qcom,connections = <&slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_xm_pcie: mas-xm-pcie {
@@ -472,8 +501,12 @@
 			label = "mas-xm-pcie";
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <2>;
 			qcom,connections = <&slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
+			qcom,forwarding;
 		};
 
 		mas_xm_qdss_etr: mas-xm-qdss-etr {
@@ -481,20 +514,22 @@
 			label = "mas-xm-qdss-etr";
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <3>;
 			qcom,connections = <&slv_qhs_crypto_cfg
-				 &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
-				 &slv_qhs_aoss &slv_qhs_spmi_fetcher
-				 &slv_qhs_pdm &slv_qns_snoc_memnoc
-				 &slv_qhs_tcsr &slv_qhs_qpic
-				 &slv_qxs_imem &slv_qhs_ipa
-				 &slv_qhs_usb3_phy &slv_qhs_aop
-				 &slv_qhs_blsp1 &slv_qhs_sdc1
-				 &slv_qhs_pcie_parf &slv_qhs_audio
-				 &slv_qhs_tlmm &slv_qhs_prng
-				 &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
-				 &slv_qhs_usb3>;
+				&slv_qhs_pdm &slv_qhs_pcie_parf
+				 &slv_qhs_tlmm &slv_qhs_spmi_fetcher
+				 &slv_qhs_prng &slv_qhs_qpic
+				 &slv_qxs_imem &slv_qhs_snoc_cfg
+				 &slv_qhs_audio &slv_qhs_sdc1
+				 &slv_qhs_aoss &slv_qhs_ipa
+				 &slv_qns_snoc_memnoc &slv_qhs_usb3_phy
+				 &slv_qhs_aop &slv_qhs_tcsr
+				 &slv_qhs_blsp1 &slv_xs_sys_tcu_cfg
+				 &slv_qhs_usb3 &slv_qhs_clk_ctl>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_sn8>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_xm_sdc1: mas-xm-sdc1 {
@@ -502,9 +537,12 @@
 			label = "mas-xm-sdc1";
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <8>;
 			qcom,connections = <&slv_qhs_aoss &slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
 			qcom,bcms = <&bcm_pn1>;
+			qcom,ap-owned;
+			qcom,prio = <1>;
 		};
 
 		mas_xm_usb3: mas-xm-usb3 {
@@ -512,8 +550,11 @@
 			label = "mas-xm-usb3";
 			qcom,buswidth = <8>;
 			qcom,agg-ports = <1>;
+			qcom,qport = <4>;
 			qcom,connections = <&slv_qns_aggre_noc>;
 			qcom,bus-dev = <&fab_system_noc>;
+			qcom,ap-owned;
+			qcom,prio = <2>;
 		};
 
 		/*Internal nodes*/
@@ -532,7 +573,7 @@
 		slv_ebi:slv-ebi {
 			cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
 			label = "slv-ebi";
-			qcom,buswidth = <16>;
+			qcom,buswidth = <4>;
 			qcom,agg-ports = <1>;
 			qcom,bus-dev = <&fab_mc_virt>;
 			qcom,bcms = <&bcm_mc0>;
@@ -612,15 +653,6 @@
 			qcom,bcms = <&bcm_pn0>;
 		};
 
-		slv_qhs_emac_cfg:slv-qhs-emac-cfg {
-			cell-id = <MSM_BUS_SLAVE_EMAC_CFG>;
-			label = "slv-qhs-emac-cfg";
-			qcom,buswidth = <4>;
-			qcom,agg-ports = <1>;
-			qcom,bus-dev = <&fab_system_noc>;
-			qcom,bcms = <&bcm_pn0>;
-		};
-
 		slv_qhs_ipa:slv-qhs-ipa {
 			cell-id = <MSM_BUS_SLAVE_IPA_CFG>;
 			label = "slv-qhs-ipa";
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
index 15129c7..948a309 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
@@ -20,7 +20,7 @@
 	model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP";
 	compatible = "qcom,sdxpoorwills-cdp",
 		"qcom,sdxpoorwills", "qcom,cdp";
-	qcom,board-id = <1 0x0>, <1 0x100>;
+	qcom,board-id = <1 0x0>, <1 0x100>, <1 0x2>, <1 0x102>;
 };
 
 &blsp1_uart2 {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
index 8d7e377..0018a4f 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
@@ -20,7 +20,7 @@
 	model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP";
 	compatible = "qcom,sdxpoorwills-mtp",
 		"qcom,sdxpoorwills", "qcom,mtp";
-	qcom,board-id = <8 0x0>, <8 0x100>;
+	qcom,board-id = <8 0x0>, <8 0x100>, <8 0x2>, <8 0x102>;
 };
 
 &blsp1_uart2 {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
index aa9e7f2..227a120 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
@@ -61,6 +61,10 @@
 	compatible = "regulator-fixed";
 };
 
+&ipa_hw {
+	qcom,ipa-hw-mode = <1>; /* IPA hw type = Virtual */
+};
+
 &usb {
 	/delete-property/ qcom,usb-dbm;
 	qcom,charging-disabled;
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi
index f9ad6f4..fbfaa0d 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi
@@ -105,5 +105,28 @@
 		interrupt-controller;
 		#interrupt-cells = <2>;
 	};
+
+	/* ipa - outbound entry to mss */
+	smp2pgpio_ipa_1_out: qcom,smp2pgpio-ipa-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "ipa";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	/* ipa - inbound entry from mss */
+	smp2pgpio_ipa_1_in: qcom,smp2pgpio-ipa-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "ipa";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
 };
 
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
index be2b63e..def0e13 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
@@ -92,8 +92,10 @@
 	/* USB port for Super Speed PHY */
 	usb3_qmp_phy: ssphy@ff0000 {
 		compatible = "qcom,usb-ssphy-qmp-v2";
-		reg = <0xff0000 0x1000>;
-		reg-names = "qmp_phy_base";
+		reg = <0xff0000 0x1000>,
+		    <0x01fcb244 0x4>;
+		reg-names = "qmp_phy_base",
+			"vls_clamp_reg";
 
 		vdd-supply = <&pmxpoorwills_l4>;
 		core-supply = <&pmxpoorwills_l1>;
@@ -101,112 +103,108 @@
 		qcom,vbus-valid-override;
 		qcom,qmp-phy-init-seq =
 		/* <reg_offset, value, delay> */
-			<0x048 0x07 0x00 /* QSERDES_COM_PLL_IVCO */
-			 0x080 0x14 0x00 /* QSERDES_COM_SYSCLK_EN_SEL */
-			 0x034 0x04 0x00 /* QSERDES_COM_BIAS_EN_CLKBUFLR_EN */
-			 0x138 0x30 0x00 /* QSERDES_COM_CLK_SELECT */
-			 0x03c 0x02 0x00 /* QSERDES_COM_SYS_CLK_CTRL */
-			 0x08c 0x08 0x00 /* QSERDES_COM_RESETSM_CNTRL2 */
-			 0x15c 0x06 0x00 /* QSERDES_COM_CMN_CONFIG */
-			 0x164 0x01 0x00 /* QSERDES_COM_SVS_MODE_CLK_SEL */
-			 0x13c 0x80 0x00 /* QSERDES_COM_HSCLK_SEL */
-			 0x0b0 0x82 0x00 /* QSERDES_COM_DEC_START_MODE0 */
-			 0x0b8 0xab 0x00 /* QSERDES_COM_DIV_FRAC_START1_MODE0 */
-			 0x0bc 0xea 0x00 /* QSERDES_COM_DIV_FRAC_START2_MODE0 */
-			 0x0c0 0x02 0x00 /* QSERDES_COM_DIV_FRAC_START3_MODE0 */
-			 0x060 0x06 0x00 /* QSERDES_COM_CP_CTRL_MODE0 */
-			 0x068 0x16 0x00 /* QSERDES_COM_PLL_RCTRL_MODE0 */
-			 0x070 0x36 0x00 /* QSERDES_COM_PLL_CCTRL_MODE0 */
-			 0x0dc 0x00 0x00 /* QSERDES_COM_INTEGLOOP_GAIN1_MODE0 */
-			 0x0d8 0x3f 0x00 /* QSERDES_COM_INTEGLOOP_GAIN0_MODE0 */
-			 0x0f8 0x01 0x00 /* QSERDES_COM_VCO_TUNE2_MODE0 */
-			 0x0f4 0xc9 0x00 /* QSERDES_COM_VCO_TUNE1_MODE0 */
-			 0x148 0x0a 0x00 /* QSERDES_COM_CORECLK_DIV_MODE0 */
-			 0x0a0 0x00 0x00 /* QSERDES_COM_LOCK_CMP3_MODE0 */
-			 0x09c 0x34 0x00 /* QSERDES_COM_LOCK_CMP2_MODE0 */
-			 0x098 0x15 0x00 /* QSERDES_COM_LOCK_CMP1_MODE0 */
-			 0x090 0x04 0x00 /* QSERDES_COM_LOCK_CMP_EN */
-			 0x154 0x00 0x00 /* QSERDES_COM_CORE_CLK_EN */
-			 0x094 0x00 0x00 /* QSERDES_COM_LOCK_CMP_CFG */
-			 0x0f0 0x00 0x00 /* QSERDES_COM_VCO_TUNE_MAP */
-			 0x040 0x0a 0x00 /* QSERDES_COM_SYSCLK_BUF_ENABLE */
-			 0x0d0 0x80 0x00 /* QSERDES_COM_INTEGLOOP_INITVAL */
+			<0x058 0x07 0x00 /* QSERDES_COM_PLL_IVCO */
+			 0x094 0x1a 0x00 /* QSERDES_COM_SYSCLK_EN_SEL */
+			 0x044 0x14 0x00 /* QSERDES_COM_BIAS_EN_CLKBUFLR_EN */
+			 0x154 0x31 0x00 /* QSERDES_COM_CLK_SELECT */
+			 0x04c 0x02 0x00 /* QSERDES_COM_SYS_CLK_CTRL */
+			 0x0a0 0x08 0x00 /* QSERDES_COM_RESETSM_CNTRL2 */
+			 0x17c 0x06 0x00 /* QSERDES_COM_CMN_CONFIG */
+			 0x184 0x05 0x00 /* QSERDES_COM_SVS_MODE_CLK_SEL */
+			 0x1bc 0x11 0x00 /* QSERDES_COM_BIN_VCOCAL_HSCLK_SEL*/
+			 0x158 0x01 0x00 /* QSERDES_COM_HSCLK_SEL */
+			 0x0bc 0x82 0x00 /* QSERDES_COM_DEC_START_MODE0 */
+			 0x0cc 0xab 0x00 /* QSERDES_COM_DIV_FRAC_START1_MODE0 */
+			 0x0d0 0xea 0x00 /* QSERDES_COM_DIV_FRAC_START2_MODE0 */
+			 0x0d4 0x02 0x00 /* COM_DIV_FRAC_START3_MODE0 */
+			 0x1ac 0xca 0x00 /* COM_BIN_VCOCAL_CMP_CODE1_MODE0 */
+			 0x1b0 0x1e 0x00 /* COM_BIN_VCOCAL_CMP_CODE2_MODE0 */
+			 0x074 0x06 0x00 /* QSERDES_COM_CP_CTRL_MODE0 */
+			 0x07c 0x16 0x00 /* QSERDES_COM_PLL_RCTRL_MODE0 */
+			 0x084 0x36 0x00 /* QSERDES_COM_PLL_CCTRL_MODE0 */
+			 0x0f0 0x00 0x00 /* QSERDES_COM_INTEGLOOP_GAIN1_MODE0 */
+			 0x0ec 0x3f 0x00 /* QSERDES_COM_INTEGLOOP_GAIN0_MODE0 */
+			 0x114 0x02 0x00 /* QSERDES_COM_VCO_TUNE2_MODE0 */
+			 0x110 0x24 0x00 /* QSERDES_COM_VCO_TUNE1_MODE0 */
+			 0x168 0x0a 0x00 /* QSERDES_COM_CORECLK_DIV_MODE0 */
+			 0x0b0 0x34 0x00 /* QSERDES_COM_LOCK_CMP2_MODE0 */
+			 0x0ac 0x14 0x00 /* QSERDES_COM_LOCK_CMP1_MODE0 */
+			 0x0a4 0x04 0x00 /* QSERDES_COM_LOCK_CMP_EN */
+			 0x174 0x00 0x00 /* QSERDES_COM_CORE_CLK_EN */
+			 0x0a8 0x00 0x00 /* QSERDES_COM_LOCK_CMP_CFG */
+			 0x10c 0x00 0x00 /* QSERDES_COM_VCO_TUNE_MAP */
+			 0x050 0x0a 0x00 /* QSERDES_COM_SYSCLK_BUF_ENABLE */
+			 0x00c 0x0a 0x00 /* QSERDES_COM_BG_TIMER */
 			 0x010 0x01 0x00 /* QSERDES_COM_SSC_EN_CENTER */
 			 0x01c 0x31 0x00 /* QSERDES_COM_SSC_PER1 */
 			 0x020 0x01 0x00 /* QSERDES_COM_SSC_PER2 */
 			 0x014 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER1 */
 			 0x018 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER2 */
-			 0x024 0x85 0x00 /* QSERDES_COM_SSC_STEP_SIZE1 */
-			 0x028 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE2 */
-			 0x4c0 0x0c 0x00 /* QSERDES_RX_VGA_CAL_CNTRL2 */
-			 0x564 0x50 0x00 /* QSERDES_RX_RX_MODE_00 */
-			 0x430 0x0b 0x00 /* QSERDES_RX_UCDR_FASTLOCK_FO_GAIN */
-			 0x4d4 0x0e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 */
-			 0x4d8 0x4e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 */
-			 0x4dc 0x18 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 */
-			 0x4f8 0x77 0x00 /* RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */
-			 0x4fc 0x80 0x00 /* RX_RX_OFFSET_ADAPTOR_CNTRL2 */
-			 0x504 0x03 0x00 /* QSERDES_RX_SIGDET_CNTRL */
-			 0x50c 0x1c 0x00 /* QSERDES_RX_SIGDET_DEGLITCH_CNTRL */
-			 0x434 0x75 0x00 /* RX_UCDR_SO_SATURATION_AND_ENABLE */
-			 0x444 0x80 0x00 /* QSERDES_RX_UCDR_PI_CONTROLS */
+			 0x030 0xde 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE1 */
+			 0x034 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE2_MODE1 */
+			 0x024 0xde 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE0 */
+			 0x028 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE0 */
+			 0x4a4 0x3f 0x00 /* QSERDES_RX_RX_IDAC_ENABLES */
+			 0x594 0xbf 0x00 /* QSERDES_RX_RX_MODE_01_HIGH4 */
+			 0x590 0x09 0x00 /* QSERDES_RX_RX_MODE_01_HIGH3 */
+			 0x58c 0xc8 0x00 /* QSERDES_RX_RX_MODE_01_HIGH2 */
+			 0x588 0xc8 0x00 /* QSERDES_RX_RX_MODE_01_HIGH */
+			 0x584 0xe0 0x00 /* QSERDES_RX_RX_MODE_01_LOW */
+			 0x444 0x01 0x00 /* QSERDES_RX_UCDR_PI_CONTROLS */
 			 0x408 0x0a 0x00 /* QSERDES_RX_UCDR_FO_GAIN */
-			 0x40c 0x06 0x00 /* QSERDES_RX_UCDR_SO_GAIN */
-			 0x500 0x00 0x00 /* QSERDES_RX_SIGDET_ENABLES */
-			 0x260 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */
-			 0x2a4 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */
-			 0x28c 0xc6 0x00 /* QSERDES_TX_LANE_MODE_1 */
-			 0x248 0x09 0x00 /* TX_RES_CODE_LANE_OFFSET_RX */
-			 0x244 0x0d 0x00 /* TX_RES_CODE_LANE_OFFSET_TX */
-			 0x8c8 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */
-			 0x8cc 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */
-			 0x8d0 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */
-			 0x8d4 0x40 0x00 /* USB3_UNI_PCS_FLL_MAN_CODE */
-			 0x8c4 0x02 0x00 /* USB3_UNI_PCS_FLL_CNTRL1 */
-			 0x864 0x1b 0x00 /* USB3_UNI_PCS_POWER_STATE_CONFIG2 */
-			 0x80c 0x9f 0x00 /* USB3_UNI_PCS_TXMGN_V0 */
-			 0x810 0x9f 0x00 /* USB3_UNI_PCS_TXMGN_V1 */
-			 0x814 0xb5 0x00 /* USB3_UNI_PCS_TXMGN_V2 */
-			 0x818 0x4c 0x00 /* USB3_UNI_PCS_TXMGN_V3 */
-			 0x81c 0x64 0x00 /* USB3_UNI_PCS_TXMGN_V4 */
-			 0x820 0x6a 0x00 /* USB3_UNI_PCS_TXMGN_LS */
-			 0x824 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V0 */
-			 0x828 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V0 */
-			 0x82c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V1 */
-			 0x830 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V1 */
-			 0x834 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V2 */
-			 0x838 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V2 */
-			 0x83c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V3 */
-			 0x840 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V3 */
-			 0x844 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V4 */
-			 0x848 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V4 */
-			 0x84c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_LS */
-			 0x850 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_LS */
-			 0x85c 0x02 0x00 /* USB3_UNI_PCS_RATE_SLEW_CNTRL */
-			 0x8a0 0x04 0x00 /* PCS_PWRUP_RESET_DLY_TIME_AUXCLK */
-			 0x88c 0x44 0x00 /* USB3_UNI_PCS_TSYNC_RSYNC_TIME */
-			 0x880 0xd1 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG1 */
-			 0x884 0x1f 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG2 */
-			 0x888 0x47 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG3 */
-			 0x870 0xe7 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_L */
-			 0x874 0x03 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_H */
-			 0x878 0x40 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_U3_L */
-			 0x87c 0x00 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_U3_H */
-			 0x9d8 0xba 0x00 /* USB3_UNI_PCS_RX_SIGDET_LVL */
-			 0x8b8 0x75 0x00 /* RXEQTRAINING_WAIT_TIME */
-			 0x8b0 0x86 0x00 /* PCS_LFPS_TX_ECSTART_EQTLOCK */
-			 0x8bc 0x13 0x00 /* PCS_RXEQTRAINING_RUN_TIME */
-			 0xa0c 0x21 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG1 */
-			 0xa10 0x60 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG2 */
+			 0x414 0x06 0x00 /* QSERDES_RX_UCDR_SO_GAIN */
+			 0x430 0x2f 0x00 /* QSERDES_RX_UCDR_FASTLOCK_FO_GAIN */
+			 0x43c 0xff 0x00 /* RX_UCDR_FASTLOCK_COUNT_LOW */
+			 0x440 0x0f 0x00 /* RX_UCDR_FASTLOCK_COUNT_HIGH */
+			 0x420 0x0a 0x00 /* QSERDES_RX_UCDR_SVS_FO_GAIN */
+			 0x42c 0x06 0x00 /* QSERDES_RX_UCDR_SVS_SO_GAIN */
+			 0x434 0x7f 0x00 /* RX_UCDR_SO_SATURATION_AND_ENABLE */
+			 0x4d8 0x0c 0x00 /* QSERDES_RX_VGA_CAL_CNTRL2 */
+			 0x4ec 0x0e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 */
+			 0x4f0 0x4e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 */
+			 0x4f4 0x18 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 */
+			 0x5b4 0x04 0x00 /* QSERDES_RX_DFE_EN_TIMER */
+			 0x510 0x77 0x00 /* RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */
+			 0x514 0x80 0x00 /* RX_RX_OFFSET_ADAPTOR_CNTRL2 */
+			 0x51c 0x04 0x00 /* QSERDES_RX_SIGDET_CNTRL */
+			 0x524 0x1a 0x00 /* QSERDES_RX_SIGDET_DEGLITCH_CNTRL */
+			 0x4fc 0x00 0x00 /* QSERDES_RX_RX_IDAC_TSETTLE_HIGH */
+			 0x4f8 0xc0 0x00 /* QSERDES_RX_RX_IDAC_TSETTLE_LOW */
+			 0x258 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */
+			 0x29c 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */
+			 0x284 0x05 0x00 /* QSERDES_TX_LANE_MODE_1 */
+			 0x288 0x02 0x00 /* QSERDES_TX_LANE_MODE_2 */
+			 0x28c 0x00 0x00 /* QSERDES_TX_LANE_MODE_3*/
+			 0x89c 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */
+			 0x8a0 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */
+			 0x8a4 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */
+			 0x8a8 0x40 0x00 /* USB3_UNI_PCS_FLL_MAN_CODE */
+			 0x898 0x02 0x00 /* USB3_UNI_PCS_FLL_CNTRL1 */
+			 0x8c4 0xd0 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG1 */
+			 0x8c8 0x17 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG2 */
+			 0x8cc 0x20 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG3 */
+			 0x890 0x4f 0x00 /* USB3_UNI_PCS_POWER_STATE_CONFIG1 */
+			 0x990 0xe7 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_L */
+			 0x994 0x03 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_H */
+			 0x988 0xba 0x00 /* USB3_UNI_PCS_RX_SIGDET_LVL */
+			 0xe2c 0x75 0x00 /* USB3_RXEQTRAINING_WAIT_TIME */
+			 0xe38 0x07 0x00 /* USB3_RXEQTRAINING_DFE_TIME_S2 */
+			 0xe18 0x64 0x00 /* USB3_LFPS_DET_HIGH_COUNT_VAL */
+			 0x9c0 0x88 0x00 /* USB3_UNI_PCS_ALIGN_DETECT_CONFIG1 */
+			 0x9c4 0x13 0x00 /* USB3_UNI_PCS_ALIGN_DETECT_CONFIG2 */
+			 0x9dc 0x0d 0x00 /* USB3_UNI_PCS_EQ_CONFIG1 */
+			 0x9e0 0x0d 0x00 /* USB3_UNI_PCS_EQ_CONFIG2 */
+			 0x8dc 0x21 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG1 */
+			 0x8e0 0x60 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG2 */
 			 0xffffffff 0xffffffff 0x00>;
 
 		qcom,qmp-phy-reg-offset =
-				<0x974 /* USB3_UNI_PCS_PCS_STATUS */
-				 0x8d8 /* USB3_UNI_PCS_AUTONOMOUS_MODE_CTRL */
-				 0x8dc /* USB3_UNI_PCS_LFPS_RXTERM_IRQ_CLEAR */
-				 0x804 /* USB3_UNI_PCS_POWER_DOWN_CONTROL */
+				<0x814 /* USB3_UNI_PCS_PCS_STATUS */
+				 0xe08 /* USB3_UNI_PCS_AUTONOMOUS_MODE_CTRL */
+				 0xe14 /* USB3_UNI_PCS_LFPS_RXTERM_IRQ_CLEAR */
+				 0x840 /* USB3_UNI_PCS_POWER_DOWN_CONTROL */
 				 0x800 /* USB3_UNI_PCS_SW_RESET */
-				 0x808>; /* USB3_UNI_PCS_START_CONTROL */
+				 0x844>; /* USB3_UNI_PCS_START_CONTROL */
 
 		clocks = <&clock_gcc GCC_USB3_PHY_AUX_CLK>,
 			 <&clock_gcc GCC_USB3_PHY_PIPE_CLK>,
@@ -215,5 +213,8 @@
 
 		clock-names = "aux_clk", "pipe_clk", "ref_clk_src",
 				"cfg_ahb_clk";
+		resets = <&clock_gcc GCC_USB3_PHY_BCR>,
+		       <&clock_gcc GCC_USB3PHY_PHY_BCR>;
+		reset-names = "phy_reset", "phy_phy_reset";
 	};
 };
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 3d2dc66..5fca795 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -206,6 +206,16 @@
 		mbox-names = "apps";
 	};
 
+	snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive {
+		compatible = "qcom,devbw";
+		governor = "powersave";
+		qcom,src-dst-ports = <53 747>;
+		qcom,active-only;
+		status = "ok";
+		qcom,bw-tbl =
+			< 1 >;
+	};
+
 	blsp1_uart2: serial@831000 {
 		compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
 		reg = <0x831000 0x200>;
@@ -484,11 +494,177 @@
 		reg = <0xc37000c 8>;
 	};
 
+	qcom,msm_gsi {
+		compatible = "qcom,msm_gsi";
+	};
+
+	qcom,rmnet-ipa {
+		compatible = "qcom,rmnet-ipa3";
+		qcom,rmnet-ipa-ssr;
+		qcom,ipa-loaduC;
+		qcom,ipa-advertise-sg-support;
+	};
+
 	system_pm {
 		compatible = "qcom,system-pm";
 		mboxes = <&apps_rsc 0>;
 	};
 
+	ipa_hw: qcom,ipa@01e00000 {
+		compatible = "qcom,ipa";
+		reg = <0x1e00000 0x34000>,
+		      <0x1e04000 0x28000>;
+		reg-names = "ipa-base", "gsi-base";
+		interrupts =
+			<0 241 0>,
+			<0 47 0>;
+		interrupt-names = "ipa-irq", "gsi-irq";
+		qcom,ipa-hw-ver = <14>; /* IPA core version = IPAv4.0 */
+		qcom,ipa-hw-mode = <0>;
+		qcom,ee = <0>;
+		qcom,use-ipa-tethering-bridge;
+		qcom,modem-cfg-emb-pipe-flt;
+		qcom,use-ipa-pm;
+		qcom,bandwidth-vote-for-ipa;
+		qcom,msm-bus,name = "ipa";
+		qcom,msm-bus,num-cases = <5>;
+		qcom,msm-bus,num-paths = <4>;
+		qcom,msm-bus,vectors-KBps =
+		/* No vote */
+			<90 512 0 0>,
+			<90 585 0 0>,
+			<1 676 0 0>,
+			<143 777 0 0>,
+		/* SVS2 */
+			<90 512 3616000 7232000>,
+			<90 585 300000 600000>,
+			<1 676 90000 180000>, /*gcc_config_noc_clk_src */
+			<143 777 0 120>, /* IB defined for IPA2X_clk in MHz*/
+		/* SVS */
+			<90 512 6640000 13280000>,
+			<90 585 400000 800000>,
+			<1 676 100000 200000>,
+			<143 777 0 250>, /* IB defined for IPA2X_clk in MHz*/
+		/* NOMINAL */
+			<90 512 10400000 20800000>,
+			<90 585 800000 1600000>,
+			<1 676 200000 400000>,
+			<143 777 0 440>, /* IB defined for IPA2X_clk in MHz*/
+		/* TURBO */
+			<90 512 10400000 20800000>,
+			<90 585 960000 1920000>,
+			<1 676 266000 532000>,
+			<143 777 0 500>; /* IB defined for IPA clk in MHz*/
+		qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL",
+		"TURBO";
+		qcom,throughput-threshold = <310 600 1000>;
+		qcom,scaling-exceptions = <>;
+
+
+		/* IPA RAM mmap */
+		qcom,ipa-ram-mmap = <
+			0x280	/* ofst_start; */
+			0x0	/* nat_ofst; */
+			0x0	/* nat_size; */
+			0x288	/* v4_flt_hash_ofst; */
+			0x78	/* v4_flt_hash_size; */
+			0x4000	/* v4_flt_hash_size_ddr; */
+			0x308	/* v4_flt_nhash_ofst; */
+			0x78	/* v4_flt_nhash_size; */
+			0x4000	/* v4_flt_nhash_size_ddr; */
+			0x388	/* v6_flt_hash_ofst; */
+			0x78	/* v6_flt_hash_size; */
+			0x4000	/* v6_flt_hash_size_ddr; */
+			0x408	/* v6_flt_nhash_ofst; */
+			0x78	/* v6_flt_nhash_size; */
+			0x4000	/* v6_flt_nhash_size_ddr; */
+			0xf	/* v4_rt_num_index; */
+			0x0	/* v4_modem_rt_index_lo; */
+			0x7	/* v4_modem_rt_index_hi; */
+			0x8	/* v4_apps_rt_index_lo; */
+			0xe	/* v4_apps_rt_index_hi; */
+			0x488	/* v4_rt_hash_ofst; */
+			0x78	/* v4_rt_hash_size; */
+			0x4000	/* v4_rt_hash_size_ddr; */
+			0x508	/* v4_rt_nhash_ofst; */
+			0x78	/* v4_rt_nhash_size; */
+			0x4000	/* v4_rt_nhash_size_ddr; */
+			0xf	/* v6_rt_num_index; */
+			0x0	/* v6_modem_rt_index_lo; */
+			0x7	/* v6_modem_rt_index_hi; */
+			0x8	/* v6_apps_rt_index_lo; */
+			0xe	/* v6_apps_rt_index_hi; */
+			0x588	/* v6_rt_hash_ofst; */
+			0x78	/* v6_rt_hash_size; */
+			0x4000	/* v6_rt_hash_size_ddr; */
+			0x608	/* v6_rt_nhash_ofst; */
+			0x78	/* v6_rt_nhash_size; */
+			0x4000	/* v6_rt_nhash_size_ddr; */
+			0x688	/* modem_hdr_ofst; */
+			0x140	/* modem_hdr_size; */
+			0x7c8	/* apps_hdr_ofst; */
+			0x0	/* apps_hdr_size; */
+			0x800	/* apps_hdr_size_ddr; */
+			0x7d0	/* modem_hdr_proc_ctx_ofst; */
+			0x200	/* modem_hdr_proc_ctx_size; */
+			0x9d0	/* apps_hdr_proc_ctx_ofst; */
+			0x200	/* apps_hdr_proc_ctx_size; */
+			0x0	/* apps_hdr_proc_ctx_size_ddr; */
+			0x0	/* modem_comp_decomp_ofst; diff */
+			0x0	/* modem_comp_decomp_size; diff */
+			0x13f0	/* modem_ofst; */
+			0x100c	/* modem_size; */
+			0x23fc	/* apps_v4_flt_hash_ofst; */
+			0x0	/* apps_v4_flt_hash_size; */
+			0x23fc	/* apps_v4_flt_nhash_ofst; */
+			0x0	/* apps_v4_flt_nhash_size; */
+			0x23fc	/* apps_v6_flt_hash_ofst; */
+			0x0	/* apps_v6_flt_hash_size; */
+			0x23fc	/* apps_v6_flt_nhash_ofst; */
+			0x0	/* apps_v6_flt_nhash_size; */
+			0x80	/* uc_info_ofst; */
+			0x200	/* uc_info_size; */
+			0x2800	/* end_ofst; */
+			0x23fc	/* apps_v4_rt_hash_ofst; */
+			0x0	/* apps_v4_rt_hash_size; */
+			0x23fc	/* apps_v4_rt_nhash_ofst; */
+			0x0	/* apps_v4_rt_nhash_size; */
+			0x23fc	/* apps_v6_rt_hash_ofst; */
+			0x0	/* apps_v6_rt_hash_size; */
+			0x23fc	/* apps_v6_rt_nhash_ofst; */
+			0x0	/* apps_v6_rt_nhash_size; */
+			0x2400	/* uc_event_ring_ofst; */
+			0x400	/* uc_event_ring_size;*/
+			0xbd8	/* pdn_config_ofst; */
+			0x50	/* pdn_config_size; */
+			0xc30  /* stats_quota_ofst */
+			0x60   /* stats_quota_size */
+			0xc90  /* stats_tethering_ofst */
+			0x140  /* stats_tethering_size */
+			0xdd0  /* stats_flt_v4_ofst */
+			0x180  /* stats_flt_v4_size */
+			0xf50  /* stats_flt_v6_ofst */
+			0x180  /* stats_flt_v6_size */
+			0x10d0 /* stats_rt_v4_ofst */
+			0x180  /* stats_rt_v4_size */
+			0x1250 /* stats_rt_v6_ofst */
+			0x180  /* stats_rt_v6_size */
+			0x13d0 /* stats_drop_ofst */
+			0x20  /* stats_drop_size */
+		>;
+
+		/* smp2p gpio information */
+		qcom,smp2pgpio_map_ipa_1_out {
+			compatible = "qcom,smp2pgpio-map-ipa-1-out";
+			gpios = <&smp2pgpio_ipa_1_out 0 0>;
+		};
+
+		qcom,smp2pgpio_map_ipa_1_in {
+			compatible = "qcom,smp2pgpio-map-ipa-1-in";
+			gpios = <&smp2pgpio_ipa_1_in 0 0>;
+		};
+	};
+
 	emac_hw: qcom,emac@00020000 {
 		compatible = "qcom,emac-dwc-eqos";
 		reg = <0x20000 0x10000>,
@@ -518,7 +694,7 @@
 		reg = <0xc300000 0x400>,
 			<0x17811008 0x4>;
 		reg-names = "msgram", "irq-reg-base";
-		qcom,irq-mask = <0x1>;
+		qcom,irq-mask = <0x2>;
 		interrupts = <GIC_SPI 221 IRQ_TYPE_EDGE_RISING>;
 		priority = <0>;
 		mbox-desc-offset = <0x0>;
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 067878b..944fe67 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -25,6 +25,7 @@
 # CONFIG_PID_NS is not set
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_XZ is not set
 # CONFIG_RD_LZO is not set
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 46f3e0c..c744f9e 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -29,6 +29,7 @@
 # CONFIG_PID_NS is not set
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_XZ is not set
 # CONFIG_RD_LZO is not set
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 8edfbf2..6531949 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -144,6 +144,7 @@
 	depends on ARCH_QCOM
 	select COMMON_CLK_QCOM
 	select QCOM_GDSC
+	select CPU_FREQ_QCOM
 	help
 	  This enables support for the MSM8953 chipset. If you do not
 	  wish to build a kernel that runs on this chipset, say 'N' here.
@@ -153,6 +154,7 @@
 	depends on ARCH_QCOM
 	select COMMON_CLK_QCOM
 	select QCOM_GDSC
+	select CPU_FREQ_QCOM
 	help
 	  This enables support for the sdm450 chipset. If you do not
 	  wish to build a kernel that runs on this chipset, say 'N' here.
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 3df7439..5a7e17e 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -126,7 +126,8 @@
 		sda670-pm660a-mtp-overlay.dtbo \
 		qcs605-cdp-overlay.dtbo \
 		qcs605-mtp-overlay.dtbo \
-		qcs605-external-codec-mtp-overlay.dtbo
+		qcs605-external-codec-mtp-overlay.dtbo \
+		qcs605-lc-mtp-overlay.dtbo
 
 sdm670-cdp-overlay.dtbo-base := sdm670.dtb
 sdm670-mtp-overlay.dtbo-base := sdm670.dtb
@@ -154,6 +155,7 @@
 qcs605-cdp-overlay.dtbo-base := qcs605.dtb
 qcs605-mtp-overlay.dtbo-base := qcs605.dtb
 qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb
+qcs605-lc-mtp-overlay.dtbo-base := qcs605.dtb
 
 else
 dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
@@ -182,7 +184,8 @@
 	qcs605-360camera.dtb \
 	qcs605-mtp.dtb \
 	qcs605-cdp.dtb \
-	qcs605-external-codec-mtp.dtb
+	qcs605-external-codec-mtp.dtb \
+	qcs605-lc-mtp.dtb
 endif
 
 ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
diff --git a/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi b/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi
new file mode 100644
index 0000000..3eed42a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+qcom,ascent-3450mah {
+	/* #Ascent_860_82209_0000_3450mAh_averaged_MasterSlave_Sept28th2015*/
+	qcom,max-voltage-uv = <4350000>;
+	qcom,nom-batt-capacity-mah = <3450>;
+	qcom,batt-id-kohm = <60>;
+	qcom,battery-beta = <3435>;
+	qcom,battery-type = "ascent_3450mah";
+	qcom,chg-rslow-comp-c1 = <6834679>;
+	qcom,chg-rslow-comp-c2 = <20647220>;
+	qcom,chg-rs-to-rslow = <915002>;
+	qcom,chg-rslow-comp-thr = <0xD5>;
+	qcom,checksum = <0xE50C>;
+	qcom,fg-profile-data = [
+		 C5 83 25 77
+		 AB 7B CA 74
+		 4C 83 7F 5B
+		 EB 80 ED 8C
+		 EA 81 61 9B
+		 A6 BE 2B D0
+		 55 0E D6 83
+		 09 77 25 7B
+		 03 74 49 83
+		 CC 70 0C 70
+		 0C 85 67 82
+		 E6 93 27 B5
+		 61 C0 58 10
+		 23 0D 50 59
+		 CE 6E 71 FD
+		 CD 15 CC 3F
+		 1D 36 00 00
+		 B9 47 29 3B
+		 1D 2E 00 00
+		 00 00 00 00
+		 00 00 00 00
+		 D8 6A E7 69
+		 B3 7C 4E 7A
+		 7E 77 77 70
+		 40 77 0D 73
+		 22 76 96 6A
+		 71 65 20 B0
+		 2C 97 63 12
+		 64 A0 71 0C
+		 28 00 FF 36
+		 F0 11 30 03
+		 00 00 00 0C
+	];
+};
diff --git a/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi b/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi
new file mode 100644
index 0000000..24b4626
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi
@@ -0,0 +1,61 @@
+/* Copyright (c) 2014-2015, 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.
+ */
+
+qcom,itech-3000mah {
+	/* #Itech_B00826LF_3000mAh_Feb24th_Averaged*/
+	qcom,max-voltage-uv = <4350000>;
+	qcom,v-cutoff-uv = <3400000>;
+	qcom,chg-term-ua = <100000>;
+	qcom,batt-id-kohm = <100>;
+	qcom,battery-type = "itech_3000mah";
+	qcom,chg-rslow-comp-c1 = <4365000>;
+	qcom,chg-rslow-comp-c2 = <8609000>;
+	qcom,chg-rslow-comp-thr = <0xBE>;
+	qcom,chg-rs-to-rslow = <761000>;
+	qcom,fastchg-current-ma = <2000>;
+	qcom,fg-cc-cv-threshold-mv = <4340>;
+	qcom,checksum = <0x0B7C>;
+	qcom,fg-profile-data = [
+		F0 83 6B 7D
+		66 81 EC 77
+		43 83 E3 5A
+		7C 81 33 8D
+		E1 81 EC 98
+		7B B5 F8 BB
+		5B 12 E2 83
+		4A 7C 63 80
+		CF 75 50 83
+		FD 5A 83 82
+		E6 8E 12 82
+		B6 9A 1A BE
+		BE CB 55 0E
+		96 0B E0 5A
+		CE 6E 71 FD
+		2A 31 7E 47
+		CF 40 00 00
+		DB 45 0F 32
+		AF 31 00 00
+		00 00 00 00
+		00 00 00 00
+		E3 6A 60 69
+		9E 6D 47 83
+		13 7C 23 70
+		0B 74 8F 80
+		DB 75 17 68
+		BA 75 BF B3
+		21 5B 69 B5
+		6C A0 71 0C
+		28 00 FF 36
+		F0 11 30 03
+		00 00 00 0E
+	];
+};
diff --git a/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi b/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi
new file mode 100644
index 0000000..da52039
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi
@@ -0,0 +1,62 @@
+/* Copyright (c) 2015-2016, 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.
+ */
+
+qcom,qrd_msm8937_sku1_2920mah {
+	/* #QRD8937_2800mAh_China_data_averaged_MasterSlave_Oct30th2015*/
+	qcom,max-voltage-uv = <4400000>;
+	qcom,nom-batt-capacity-mah = <2800>;
+	qcom,batt-id-kohm = <90>;
+	qcom,battery-beta = <3380>;
+	qcom,battery-type = "qrd_msm8937_sku1_2800mah";
+	qcom,fastchg-current-ma = <2600>;
+	qcom,fg-cc-cv-threshold-mv = <4390>;
+	qcom,chg-rslow-comp-c1 = <6733839>;
+	qcom,chg-rslow-comp-c2 = <23336040>;
+	qcom,chg-rs-to-rslow = <1049243>;
+	qcom,chg-rslow-comp-thr = <0xDB>;
+	qcom,checksum = <0x7E2A>;
+	qcom,gui-version = "PMI8950GUI - 2.0.0.14";
+	qcom,fg-profile-data = [
+		C6 83 8A 77
+		3E 80 84 75
+		72 83 A1 7C
+		A0 90 FC 97
+		3F 82 09 99
+		92 B7 97 C3
+		4C 14 EB 83
+		A7 7C CE 80
+		79 76 60 83
+		3B 64 34 88
+		19 94 49 82
+		07 9A 7F BD
+		BF CA 53 0D
+		32 0B 68 59
+		14 70 71 FD
+		8C 28 9C 45
+		3F 21 00 00
+		B6 47 FE 30
+		0B 40 00 00
+		00 00 00 00
+		00 00 00 00
+		3A 70 78 6B
+		F7 77 7F 88
+		32 7C F2 70
+		64 75 0B 79
+		2B 77 F3 6B
+		CA 70 7D B1
+		21 57 6B 6B
+		6D A0 71 0C
+		28 00 FF 36
+		F0 11 30 03
+		00 00 00 0C
+	];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
index 1b78fdd..8d80a40 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
@@ -58,6 +58,7 @@
 			reg = <0x0>;
 			enable-method = "psci";
 			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
 			next-level-cache = <&L2_0>;
 			L2_0: l2-cache {
 			      compatible = "arm,arch-cache";
@@ -81,6 +82,7 @@
 			enable-method = "psci";
 			reg = <0x1>;
 			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
 			next-level-cache = <&L2_0>;
 			L1_I_1: l1-icache {
 			      compatible = "arm,arch-cache";
@@ -98,6 +100,7 @@
 			enable-method = "psci";
 			reg = <0x2>;
 			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
 			next-level-cache = <&L2_0>;
 			L1_I_2: l1-icache {
 			      compatible = "arm,arch-cache";
@@ -115,6 +118,7 @@
 			enable-method = "psci";
 			reg = <0x3>;
 			efficiency = <1024>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
 			next-level-cache = <&L2_0>;
 			L1_I_3: l1-icache {
 			      compatible = "arm,arch-cache";
@@ -132,6 +136,7 @@
 			enable-method = "psci";
 			reg = <0x100>;
 			efficiency = <1126>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
 			next-level-cache = <&L2_1>;
 			L2_1: l2-cache {
 			      compatible = "arm,arch-cache";
@@ -155,6 +160,7 @@
 			enable-method = "psci";
 			reg = <0x101>;
 			efficiency = <1126>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
 			next-level-cache = <&L2_1>;
 			L1_I_101: l1-icache {
 			      compatible = "arm,arch-cache";
@@ -172,6 +178,7 @@
 			enable-method = "psci";
 			reg = <0x102>;
 			efficiency = <1126>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
 			next-level-cache = <&L2_1>;
 			L1_I_102: l1-icache {
 			      compatible = "arm,arch-cache";
@@ -189,6 +196,7 @@
 			enable-method = "psci";
 			reg = <0x103>;
 			efficiency = <1126>;
+			sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
 			next-level-cache = <&L2_1>;
 			L1_I_103: l1-icache {
 			      compatible = "arm,arch-cache";
@@ -200,6 +208,77 @@
 			};
 		};
 	};
+
+	energy_costs: energy-costs {
+		compatible = "sched-energy";
+
+		CPU_COST_0: core-cost0 {
+			busy-cost-data = <
+				 652800   5
+				 883200   8
+				1036800  10
+				1248000  13
+				1401600  16
+				1536000  19
+				1689600  22
+				1804800  26
+				1843200  27
+				1958400  33
+				2016000  36
+				2150400  43
+				2208000  44
+				2304000  54
+				2400000  65
+			>;
+			idle-cost-data = <
+				4 3 2 1
+			>;
+		};
+		CLUSTER_COST_0: cluster-cost0 {
+			busy-cost-data = <
+				 652800   69
+				 883200   72
+				1036800   74
+				1248000   77
+				1401600   80
+				1536000   90
+				1689600  100
+				1804800  110
+				1843200  120
+				1958400  130
+				2016000  140
+				2150400  150
+				2208000  160
+				2304000  170
+				2400000  180
+			>;
+			idle-cost-data = <
+				4 3 2 1
+			>;
+		};
+		CLUSTER_COST_1: cluster-cost1 {
+			busy-cost-data = <
+				 652800    5
+				 883200    8
+				1036800   10
+				1248000   13
+				1401600   16
+				1536000   85
+				1689600   95
+				1804800  105
+				1843200  115
+				1958400  125
+				2016000  135
+				2150400  145
+				2208000  155
+				2304000  165
+				2400000  175
+			>;
+			idle-cost-data = <
+				4 3 2 1
+			>;
+		};
+	};
 };
 
 &soc {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
index 1e8b0f0..12b039c 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
@@ -14,7 +14,9 @@
 /dts-v1/;
 
 #include "msm8953.dtsi"
+#include "pmi8950.dtsi"
 #include "msm8953-mtp.dtsi"
+#include "msm8953-pmi8950.dtsi"
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 MTP";
@@ -22,3 +24,21 @@
 	qcom,board-id= <8 0>;
 	qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
 };
+
+/{
+	mtp_batterydata: qcom,battery-data {
+		qcom,batt-id-range-pct = <15>;
+		#include "batterydata-itech-3000mah.dtsi"
+		#include "batterydata-ascent-3450mAh.dtsi"
+	};
+};
+
+&pmi8950_fg {
+	qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pmi8950_charger {
+	qcom,battery-data = <&mtp_batterydata>;
+	qcom,chg-led-sw-controls;
+	qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
new file mode 100644
index 0000000..6270223
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	led_flash0: qcom,camera-flash {
+		cell-index = <0>;
+		compatible = "qcom,camera-flash";
+		qcom,flash-type = <1>;
+		qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
+		qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
+		qcom,switch-source = <&pmi8950_switch>;
+	};
+};
+
+&labibb {
+	status = "ok";
+	qpnp,qpnp-labibb-mode = "lcd";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi
new file mode 100644
index 0000000..e4634c4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi
@@ -0,0 +1,928 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		status = "okay";
+		pm8953_s1: regulator-s1 {
+			regulator-min-microvolt = <870000>;
+			regulator-max-microvolt = <1156000>;
+			qcom,init-voltage = <1000000>;
+			status = "okay";
+		};
+	};
+
+	/* PM8953 S2 - VDD_CX supply */
+	rpm-regulator-smpa2 {
+		status = "okay";
+		pm8953_s2_level: regulator-s2-level {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s2_level";
+			qcom,set = <3>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-level;
+		};
+
+		pm8953_s2_floor_level: regulator-s2-floor-level {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s2_floor_level";
+			qcom,set = <3>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-floor-level;
+			qcom,always-send-voltage;
+		};
+
+		pm8953_s2_level_ao: regulator-s2-level-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s2_level_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-level;
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		status = "okay";
+		pm8953_s3: regulator-s3 {
+			regulator-min-microvolt = <1225000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,init-voltage = <1225000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		status = "okay";
+		pm8953_s4: regulator-s4 {
+			regulator-min-microvolt = <1900000>;
+			regulator-max-microvolt = <2050000>;
+			qcom,init-voltage = <1900000>;
+			status = "okay";
+		};
+	};
+
+	/* VDD_MX supply */
+	rpm-regulator-smpa7 {
+		status = "okay";
+		pm8953_s7_level: regulator-s7-level {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s7_level";
+			qcom,set = <3>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,init-voltage-level =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			qcom,use-voltage-level;
+			qcom,always-send-voltage;
+		};
+
+		pm8953_s7_level_ao: regulator-s7-level-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s7_level_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,use-voltage-level;
+			qcom,always-send-voltage;
+		};
+
+		pm8953_s7_level_so: regulator-s7-level-so {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s7_level_so";
+			qcom,set = <2>;
+			regulator-min-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			regulator-max-microvolt =
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+			qcom,init-voltage-level =
+					<RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+			qcom,use-voltage-level;
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		status = "okay";
+		pm8953_l1: regulator-l1 {
+			regulator-min-microvolt = <1000000>;
+			regulator-max-microvolt = <1100000>;
+			qcom,init-voltage = <1000000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		status = "okay";
+		pm8953_l2: regulator-l2 {
+			regulator-min-microvolt = <975000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,init-voltage = <975000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		status = "okay";
+		pm8953_l3: regulator-l3 {
+			regulator-min-microvolt = <925000>;
+			regulator-max-microvolt = <925000>;
+			qcom,init-voltage = <925000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		status = "okay";
+		pm8953_l5: regulator-l5 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		status = "okay";
+		pm8953_l6: regulator-l6 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		status = "okay";
+		pm8953_l7: regulator-l7 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1900000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+
+		pm8953_l7_ao: regulator-l7-ao {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l7_ao";
+			qcom,set = <1>;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1900000>;
+			qcom,init-voltage = <1800000>;
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		status = "okay";
+		pm8953_l8: regulator-l8 {
+			regulator-min-microvolt = <2900000>;
+			regulator-max-microvolt = <2900000>;
+			qcom,init-voltage = <2900000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		status = "okay";
+		pm8953_l9: regulator-l9 {
+			regulator-min-microvolt = <3000000>;
+			regulator-max-microvolt = <3300000>;
+			qcom,init-voltage = <3000000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		status = "okay";
+		pm8953_l10: regulator-l10 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,init-voltage = <2850000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+		status = "okay";
+		pm8953_l11: regulator-l11 {
+			regulator-min-microvolt = <2950000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,init-voltage = <2950000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		status = "okay";
+		pm8953_l12: regulator-l12 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <2950000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+		status = "okay";
+		pm8953_l13: regulator-l13 {
+			regulator-min-microvolt = <3125000>;
+			regulator-max-microvolt = <3125000>;
+			qcom,init-voltage = <3125000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		status = "okay";
+		pm8953_l16: regulator-l16 {
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			qcom,init-voltage = <1800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		status = "okay";
+		pm8953_l17: regulator-l17 {
+			regulator-min-microvolt = <2850000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,init-voltage = <2850000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		status = "okay";
+		pm8953_l19: regulator-l19 {
+			regulator-min-microvolt = <1200000>;
+			regulator-max-microvolt = <1350000>;
+			qcom,init-voltage = <1200000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa22 {
+		status = "okay";
+		pm8953_l22: regulator-l22 {
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2850000>;
+			qcom,init-voltage = <2800000>;
+			status = "okay";
+		};
+	};
+
+	rpm-regulator-ldoa23 {
+		status = "okay";
+		pm8953_l23: regulator-l23 {
+			regulator-min-microvolt = <975000>;
+			regulator-max-microvolt = <1225000>;
+			qcom,init-voltage = <975000>;
+			status = "okay";
+		};
+	};
+};
+
+&spmi_bus {
+	qcom,pm8953@1 {
+		/* PM8953 S5 + S6 = VDD_APC supply */
+		pm8953_s5: spm-regulator@2000 {
+			compatible = "qcom,spm-regulator";
+			reg = <0x2000 0x100>;
+			regulator-name = "pm8953_s5";
+			regulator-min-microvolt = <400000>;
+			regulator-max-microvolt = <1140000>;
+
+			pm8953_s5_limit: avs-limit-regulator {
+				regulator-name = "pm8953_s5_avs_limit";
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1140000>;
+			};
+		};
+	};
+};
+
+&soc {
+	apc_mem_acc_vreg: regulator@19461d4 {
+		compatible = "qcom,mem-acc-regulator";
+		reg = <0x019461d4 0x4>, <0x019461d8 0x4>;
+		reg-names = "acc-sel-l1", "acc-sel-l2";
+		regulator-name = "apc_mem_acc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <2>;
+
+		qcom,corner-acc-map = <0x1 0x0>;
+		qcom,acc-sel-l1-bit-pos = <0>;
+		qcom,acc-sel-l1-bit-size = <1>;
+		qcom,acc-sel-l2-bit-pos = <0>;
+		qcom,acc-sel-l2-bit-size = <1>;
+	};
+
+	apc_cpr: cpr4-ctrl@b018000 {
+		compatible = "qcom,cpr4-msm8953-apss-regulator";
+		reg = <0xb018000 0x4000>, <0xa4000 0x1000>;
+		reg-names = "cpr_ctrl", "fuse_base";
+		interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "cpr";
+
+		qcom,cpr-ctrl-name = "apc";
+
+		qcom,cpr-sensor-time = <1000>;
+		qcom,cpr-loop-time = <5000000>;
+		qcom,cpr-idle-cycles = <15>;
+		qcom,cpr-step-quot-init-min = <12>;
+		qcom,cpr-step-quot-init-max = <14>;
+		qcom,cpr-count-mode = <0>;		/* All-at-once */
+		qcom,cpr-count-repeat = <14>;
+		qcom,cpr-down-error-step-limit = <1>;
+		qcom,cpr-up-error-step-limit = <1>;
+
+		qcom,apm-ctrl = <&apc_apm>;
+		qcom,apm-threshold-voltage = <850000>;
+		qcom,apm-hysteresis-voltage = <5000>;
+
+		vdd-supply = <&pm8953_s5>;
+		qcom,voltage-step = <5000>;
+		vdd-limit-supply = <&pm8953_s5_limit>;
+		mem-acc-supply = <&apc_mem_acc_vreg>;
+
+		qcom,cpr-enable;
+		qcom,cpr-hw-closed-loop;
+
+		qcom,cpr-panic-reg-addr-list =
+			<0xb1d2c18 0xb1d2900 0x0b1112b0 0xb018798>;
+		qcom,cpr-panic-reg-name-list =
+			"CCI_SAW4_PMIC_STS", "CCI_SAW4_VCTL",
+			"APCS_ALIAS0_APM_CTLER_STATUS",
+			"APCS0_CPR_CORE_ADJ_MODE_REG";
+
+		qcom,cpr-temp-point-map = <250 650 850>;
+		qcom,cpr-initial-temp-band = <0>;
+
+		/* Turbo (corner 6) ceiling voltage */
+		qcom,cpr-aging-ref-voltage = <990000>;
+
+		thread@0 {
+			qcom,cpr-thread-id = <0>;
+			qcom,cpr-consecutive-up = <0>;
+			qcom,cpr-consecutive-down = <2>;
+			qcom,cpr-up-threshold = <2>;
+			qcom,cpr-down-threshold = <1>;
+
+			apc_vreg: regulator {
+				regulator-name = "apc_corner";
+				regulator-min-microvolt = <1>;
+				regulator-max-microvolt = <9>;
+
+				qcom,cpr-fuse-corners = <4>;
+				qcom,cpr-fuse-combos = <64>;
+				qcom,cpr-speed-bins = <8>;
+				qcom,cpr-speed-bin-corners =
+					<9 0 7 0 0 0 7 9>;
+				qcom,cpr-corners =
+					/* Speed bin 0 */
+					<9 9 9 9 9 9 9 9>,
+
+					/* Speed bin 1 */
+					<0 0 0 0 0 0 0 0>,
+
+					/* Speed bin 2 */
+					<7 7 7 7 7 7 7 7>,
+
+					/* Speed bin 3..5 */
+					<0 0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0 0>,
+
+					/* Speed bin 6 */
+					<7 7 7 7 7 7 7 7>,
+
+					/* Speed bin 7 */
+					<9 9 9 9 9 9 9 9>;
+
+				qcom,cpr-corner-fmax-map =
+					/* Speed bin 0 */
+					<1 2 4 9>,
+
+					/* Speed bin 1 */
+					<0 0 0 0>,
+
+					/* Speed bin 2 */
+					<1 2 4 7>,
+
+					/* Speed bin 3..5 */
+					<0 0 0 0>,
+					<0 0 0 0>,
+					<0 0 0 0>,
+
+					/* Speed bin 6 */
+					<1 2 4 7>,
+
+					/* Speed bin 7 */
+					<1 2 4 9>;
+
+				qcom,cpr-voltage-ceiling =
+					/* Speed bin 0 */
+					<715000  790000 860000 865000 920000
+					 990000 1065000 1065000 1065000>,
+
+					/* Speed bin 2 */
+					<715000  790000 860000 865000 920000
+					 990000 1065000>,
+
+					/* Speed bin 6 */
+					<715000  790000 860000 865000 920000
+					 990000 1065000>,
+
+					/* Speed bin 7 */
+					<715000  790000 860000 865000 920000
+					 990000 1065000 1065000 1065000>;
+
+				qcom,cpr-voltage-floor =
+					/* Speed bin 0 */
+					<500000  500000 500000 500000 500000
+					 500000  500000 500000 500000>,
+
+					/* Speed bin 2 */
+					<500000  500000 500000 500000 500000
+					 500000  500000>,
+
+					/* Speed bin 6 */
+					<500000  500000 500000 500000 500000
+					 500000  500000>,
+
+					/* Speed bin 7 */
+					<500000  500000 500000 500000 500000
+					 500000  500000 500000 500000>;
+
+				qcom,cpr-floor-to-ceiling-max-range =
+					/* Speed bin 0; CPR rev 0..7 */
+					 <    0     0     0     0     0
+					      0     0     0     0>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+
+					/* Speed bin 2; CPR rev 0..7 */
+					 <    0     0     0     0     0
+					      0     0>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+
+					/* Speed bin 6; CPR rev 0..7 */
+					 <    0     0     0     0     0
+					      0     0>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000>,
+
+					/* Speed bin 7; CPR rev 0..7 */
+					 <    0     0     0     0     0
+					      0     0     0     0>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>,
+					 <50000 50000 50000 50000 50000
+					  50000 50000 50000 50000>;
+
+				qcom,cpr-misc-fuse-voltage-adjustment =
+					/* Speed bin 0; misc fuse 0..1 */
+					<    0     0     0     0      0
+					     0     0     0     0>,
+					<    0     0 30000     0      0
+					     0     0     0     0>,
+
+					/* Speed bin 2; misc fuse 0..1 */
+					<    0     0     0     0      0
+					     0     0>,
+					<    0     0 30000     0      0
+					     0     0>,
+
+					/* Speed bin 6; misc fuse 0..1 */
+					<    0     0     0     0      0
+					     0     0>,
+					<    0     0 30000     0      0
+					     0     0>,
+
+					/* Speed bin 7; misc fuse 0..1 */
+					<    0     0     0     0      0
+					     0     0     0     0>,
+					<    0     0 30000     0      0
+					     0     0     0     0>;
+
+				qcom,mem-acc-voltage =
+					/* Speed bin 0 */
+					<1 1 2 2 2 2 2 2 2>,
+
+					/* Speed bin 2 */
+					<1 1 2 2 2 2 2>,
+
+					/* Speed bin 6 */
+					<1 1 2 2 2 2 2>,
+
+					/* Speed bin 7 */
+					<1 1 2 2 2 2 2 2 2>;
+
+				qcom,corner-frequencies =
+					/* Speed bin 0 */
+					<652800000 1036800000 1401600000
+					1689600000 1804800000 1958400000
+					2016000000 2150400000 2208000000>,
+
+					/* Speed bin 2 */
+					<652800000 1036800000 1401600000
+					1689600000 1804800000 1958400000
+					2016000000>,
+
+					/* Speed bin 6 */
+					<652800000 1036800000 1401600000
+					1689600000 1804800000 1958400000
+					2016000000>,
+
+					/* Speed bin 7 */
+					<652800000 1036800000 1401600000
+					1689600000 1804800000 1958400000
+					2016000000 2150400000 2208000000>;
+
+				qcom,cpr-open-loop-voltage-fuse-adjustment =
+					/* Speed bin 0; CPR rev 0..7 */
+					<     0      0      0     0>,
+					< 25000      0   5000 40000>,
+					< 25000      0   5000 40000>,
+					< 25000      0   5000 40000>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 1; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 2; CPR rev 0..7 */
+					<     0      0      0     0>,
+					< 25000      0   5000 40000>,
+					< 25000      0   5000 40000>,
+					< 25000      0   5000 40000>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 3; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 4; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 5; CPR rev 0..7 */
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 6; CPR rev 0..7 */
+					<     0      0      0     0>,
+					< 25000      0   5000 40000>,
+					< 25000      0   5000 40000>,
+					< 25000      0   5000 40000>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+
+					/* Speed bin 7; CPR rev 0..7 */
+					<     0      0      0     0>,
+					< 25000      0   5000 40000>,
+					< 25000      0   5000 40000>,
+					< 25000      0   5000 40000>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>,
+					<     0      0      0     0>;
+
+				qcom,cpr-closed-loop-voltage-fuse-adjustment =
+					/* Speed bin 0; CPR rev 0..7 */
+					<      0        0        0      0>,
+					<  10000 (-15000)        0  25000>,
+					<  10000 (-15000)        0  25000>,
+					<(-5000) (-30000) (-15000)  10000>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+
+					/* Speed bin 1; CPR rev 0..7 */
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+
+					/* Speed bin 2; CPR rev 0..7 */
+					<      0        0        0      0>,
+					<  10000 (-15000)        0  25000>,
+					<  10000 (-15000)        0  25000>,
+					<(-5000) (-30000) (-15000)  10000>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+
+					/* Speed bin 3; CPR rev 0..7 */
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+
+					/* Speed bin 4; CPR rev 0..7 */
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+
+					/* Speed bin 5; CPR rev 0..7 */
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+
+					/* Speed bin 6; CPR rev 0..7 */
+					<      0        0        0      0>,
+					<  10000 (-15000)        0  25000>,
+					<  10000 (-15000)        0  25000>,
+					<(-5000) (-30000) (-15000)  10000>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+
+					/* Speed bin 7; CPR rev 0..7 */
+					<      0        0        0      0>,
+					<  10000 (-15000)        0  25000>,
+					<  10000 (-15000)        0  25000>,
+					<(-5000) (-30000) (-15000)  10000>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>,
+					<      0        0        0      0>;
+
+				qcom,cpr-ro-scaling-factor =
+				      <3610 3790    0 2200 2450 2310 2170 2210
+				       2330 2210 2470 2340  780 2700 2450 2090>,
+				      <3610 3790    0 2200 2450 2310 2170 2210
+				       2330 2210 2470 2340  780 2700 2450 2090>,
+				      <3610 3790    0 2200 2450 2310 2170 2210
+				       2330 2210 2470 2340  780 2700 2450 2090>,
+				      <3610 3790    0 2200 2450 2310 2170 2210
+				       2330 2210 2470 2340  780 2700 2450 2090>;
+
+				qcom,allow-voltage-interpolation;
+				qcom,allow-quotient-interpolation;
+				qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+				qcom,corner-allow-temp-adjustment =
+					/* Speed bin 0; CPR rev 0..7 */
+					<0 0 0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+
+					/* Speed bin 2; CPR rev 0..7 */
+					<0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0>,
+					<1 1 1 1 0 0 0>,
+					<1 1 1 1 0 0 0>,
+					<1 1 1 1 0 0 0>,
+					<1 1 1 1 0 0 0>,
+					<1 1 1 1 0 0 0>,
+
+					/* Speed bin 6; CPR rev 0..7 */
+					<0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0>,
+					<1 1 1 1 0 0 0>,
+					<1 1 1 1 0 0 0>,
+					<1 1 1 1 0 0 0>,
+					<1 1 1 1 0 0 0>,
+					<1 1 1 1 0 0 0>,
+
+					/* Speed bin 7; CPR rev 0..7 */
+					<0 0 0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>,
+					<1 1 1 1 0 0 0 0 0>;
+
+				qcom,cpr-corner1-temp-core-voltage-adjustment =
+					<(0) (-5000) (-15000) (-20000)>;
+
+				qcom,cpr-corner2-temp-core-voltage-adjustment =
+					<(0) (-5000) (-15000) (-15000)>;
+
+				qcom,cpr-corner3-temp-core-voltage-adjustment =
+					<(0) (-5000) (-15000)      (0)>;
+
+				qcom,cpr-corner4-temp-core-voltage-adjustment =
+					<(0) (-5000) (-15000)      (0)>;
+
+				qcom,cpr-aging-max-voltage-adjustment = <15000>;
+				qcom,cpr-aging-ref-corner = <6>; /* Turbo */
+				qcom,cpr-aging-ro-scaling-factor = <2800>;
+				qcom,allow-aging-voltage-adjustment =
+					/* Speed bin 0 */
+					<0 0 0 1 1 1 1 1>,
+
+					/* Speed bin 1 */
+					<0 0 0 0 0 0 0 0>,
+
+					/* Speed bin 2 */
+					<0 0 0 1 1 1 1 1>,
+
+					/* Speed bin 3..5 */
+					<0 0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0 0>,
+					<0 0 0 0 0 0 0 0>,
+
+					/* Speed bin 6 */
+					<0 0 0 1 1 1 1 1>,
+
+					/* Speed bin 7 */
+					<0 0 0 1 1 1 1 1>;
+			};
+		};
+	};
+
+	gfx_mem_acc: regulator@194415c {
+		compatible = "qcom,mem-acc-regulator";
+		reg = <0x0194415c 0x4>;
+		reg-names = "acc-sel-l1";
+		regulator-name = "gfx_mem_acc_corner";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <2>;
+
+		qcom,acc-sel-l1-bit-pos = <0>;
+		qcom,acc-sel-l1-bit-size = <1>;
+		qcom,corner-acc-map = <0x1 0x0>;
+	};
+
+	gfx_vreg_corner: ldo@185f000 {
+		compatible = "qcom,msm8953-gfx-ldo";
+		reg = <0x0185f000 0x30>, <0xa4000 0x1000>;
+		reg-names = "ldo_addr", "efuse_addr";
+
+		regulator-name = "msm_gfx_ldo";
+		regulator-min-microvolt = <1>;
+		regulator-max-microvolt = <7>;
+
+		qcom,ldo-voltage-ceiling = <620000 680000 750000>;
+		qcom,ldo-voltage-floor =   <510000 510000 600000>;
+
+		qcom,num-corners = <7>;
+		qcom,num-ldo-corners = <3>;
+		qcom,ldo-enable-corner-map = <1 1 1 0 0 0 0>;
+		qcom,init-corner = <4>;
+
+		vdd-cx-supply = <&pm8953_s2_level>;
+		qcom,vdd-cx-corner-map = <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+					<RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+					<RPM_SMD_REGULATOR_LEVEL_SVS>,
+					<RPM_SMD_REGULATOR_LEVEL_SVS_PLUS>,
+					<RPM_SMD_REGULATOR_LEVEL_NOM>,
+					<RPM_SMD_REGULATOR_LEVEL_NOM_PLUS>,
+					<RPM_SMD_REGULATOR_LEVEL_TURBO>;
+
+		mem-acc-supply = <&gfx_mem_acc>;
+		qcom,mem-acc-corner-map = <1 1 1 2 2 2 2>;
+		qcom,ldo-init-voltage-adjustment = <35000 25000 0>;
+	};
+
+	eldo2_8953: eldo2 {
+		compatible = "regulator-fixed";
+		regulator-name = "eldo2_8953";
+		startup-delay-us = <0>;
+		enable-active-high;
+		gpio = <&tlmm 50 0>;
+		regulator-always-on;
+	};
+
+	adv_vreg: adv_vreg {
+		compatible = "regulator-fixed";
+		regulator-name = "adv_vreg";
+		startup-delay-us = <400>;
+		enable-active-high;
+		gpio = <&pm8953_gpios 5 0>;
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 12b39a9..a9ca87c 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -13,7 +13,9 @@
 
 #include "skeleton64.dtsi"
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/spmi/spmi.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
 
 / {
 	model = "Qualcomm Technologies, Inc. MSM 8953";
@@ -617,7 +619,12 @@
 			reg = <0x6b0 32>;
 		};
 
-		 pil@94c {
+		kaslr_offset@6d0 {
+			compatible = "qcom,msm-imem-kaslr_offset";
+			reg = <0x6d0 12>;
+		};
+
+		pil@94c {
 			compatible = "qcom,msm-imem-pil";
 			reg = <0x94c 200>;
 
@@ -764,3 +771,7 @@
 		cell-index = <0>;
 	};
 };
+
+#include "pm8953-rpm-regulator.dtsi"
+#include "pm8953.dtsi"
+#include "msm8953-regulator.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi
new file mode 100644
index 0000000..1e594c6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&rpm_bus {
+	rpm-regulator-smpa1 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s1 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa2 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s2 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s2";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa3 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s3 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa4 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <4>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s4 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s4";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-smpa7 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "smpa";
+		qcom,resource-id = <7>;
+		qcom,regulator-type = <1>;
+		qcom,hpm-min-load = <100000>;
+		status = "disabled";
+
+		regulator-s7 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_s7";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa1 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <1>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l1 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l1";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa2 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <2>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l2 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l2";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa3 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l3 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l3";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa5 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <5>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l5 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l5";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa6 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <6>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l6 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l6";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa7 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <7>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l7 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l7";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa8 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <8>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l8 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l8";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa9 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <9>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l9 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l9";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa10 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <10>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l10 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l10";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa11 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <11>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l11 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l11";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa12 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <12>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l12 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l12";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa13 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <13>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l13 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l13";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa16 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <16>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <5000>;
+		status = "disabled";
+
+		regulator-l16 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l16";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa17 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <17>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l17 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l17";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa19 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <19>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l19 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l19";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa22 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <22>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l22 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l22";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	rpm-regulator-ldoa23 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "ldoa";
+		qcom,resource-id = <23>;
+		qcom,regulator-type = <0>;
+		qcom,hpm-min-load = <10000>;
+		status = "disabled";
+
+		regulator-l23 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "pm8953_l23";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+
+	/* Regulator to notify APC corner to RPM */
+	rpm-regulator-clk0 {
+		compatible = "qcom,rpm-smd-regulator-resource";
+		qcom,resource-name = "clk0";
+		qcom,resource-id = <3>;
+		qcom,regulator-type = <1>;
+		status = "disabled";
+
+		regulator-clk0 {
+			compatible = "qcom,rpm-smd-regulator";
+			regulator-name = "rpm_apc";
+			qcom,set = <3>;
+			status = "disabled";
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8953.dtsi b/arch/arm64/boot/dts/qcom/pm8953.dtsi
new file mode 100644
index 0000000..60162e3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8953.dtsi
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&spmi_bus {
+
+	qcom,pm8953@0 {
+		compatible = "qcom,spmi-pmic";
+		reg = <0x0 SPMI_USID>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		pm8953_revid: qcom,revid@100 {
+			compatible = "qcom,qpnp-revid";
+			reg = <0x100 0x100>;
+		};
+
+		qcom,power-on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>,
+				<0x0 0x8 0x1 IRQ_TYPE_NONE>,
+				<0x0 0x8 0x4 IRQ_TYPE_NONE>,
+				<0x0 0x8 0x5 IRQ_TYPE_NONE>;
+			interrupt-names = "kpdpwr", "resin",
+				"resin-bark", "kpdpwr-resin-bark";
+			qcom,pon-dbc-delay = <15625>;
+			qcom,system-reset;
+
+			qcom,pon_1 {
+				qcom,pon-type = <0>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+
+			qcom,pon_2 {
+				qcom,pon-type = <1>;
+				qcom,pull-up = <1>;
+				linux,code = <114>;
+			};
+		};
+
+		pm8953_temp_alarm: qcom,temp-alarm@2400 {
+			compatible = "qcom,qpnp-temp-alarm";
+			reg = <0x2400 0x100>;
+			interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
+			label = "pm8953_tz";
+			qcom,channel-num = <8>;
+			qcom,threshold-set = <0>;
+			qcom,temp_alarm-vadc = <&pm8953_vadc>;
+		};
+
+		pm8953_coincell: qcom,coincell@2800 {
+			compatible = "qcom,qpnp-coincell";
+			reg = <0x2800 0x100>;
+		};
+
+		pm8953_mpps: mpps {
+			compatible = "qcom,qpnp-pin";
+			spmi-dev-container;
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8953-mpp";
+
+			mpp@a000 {
+				reg = <0xa000 0x100>;
+				qcom,pin-num = <1>;
+				status = "disabled";
+			};
+
+			mpp@a100 {
+				reg = <0xa100 0x100>;
+				qcom,pin-num = <2>;
+			};
+
+			mpp@a200 {
+				reg = <0xa200 0x100>;
+				qcom,pin-num = <3>;
+				status = "disabled";
+			};
+
+			mpp@a300 {
+				reg = <0xa300 0x100>;
+				qcom,pin-num = <4>;
+			};
+		};
+
+		pm8953_gpios: gpios {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-pin";
+			gpio-controller;
+			#gpio-cells = <2>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			label = "pm8953-gpio";
+
+			gpio@c000 {
+				reg = <0xc000 0x100>;
+				qcom,pin-num = <1>;
+				status = "disabled";
+			};
+
+			gpio@c100 {
+				reg = <0xc100 0x100>;
+				qcom,pin-num = <2>;
+				status = "disabled";
+			};
+
+			gpio@c200 {
+				reg = <0xc200 0x100>;
+				qcom,pin-num = <3>;
+				status = "disabled";
+			};
+
+			gpio@c300 {
+				reg = <0xc300 0x100>;
+				qcom,pin-num = <4>;
+				status = "disabled";
+			};
+
+			gpio@c400 {
+				reg = <0xc400 0x100>;
+				qcom,pin-num = <5>;
+				status = "disabled";
+			};
+
+			gpio@c500 {
+				reg = <0xc500 0x100>;
+				qcom,pin-num = <6>;
+				status = "disabled";
+			};
+
+			gpio@c600 {
+				reg = <0xc600 0x100>;
+				qcom,pin-num = <7>;
+				status = "disabled";
+			};
+
+			gpio@c700 {
+				reg = <0xc700 0x100>;
+				qcom,pin-num = <8>;
+				status = "disabled";
+			};
+		};
+
+		pm8953_vadc: vadc@3100 {
+			compatible = "qcom,qpnp-vadc";
+			reg = <0x3100 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names = "eoc-int-en-set";
+			qcom,adc-bit-resolution = <15>;
+			qcom,adc-vdd-reference = <1800>;
+			qcom,vadc-poll-eoc;
+
+			chan@8 {
+				label = "die_temp";
+				reg = <8>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <3>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@9 {
+				label = "ref_625mv";
+				reg = <9>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@a {
+				label = "ref_1250v";
+				reg = <0xa>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+
+			chan@c {
+				label = "ref_buf_625mv";
+				reg = <0xc>;
+				qcom,decimation = <0>;
+				qcom,pre-div-channel-scaling = <0>;
+				qcom,calibration-type = "absolute";
+				qcom,scale-function = <0>;
+				qcom,hw-settle-time = <0>;
+				qcom,fast-avg-setup = <0>;
+			};
+		};
+
+		pm8953_adc_tm: vadc@3400 {
+			compatible = "qcom,qpnp-adc-tm";
+			reg = <0x3400 0x100>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupts =	<0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x34 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0x34 0x4 IRQ_TYPE_EDGE_RISING>;
+			interrupt-names =	"eoc-int-en-set",
+						"high-thr-en-set",
+						"low-thr-en-set";
+			qcom,adc-bit-resolution = <15>;
+			qcom,adc-vdd-reference = <1800>;
+			qcom,adc_tm-vadc = <&pm8953_vadc>;
+
+		};
+
+		pm8953_rtc: qcom,pm8953_rtc {
+			spmi-dev-container;
+			compatible = "qcom,qpnp-rtc";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			qcom,qpnp-rtc-write = <0>;
+			qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+			qcom,pm8953_rtc_rw@6000 {
+				reg = <0x6000 0x100>;
+			};
+
+			qcom,pm8953_rtc_alarm@6100 {
+				reg = <0x6100 0x100>;
+				interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
+			};
+		};
+
+		pm8953_typec: qcom,pm8953_typec@bf00 {
+			compatible = "qcom,qpnp-typec";
+			reg = <0xbf00 0x100>;
+			interrupts =    <0x0 0xbf 0x0 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0xbf 0x1 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0xbf 0x2 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0xbf 0x3 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0xbf 0x4 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0xbf 0x6 IRQ_TYPE_EDGE_RISING>,
+					<0x0 0xbf 0x7 IRQ_TYPE_EDGE_RISING>;
+
+			interrupt-names =       "vrd-change",
+						"ufp-detect",
+						"ufp-detach",
+						"dfp-detect",
+						"dfp-detach",
+						"vbus-err",
+						"vconn-oc";
+		};
+	};
+
+	pm8953_1: qcom,pm8953@1 {
+		compatible = "qcom,spmi-pmic";
+		reg = <0x1 SPMI_USID>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		pm8953_pwm: pwm@bc00 {
+			status = "disabled";
+			compatible = "qcom,qpnp-pwm";
+			reg = <0xbc00 0x100>;
+			reg-names = "qpnp-lpg-channel-base";
+			qcom,channel-id = <0>;
+			qcom,supported-sizes = <6>, <9>;
+			#pwm-cells = <2>;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index 4223cfe..8b4fccb 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -43,7 +43,7 @@
 			reg = <0x3100 0x100>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			interrupts = <0x2 0x31 0x0>;
+			interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "eoc-int-en-set";
 			qcom,adc-bit-resolution = <15>;
 			qcom,adc-vdd-reference = <1800>;
@@ -140,7 +140,6 @@
 		};
 
 		pmi8950_gpios: gpios {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
 			gpio-controller;
 			#gpio-cells = <2>;
@@ -162,7 +161,6 @@
 		};
 
 		pmi8950_mpps: mpps {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-pin";
 			gpio-controller;
 			#gpio-cells = <2>;
@@ -196,7 +194,6 @@
 		};
 
 		pmi8950_charger: qcom,qpnp-smbcharger {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-smbcharger";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -218,14 +215,14 @@
 
 			qcom,chgr@1000 {
 				reg = <0x1000 0x100>;
-				interrupts =	<0x2 0x10 0x0>,
-						<0x2 0x10 0x1>,
-						<0x2 0x10 0x2>,
-						<0x2 0x10 0x3>,
-						<0x2 0x10 0x4>,
-						<0x2 0x10 0x5>,
-						<0x2 0x10 0x6>,
-						<0x2 0x10 0x7>;
+				interrupts =	<0x2 0x10 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x10 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"chg-error",
 							"chg-inhibit",
@@ -239,9 +236,9 @@
 
 			qcom,otg@1100 {
 				reg = <0x1100 0x100>;
-				interrupts =	<0x2 0x11 0x0>,
-						<0x2 0x11 0x1>,
-						<0x2 0x11 0x3>;
+				interrupts =	<0x2 0x11 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x11 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x11 0x3 IRQ_TYPE_NONE>;
 				interrupt-names =	"otg-fail",
 							"otg-oc",
 						"usbid-change";
@@ -249,14 +246,14 @@
 
 			qcom,bat-if@1200 {
 				reg = <0x1200 0x100>;
-				interrupts =	<0x2 0x12 0x0>,
-						<0x2 0x12 0x1>,
-						<0x2 0x12 0x2>,
-						<0x2 0x12 0x3>,
-					<0x2 0x12 0x4>,
-						<0x2 0x12 0x5>,
-						<0x2 0x12 0x6>,
-						<0x2 0x12 0x7>;
+				interrupts =	<0x2 0x12 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x12 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"batt-hot",
 							"batt-warm",
@@ -270,10 +267,10 @@
 
 			qcom,usb-chgpth@1300 {
 				reg = <0x1300 0x100>;
-				interrupts =	<0x2 0x13 0x0>,
-						<0x2 0x13 0x1>,
-					<0x2 0x13 0x2>,
-						<0x2 0x13 0x5>;
+				interrupts =	<0x2 0x13 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x13 0x5 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"usbin-uv",
 						"usbin-ov",
@@ -283,20 +280,20 @@
 
 			qcom,dc-chgpth@1400 {
 				reg = <0x1400 0x100>;
-				interrupts =	<0x2 0x14 0x0>,
-						<0x2 0x14 0x1>;
+				interrupts =	<0x2 0x14 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x14 0x1 IRQ_TYPE_NONE>;
 				interrupt-names =	"dcin-uv",
 							"dcin-ov";
 			};
 
 			qcom,chgr-misc@1600 {
 				reg = <0x1600 0x100>;
-				interrupts =	<0x2 0x16 0x0>,
-						<0x2 0x16 0x1>,
-						<0x2 0x16 0x2>,
-					<0x2 0x16 0x3>,
-						<0x2 0x16 0x4>,
-						<0x2 0x16 0x5>;
+				interrupts =	<0x2 0x16 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x16 0x5 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"power-ok",
 							"temp-shutdown",
@@ -312,7 +309,6 @@
 		};
 
 		pmi8950_fg: qcom,fg {
-			spmi-dev-container;
 			compatible = "qcom,qpnp-fg";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -330,13 +326,13 @@
 			qcom,fg-soc@4000 {
 			status = "okay";
 				reg = <0x4000 0x100>;
-				interrupts =	<0x2 0x40 0x0>,
-						<0x2 0x40 0x1>,
-						<0x2 0x40 0x2>,
-						<0x2 0x40 0x3>,
-						<0x2 0x40 0x4>,
-						<0x2 0x40 0x5>,
-						<0x2 0x40 0x6>;
+				interrupts =	<0x2 0x40 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x40 0x6 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"high-soc",
 							"low-soc",
@@ -349,14 +345,14 @@
 
 			qcom,fg-batt@4100 {
 				reg = <0x4100 0x100>;
-				interrupts =	<0x2 0x41 0x0>,
-						<0x2 0x41 0x1>,
-					<0x2 0x41 0x2>,
-						<0x2 0x41 0x3>,
-						<0x2 0x41 0x4>,
-						<0x2 0x41 0x5>,
-						<0x2 0x41 0x6>,
-						<0x2 0x41 0x7>;
+				interrupts =	<0x2 0x41 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x1 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x2 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x3 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x4 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x5 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x6 IRQ_TYPE_NONE>,
+						<0x2 0x41 0x7 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"soft-cold",
 							"soft-hot",
@@ -375,8 +371,8 @@
 			qcom,fg-memif@4400 {
 				status = "okay";
 				reg = <0x4400 0x100>;
-				interrupts =	<0x2 0x44 0x0>,
-						<0x2 0x44 0x2>;
+				interrupts =	<0x2 0x44 0x0 IRQ_TYPE_NONE>,
+						<0x2 0x44 0x2 IRQ_TYPE_NONE>;
 
 				interrupt-names =	"mem-avail",
 							"data-rcvry-sug";
@@ -387,8 +383,8 @@
 			compatible = "qcom,msm-bcl";
 			reg = <0x4200 0xFF 0x88E 0x2>;
 			reg-names = "fg_user_adc", "pon_spare";
-			interrupts = <0x2 0x42 0x0>,
-					<0x2 0x42 0x1>;
+			interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+					<0x2 0x42 0x1 IRQ_TYPE_NONE>;
 			interrupt-names = "bcl-high-ibat-int",
 					"bcl-low-vbat-int";
 			qcom,vbat-scaling-factor = <39000>;
@@ -429,7 +425,6 @@
 
 		labibb: qpnp-labibb-regulator {
 			status = "disabled";
-			spmi-dev-container;
 			compatible = "qcom,qpnp-labibb-regulator";
 			#address-cells = <1>;
 			#size-cells = <1>;
@@ -512,7 +507,7 @@
 					"qpnp-wled-sink-base",
 					"qpnp-wled-ibb-base",
 					"qpnp-wled-lab-base";
-			interrupts = <0x3 0xd8 0x2>;
+			interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
 			interrupt-names = "sc-irq";
 			status = "okay";
 			linux,name = "wled";
@@ -531,6 +526,7 @@
 			qcom,fs-curr-ua = <20000>;
 			qcom,led-strings-list = [00 01];
 			qcom,en-ext-pfet-sc-pro;
+			qcom,pmic-revid = <&pmi8950_revid>;
 			qcom,cons-sync-write-delay-us = <1000>;
 		};
 
@@ -617,8 +613,8 @@
 		pmi_haptic: qcom,haptic@c000 {
 			compatible = "qcom,qpnp-haptic";
 			reg = <0xc000 0x100>;
-			interrupts = <0x3 0xc0 0x0>,
-					<0x3 0xc0 0x1>;
+			interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+					<0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
 			interrupt-names = "sc-irq", "play-irq";
 			qcom,pmic-revid = <&pmi8950_revid>;
 			vcc_pon-supply = <&pon_perph_reg>;
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts
new file mode 100644
index 0000000..e27baba
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "qcs605-lc-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
+	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+	qcom,msm-id = <347 0x0>;
+	qcom,board-id = <8 4>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
new file mode 100644
index 0000000..194bfeb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * 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 "qcs605.dtsi"
+#include "qcs605-lc-mtp.dtsi"
+
+/ {
+	model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
+	compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+	qcom,board-id = <8 4>;
+
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
new file mode 100644
index 0000000..b46cbfd
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
@@ -0,0 +1,113 @@
+/* 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.
+ */
+
+/ {
+	cpus {
+		/delete-node/ cpu@200;
+		/delete-node/ cpu@300;
+		/delete-node/ cpu@400;
+		/delete-node/ cpu@500;
+
+		cpu-map {
+			cluster0 {
+				/delete-node/ core2;
+				/delete-node/ core3;
+				/delete-node/ core4;
+				/delete-node/ core5;
+			};
+		};
+	};
+
+
+};
+
+&soc {
+	/delete-node/ jtagmm@7240000;
+	/delete-node/ jtagmm@7340000;
+	/delete-node/ jtagmm@7440000;
+	/delete-node/ jtagmm@7540000;
+	/delete-node/ cti@7220000;
+	/delete-node/ cti@7320000;
+	/delete-node/ cti@7420000;
+	/delete-node/ cti@7520000;
+	/delete-node/ etm@7240000;
+	/delete-node/ etm@7340000;
+	/delete-node/ etm@7440000;
+	/delete-node/ etm@7540000;
+	cpuss_dump {
+		/delete-node/ qcom,l1_i_cache200;
+		/delete-node/ qcom,l1_i_cache300;
+		/delete-node/ qcom,l1_i_cache400;
+		/delete-node/ qcom,l1_i_cache500;
+		/delete-node/ qcom,l1_d_cache200;
+		/delete-node/ qcom,l1_d_cache300;
+		/delete-node/ qcom,l1_d_cache400;
+		/delete-node/ qcom,l1_d_cache500;
+		/delete-node/ qcom,l1_tlb_dump200;
+		/delete-node/ qcom,l1_tlb_dump300;
+		/delete-node/ qcom,l1_tlb_dump400;
+		/delete-node/ qcom,l1_tlb_dump500;
+	};
+
+	devfreq_memlat_0: qcom,cpu0-memlat-mon {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+
+	devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+	devfreq_compute0: qcom,devfreq-compute0 {
+		qcom,cpulist = <&CPU0 &CPU1>;
+	};
+
+	funnel_apss: funnel@7800000 {
+		ports {
+			/delete-node/ port@3;
+			/delete-node/ port@4;
+			/delete-node/ port@5;
+			/delete-node/ port@6;
+		};
+	};
+
+	qcom,lpm-levels {
+		qcom,pm-cluster@0 {
+			qcom,pm-cpu@0 {
+				qcom,cpu = <&CPU0 &CPU1>;
+			};
+		};
+	};
+};
+
+&pm660_temp_alarm {
+	cooling-maps {
+		/delete-node/ trip0_cpu2;
+		/delete-node/ trip0_cpu3;
+		/delete-node/ trip0_cpu4;
+		/delete-node/ trip0_cpu5;
+		/delete-node/ trip1_cpu2;
+		/delete-node/ trip1_cpu3;
+		/delete-node/ trip1_cpu4;
+		/delete-node/ trip1_cpu5;
+	};
+};
+
+&thermal_zones {
+
+	xo-therm-cpu-step {
+		cooling-maps {
+			/delete-node/ skin_cpu2;
+			/delete-node/ skin_cpu3;
+			/delete-node/ skin_cpu4;
+			/delete-node/ skin_cpu5;
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 110e626..1f40e20 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -875,7 +875,6 @@
 			"soc_ahb_clk",
 			"cpas_ahb_clk",
 			"camnoc_axi_clk",
-			"icp_apb_clk",
 			"icp_clk",
 			"icp_clk_src";
 		clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
@@ -884,7 +883,6 @@
 				<&clock_camcc CAM_CC_SOC_AHB_CLK>,
 				<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
 				<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
-				<&clock_camcc CAM_CC_ICP_APB_CLK>,
 				<&clock_camcc CAM_CC_ICP_CLK>,
 				<&clock_camcc CAM_CC_ICP_CLK_SRC>;
 
diff --git a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
index 8323476..f8a8e15 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
@@ -63,6 +63,9 @@
 		clocks = <&clock_aop QDSS_CLK>;
 		clock-names = "apb_pclk";
 
+		interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>;
+		interrupt-names = "byte-cntr-irq";
+
 		port {
 			tmc_etr_in_replicator: endpoint {
 				slave-mode;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index e9924e2..c136752 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -371,4 +371,7 @@
 	xo-therm-mdm-step {
 		status = "disabled";
 	};
+	xo-therm-batt-step {
+		status = "disabled";
+	};
 };
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
index 0a7e25d..5d3975c 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -385,3 +385,63 @@
 	vbus_dwc3-supply = <&smb2_vbus>;
 	qcom,no-vbus-vote-with-type-C;
 };
+
+&thermal_zones {
+	xo-therm-batt-step {
+		polling-delay-passive = <0>;
+		polling-delay = <0>;
+		thermal-sensors = <&pm660_adc_tm 0x4c>;
+		thermal-governor = "step_wise";
+
+		trips {
+			batt_trip1: batt-trip1 {
+				temperature = <40000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+			batt_trip2: batt-trip2 {
+				temperature = <45000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+			batt_trip3: batt-trip3 {
+				temperature = <48000>;
+				hysteresis = <3000>;
+				type = "passive";
+			};
+			batt_trip4: batt-trip4 {
+				temperature = <50000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+			batt_trip5: batt-trip5 {
+				temperature = <52000>;
+				hysteresis = <2000>;
+				type = "passive";
+			};
+		};
+
+		cooling-maps {
+			battery_lvl1 {
+				trip = <&batt_trip1>;
+				cooling-device = <&pm660_charger 1 1>;
+			};
+			battery_lvl2 {
+				trip = <&batt_trip2>;
+				cooling-device = <&pm660_charger 2 2>;
+			};
+			battery_lvl3 {
+				trip = <&batt_trip3>;
+				cooling-device = <&pm660_charger 3 3>;
+			};
+			battery_lvl4 {
+				trip = <&batt_trip4>;
+				cooling-device = <&pm660_charger 4 4>;
+			};
+			battery_lvl5 {
+				trip = <&batt_trip5>;
+				cooling-device = <&pm660_charger 5 5>;
+			};
+		};
+	};
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 3c84314..9898ada 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -459,9 +459,9 @@
 		pm660_l19: regulator-pm660-l19 {
 			regulator-name = "pm660_l19";
 			qcom,set = <RPMH_REGULATOR_SET_ALL>;
-			regulator-min-microvolt = <3312000>;
+			regulator-min-microvolt = <3000000>;
 			regulator-max-microvolt = <3312000>;
-			qcom,init-voltage = <3312000>;
+			qcom,init-voltage = <3000000>;
 			qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
 		};
 	};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
index 6324b64..8cbc84f 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
@@ -1539,7 +1539,7 @@
 				type = "passive";
 			};
 			silver_trip1: silver-trip1 {
-				temperature = <48000>;
+				temperature = <50000>;
 				hysteresis = <0>;
 				type = "passive";
 			};
@@ -1606,7 +1606,7 @@
 			};
 			modem_trip2: modem-trip2 {
 				temperature = <48000>;
-				hysteresis = <2000>;
+				hysteresis = <3000>;
 				type = "passive";
 			};
 			modem_trip3: modem-trip3 {
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 771e599..0b8ddf3 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -488,22 +488,28 @@
 			reg = <0 0x92e00000 0 0x500000>;
 		};
 
-		pil_cdsp_mem: cdsp_regions@93300000 {
+		wlan_msa_mem: wlan_msa_region@93300000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x93300000 0 0x800000>;
+			reg = <0 0x93300000 0 0x100000>;
 		};
 
-		pil_mba_mem: pil_mba_region@0x93b00000 {
+		pil_cdsp_mem: cdsp_regions@93400000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x93b00000 0 0x200000>;
+			reg = <0 0x93400000 0 0x800000>;
 		};
 
-		pil_adsp_mem: pil_adsp_region@93d00000 {
+		pil_mba_mem: pil_mba_region@0x93c00000 {
 			compatible = "removed-dma-pool";
 			no-map;
-			reg = <0 0x93d00000 0 0x1e00000>;
+			reg = <0 0x93c00000 0 0x200000>;
+		};
+
+		pil_adsp_mem: pil_adsp_region@93e00000 {
+			compatible = "removed-dma-pool";
+			no-map;
+			reg = <0 0x93e00000 0 0x1e00000>;
 		};
 
 		adsp_mem: adsp_region {
@@ -565,6 +571,8 @@
 
 #include "sdm670-smp2p.dtsi"
 
+#include "msm-rdbg.dtsi"
+
 #include "sdm670-qupv3.dtsi"
 
 #include "sdm670-coresight.dtsi"
@@ -1034,14 +1042,12 @@
 		compatible = "qcom,clk-cpu-osm-sdm670";
 		reg = <0x17d41000 0x1400>,
 			<0x17d43000 0x1400>,
-			<0x17d45800 0x1400>,
-			<0x784248 0x4>;
-		reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
-				"cpr_rc";
+			<0x17d45800 0x1400>;
+		reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base";
 		vdd_l3_mx_ao-supply = <&pm660l_s1_level_ao>;
 		vdd_pwrcl_mx_ao-supply = <&pm660l_s1_level_ao>;
 
-		qcom,mx-turbo-freq = <1478400000 1689600000 3300000001>;
+		qcom,mx-turbo-freq = <3300000001 3300000001 3300000001>;
 		l3-devs = <&l3_cpu0 &l3_cpu6>;
 
 		clock-names = "xo_ao";
@@ -1110,7 +1116,7 @@
 		reg-names = "wdt-base";
 		interrupts = <0 0 0>, <0 1 0>;
 		qcom,bark-time = <11000>;
-		qcom,pet-time = <10000>;
+		qcom,pet-time = <9360>;
 		qcom,ipi-ping;
 		qcom,wakeup-enable;
 	};
@@ -2471,6 +2477,7 @@
 		vdd-1.8-xo-supply = <&pm660_l9>;
 		vdd-1.3-rfa-supply = <&pm660_l6>;
 		vdd-3.3-ch0-supply = <&pm660_l19>;
+		qcom,vdd-3.3-ch0-config = <3000000 3312000>;
 		qcom,wlan-msa-memory = <0x100000>;
 		qcom,smmu-s1-bypass;
 	};
@@ -2547,6 +2554,16 @@
 			< MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
 	};
 
+	snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive {
+		compatible = "qcom,devbw";
+		governor = "powersave";
+		qcom,src-dst-ports = <139 627>;
+		qcom,active-only;
+		status = "ok";
+		qcom,bw-tbl =
+			< 1 >;
+	};
+
 	devfreq_memlat_0: qcom,cpu0-memlat-mon {
 		compatible = "qcom,arm-memlat-mon";
 		qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 4ecb49a..d12a954 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -515,6 +515,13 @@
 	qcom,mdss-dsi-pan-enable-dynamic-fps;
 	qcom,mdss-dsi-pan-fps-update =
 		"dfps_immediate_porch_mode_vfp";
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9c>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+	qcom,mdss-dsi-panel-status-read-length = <1>;
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
@@ -529,6 +536,13 @@
 &dsi_dual_nt35597_truly_cmd {
 	qcom,mdss-dsi-t-clk-post = <0x0D>;
 	qcom,mdss-dsi-t-clk-pre = <0x2D>;
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9c>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+	qcom,mdss-dsi-panel-status-read-length = <1>;
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
@@ -544,6 +558,13 @@
 	qcom,mdss-dsi-t-clk-post = <0x0b>;
 	qcom,mdss-dsi-t-clk-pre = <0x23>;
 	qcom,ulps-enabled;
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9c>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+	qcom,mdss-dsi-panel-status-read-length = <1>;
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
@@ -564,6 +585,13 @@
 	qcom,mdss-dsi-pan-enable-dynamic-fps;
 	qcom,mdss-dsi-pan-fps-update =
 		"dfps_immediate_porch_mode_vfp";
+	qcom,esd-check-enabled;
+	qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+	qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+	qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+	qcom,mdss-dsi-panel-status-value = <0x9c>;
+	qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+	qcom,mdss-dsi-panel-status-read-length = <1>;
 	qcom,mdss-dsi-display-timings {
 		timing@0{
 			qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 1fcf893..947d28b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -81,12 +81,6 @@
 
 &clock_cpucc {
 	compatible = "qcom,clk-cpu-osm-v2";
-	reg = <0x17d41000 0x1400>,
-		<0x17d43000 0x1400>,
-		<0x17d45800 0x1400>,
-		<0x78425c 0x4>;
-	reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
-							"cpr_rc";
 };
 
 &pcie1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 5b050c5..5b3178d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1229,10 +1229,8 @@
 		compatible = "qcom,clk-cpu-osm";
 		reg = <0x17d41000 0x1400>,
 			<0x17d43000 0x1400>,
-			<0x17d45800 0x1400>,
-			<0x784248 0x4>;
-		reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
-							"cpr_rc";
+			<0x17d45800 0x1400>;
+		reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base";
 		vdd_l3_mx_ao-supply = <&pm8998_s6_level_ao>;
 		vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>;
 
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index db96773..2539aa2 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -26,6 +26,7 @@
 # CONFIG_PID_NS is not set
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_XZ is not set
 # CONFIG_RD_LZO is not set
@@ -65,6 +66,7 @@
 CONFIG_CP15_BARRIER_EMULATION=y
 CONFIG_SETEND_EMULATION=y
 # CONFIG_ARM64_VHE is not set
+CONFIG_RANDOMIZE_BASE=y
 CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_COMPAT=y
@@ -278,6 +280,7 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_QPNP_POWER_ON=y
 CONFIG_INPUT_UINPUT=y
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_VT is not set
@@ -300,10 +303,17 @@
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_RESET_QCOM=y
 CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_RESET_XGENE=y
 CONFIG_POWER_RESET_SYSCON=y
+CONFIG_QPNP_FG=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_QPNP=y
@@ -311,10 +321,16 @@
 CONFIG_THERMAL_TSENS=y
 CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR4_APSS=y
 CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
 CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
@@ -370,7 +386,9 @@
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH=y
 CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
@@ -399,6 +417,8 @@
 CONFIG_REMOTE_SPINLOCK_MSM=y
 CONFIG_MAILBOX=y
 CONFIG_ARM_SMMU=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_QCOM_EUD=y
 CONFIG_QCOM_WATCHDOG_V2=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index d893fd0..52f9976 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -30,6 +30,7 @@
 # CONFIG_PID_NS is not set
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_RD_XZ is not set
 # CONFIG_RD_LZO is not set
@@ -71,6 +72,7 @@
 CONFIG_CP15_BARRIER_EMULATION=y
 CONFIG_SETEND_EMULATION=y
 # CONFIG_ARM64_VHE is not set
+CONFIG_RANDOMIZE_BASE=y
 CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_COMPAT=y
@@ -288,6 +290,7 @@
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_QPNP_POWER_ON=y
 CONFIG_INPUT_UINPUT=y
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_VT is not set
@@ -310,10 +313,17 @@
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
 CONFIG_POWER_RESET_QCOM=y
 CONFIG_QCOM_DLOAD_MODE=y
 CONFIG_POWER_RESET_XGENE=y
 CONFIG_POWER_RESET_SYSCON=y
+CONFIG_QPNP_FG=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_MSM_APM=y
 CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_QPNP=y
@@ -321,10 +331,16 @@
 CONFIG_THERMAL_TSENS=y
 CONFIG_MSM_BCL_PERIPHERAL_CTL=y
 CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_SPMI_PMIC=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR4_APSS=y
 CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
 CONFIG_REGULATOR_QPNP_LABIBB=y
 CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
 CONFIG_REGULATOR_STUB=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_MEDIA_CAMERA_SUPPORT=y
@@ -382,7 +398,9 @@
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH=y
 CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
@@ -413,6 +431,8 @@
 CONFIG_IOMMU_DEBUG=y
 CONFIG_IOMMU_DEBUG_TRACKING=y
 CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
 CONFIG_MSM_BOOT_STATS=y
 CONFIG_MSM_CORE_HANG_DETECT=y
 CONFIG_MSM_GLADIATOR_HANG_DETECT=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 822324d..ab7268f 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -314,6 +314,7 @@
 CONFIG_HW_RANDOM_MSM_LEGACY=y
 # CONFIG_DEVPORT is not set
 CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_QCOM_GENI=y
 CONFIG_SPI=y
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index c1e932d..52710f1 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -779,8 +779,8 @@
 		struct perf_event *event = cpuc->events[idx];
 		struct hw_perf_event *hwc;
 
-		/* Ignore if we don't have an event. */
-		if (!event)
+		/* Ignore if we don't have an event or if it's a zombie event */
+		if (!event || event->state == PERF_EVENT_STATE_ZOMBIE)
 			continue;
 
 		/*
diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c
index 8f0e632..64d7ac7 100644
--- a/drivers/bluetooth/btfm_slim.c
+++ b/drivers/bluetooth/btfm_slim.c
@@ -130,17 +130,25 @@
 	BTFMSLIM_DBG("port: %d ch: %d", ch->port, ch->ch);
 
 	/* Define the channel with below parameters */
-	prop.prot = SLIM_AUTO_ISO;
-	prop.baser = SLIM_RATE_4000HZ;
-	prop.dataf = (rates == 48000) ? SLIM_CH_DATAF_NOT_DEFINED
-			: SLIM_CH_DATAF_LPCM_AUDIO;
+	prop.prot =  SLIM_AUTO_ISO;
+	prop.baser = ((rates == 44100) || (rates == 88200)) ?
+			SLIM_RATE_11025HZ : SLIM_RATE_4000HZ;
+	prop.dataf = ((rates == 48000) || (rates == 44100) ||
+		(rates == 88200) || (rates == 96000)) ?
+			SLIM_CH_DATAF_NOT_DEFINED : SLIM_CH_DATAF_LPCM_AUDIO;
 	prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
-	prop.ratem = (rates/4000);
+	prop.ratem = ((rates == 44100) || (rates == 88200)) ?
+		(rates/11025) : (rates/4000);
 	prop.sampleszbits = 16;
 
 	ch_h[0] = ch->ch_hdl;
 	ch_h[1] = (grp) ? (ch+1)->ch_hdl : 0;
 
+	BTFMSLIM_INFO("channel define - prot:%d, dataf:%d, auxf:%d",
+			prop.prot, prop.dataf, prop.auxf);
+	BTFMSLIM_INFO("channel define - rates:%d, baser:%d, ratem:%d",
+			rates, prop.baser, prop.ratem);
+
 	ret = slim_define_ch(btfmslim->slim_pgd, &prop, ch_h, nchan, grp,
 			&ch->grph);
 	if (ret < 0) {
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index 309648f..53388ed 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -385,10 +385,12 @@
 		.id = BTFM_BT_SCO_A2DP_SLIM_RX,
 		.playback = {
 			.stream_name = "SCO A2DP RX Playback",
+			/* 8/16/44.1/48/88.2/96 Khz */
 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000
-				| SNDRV_PCM_RATE_48000, /* 8 or 16 or 48 Khz*/
+				| SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000
+				| SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */
-			.rate_max = 48000,
+			.rate_max = 96000,
 			.rate_min = 8000,
 			.channels_min = 1,
 			.channels_max = 1,
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index f0a6d9e..2dbba83 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -83,22 +83,31 @@
 {
 	int ret = 0;
 	uint8_t reg_val = 0, en;
-	uint8_t port_bit = 0;
+	uint8_t rxport_num = 0;
 	uint16_t reg;
 
 	BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
 	if (rxport) {
 		if (enable) {
 			/* For SCO Rx, A2DP Rx */
-			reg_val = 0x1;
-			port_bit = port_num - 0x10;
-			reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(port_bit);
+			if (port_num < 24) {
+				rxport_num = port_num - 16;
+				reg_val = 0x01 << rxport_num;
+				reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_0(
+					rxport_num);
+			} else {
+				rxport_num = port_num - 24;
+				reg_val = 0x01 << rxport_num;
+				reg = CHRK_SB_PGD_RX_PORTn_MULTI_CHNL_1(
+					rxport_num);
+			}
+
 			BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
-					reg_val, reg);
+				reg_val, reg);
 			ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
 			if (ret) {
 				BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
-						ret, reg);
+					ret, reg);
 				goto error;
 			}
 		}
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 35eea02..8a28212 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -238,13 +238,13 @@
 	int ramdumpenabled;
 	void *remoteheap_ramdump_dev;
 	struct fastrpc_glink_info link;
-	struct mutex mut;
 };
 
 struct fastrpc_apps {
 	struct fastrpc_channel_ctx *channel;
 	struct cdev cdev;
 	struct class *class;
+	struct mutex smd_mutex;
 	struct smq_phy_page range;
 	struct hlist_head maps;
 	uint32_t staticpd_flags;
@@ -654,10 +654,6 @@
 		if (err)
 			goto bail;
 
-		map->uncached = !ION_IS_CACHED(flags);
-		if (map->attr & FASTRPC_ATTR_NOVA)
-			map->uncached = 1;
-
 		map->secure = flags & ION_FLAG_SECURE;
 		if (map->secure) {
 			if (!fl->secsctx)
@@ -670,9 +666,15 @@
 			sess = fl->secsctx;
 		else
 			sess = fl->sctx;
+
 		VERIFY(err, !IS_ERR_OR_NULL(sess));
 		if (err)
 			goto bail;
+
+		map->uncached = !ION_IS_CACHED(flags);
+		if (map->attr & FASTRPC_ATTR_NOVA && !sess->smmu.coherent)
+			map->uncached = 1;
+
 		VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd)));
 		if (err)
 			goto bail;
@@ -1496,12 +1498,12 @@
 
 	INIT_HLIST_HEAD(&me->drivers);
 	spin_lock_init(&me->hlock);
+	mutex_init(&me->smd_mutex);
 	me->channel = &gcinfo[0];
 	for (i = 0; i < NUM_CHANNELS; i++) {
 		init_completion(&me->channel[i].work);
 		init_completion(&me->channel[i].workport);
 		me->channel[i].sesscount = 0;
-		mutex_init(&me->channel[i].mut);
 	}
 }
 
@@ -1619,7 +1621,7 @@
 	int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
 	int hlosVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
 
-	VERIFY(err, !fastrpc_channel_open(fl));
+	VERIFY(err, 0 == (err = fastrpc_channel_open(fl)));
 	if (err)
 		goto bail;
 	if (init->flags == FASTRPC_INIT_ATTACH) {
@@ -2122,7 +2124,7 @@
 	ctx->chan = NULL;
 	glink_unregister_link_state_cb(ctx->link.link_notify_handle);
 	ctx->link.link_notify_handle = NULL;
-	mutex_unlock(&ctx->mut);
+	mutex_unlock(&me->smd_mutex);
 	pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name,
 						MAJOR(me->dev_no), cid);
 }
@@ -2215,15 +2217,6 @@
 		link->port_state = FASTRPC_LINK_DISCONNECTED;
 		break;
 	case GLINK_REMOTE_DISCONNECTED:
-		mutex_lock(&me->channel[cid].mut);
-		if (me->channel[cid].chan) {
-			link->port_state = FASTRPC_LINK_REMOTE_DISCONNECTING;
-			fastrpc_glink_close(me->channel[cid].chan, cid);
-			me->channel[cid].chan = NULL;
-		} else {
-			link->port_state = FASTRPC_LINK_DISCONNECTED;
-		}
-		mutex_unlock(&me->channel[cid].mut);
 		break;
 	default:
 		break;
@@ -2234,20 +2227,23 @@
 					struct fastrpc_session_ctx **session)
 {
 	int err = 0;
+	struct fastrpc_apps *me = &gfa;
 
-	mutex_lock(&chan->mut);
+	mutex_lock(&me->smd_mutex);
 	if (!*session)
 		err = fastrpc_session_alloc_locked(chan, secure, session);
-	mutex_unlock(&chan->mut);
+	mutex_unlock(&me->smd_mutex);
 	return err;
 }
 
 static void fastrpc_session_free(struct fastrpc_channel_ctx *chan,
 				struct fastrpc_session_ctx *session)
 {
-	mutex_lock(&chan->mut);
+	struct fastrpc_apps *me = &gfa;
+
+	mutex_lock(&me->smd_mutex);
 	session->used = 0;
-	mutex_unlock(&chan->mut);
+	mutex_unlock(&me->smd_mutex);
 }
 
 static int fastrpc_file_free(struct fastrpc_file *fl)
@@ -2280,7 +2276,7 @@
 	}
 	if (fl->ssrcount == fl->apps->channel[cid].ssrcount)
 		kref_put_mutex(&fl->apps->channel[cid].kref,
-			fastrpc_channel_close, &fl->apps->channel[cid].mut);
+				fastrpc_channel_close, &fl->apps->smd_mutex);
 	if (fl->sctx)
 		fastrpc_session_free(&fl->apps->channel[cid], fl->sctx);
 	if (fl->secsctx)
@@ -2357,20 +2353,6 @@
 	return err;
 }
 
-static void fastrpc_glink_stop(int cid)
-{
-	int err = 0;
-	struct fastrpc_glink_info *link;
-
-	VERIFY(err, (cid >= 0 && cid < NUM_CHANNELS));
-	if (err)
-		return;
-	link = &gfa.channel[cid].link;
-
-	if (link->port_state == FASTRPC_LINK_CONNECTED)
-		link->port_state = FASTRPC_LINK_REMOTE_DISCONNECTING;
-}
-
 static void fastrpc_glink_close(void *chan, int cid)
 {
 	int err = 0;
@@ -2548,20 +2530,23 @@
 	struct fastrpc_apps *me = &gfa;
 	int cid, err = 0;
 
+	mutex_lock(&me->smd_mutex);
+
 	VERIFY(err, fl && fl->sctx);
 	if (err)
-		return err;
+		goto bail;
 	cid = fl->cid;
 	VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
 	if (err)
 		goto bail;
-	mutex_lock(&me->channel[cid].mut);
 	if (me->channel[cid].ssrcount !=
 				 me->channel[cid].prevssrcount) {
 		if (!me->channel[cid].issubsystemup) {
 			VERIFY(err, 0);
-			if (err)
+			if (err) {
+				err = -ENOTCONN;
 				goto bail;
+			}
 		}
 	}
 	fl->ssrcount = me->channel[cid].ssrcount;
@@ -2574,11 +2559,9 @@
 		if (err)
 			goto bail;
 
-		mutex_unlock(&me->channel[cid].mut);
 		VERIFY(err,
 			 wait_for_completion_timeout(&me->channel[cid].workport,
 						RPC_TIMEOUT));
-		mutex_lock(&me->channel[cid].mut);
 		if (err) {
 			me->channel[cid].chan = NULL;
 			goto bail;
@@ -2603,7 +2586,7 @@
 	}
 
 bail:
-	mutex_unlock(&me->channel[cid].mut);
+	mutex_unlock(&me->smd_mutex);
 	return err;
 }
 
@@ -2866,7 +2849,7 @@
 			p.init.init.memlen < INIT_MEMLEN_MAX);
 		if (err)
 			goto bail;
-		VERIFY(err, 0 == fastrpc_init_process(fl, &p.init));
+		VERIFY(err, 0 == (err = fastrpc_init_process(fl, &p.init)));
 		if (err)
 			goto bail;
 		break;
@@ -2892,14 +2875,16 @@
 	ctx = container_of(nb, struct fastrpc_channel_ctx, nb);
 	cid = ctx - &me->channel[0];
 	if (code == SUBSYS_BEFORE_SHUTDOWN) {
-		mutex_lock(&ctx->mut);
+		mutex_lock(&me->smd_mutex);
 		ctx->ssrcount++;
 		ctx->issubsystemup = 0;
-		pr_info("'restart notifier: /dev/%s c %d %d'\n",
-			 gcinfo[cid].name, MAJOR(me->dev_no), cid);
-		if (ctx->chan)
-			fastrpc_glink_stop(cid);
-		mutex_unlock(&ctx->mut);
+		if (ctx->chan) {
+			fastrpc_glink_close(ctx->chan, cid);
+			ctx->chan = NULL;
+			pr_info("'restart notifier: closed /dev/%s c %d %d'\n",
+				 gcinfo[cid].name, MAJOR(me->dev_no), cid);
+		}
+		mutex_unlock(&me->smd_mutex);
 		if (cid == 0)
 			me->staticpd_flags = 0;
 		fastrpc_notify_drivers(me, cid);
@@ -3071,15 +3056,15 @@
 
 static void fastrpc_deinit(void)
 {
+	struct fastrpc_apps *me = &gfa;
 	struct fastrpc_channel_ctx *chan = gcinfo;
 	int i, j;
 
 	for (i = 0; i < NUM_CHANNELS; i++, chan++) {
 		if (chan->chan) {
 			kref_put_mutex(&chan->kref,
-				fastrpc_channel_close, &chan->mut);
+				fastrpc_channel_close, &me->smd_mutex);
 			chan->chan = NULL;
-			mutex_destroy(&chan->mut);
 		}
 		for (j = 0; j < NUM_SESSIONS; j++) {
 			struct fastrpc_session_ctx *sess = &chan->session[j];
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index da13912..f157a2f 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1687,10 +1687,10 @@
 		break;
 	case TYPE_CMD:
 		if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) {
-			diagfwd_write_done(peripheral, type, num);
 			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
 			"Marking buffer as free after write done p: %d, t: %d, buf_num: %d\n",
 				peripheral, type, num);
+			diagfwd_write_done(peripheral, type, num);
 		}
 		if (peripheral == APPS_DATA ||
 				ctxt == DIAG_MEMORY_DEVICE_MODE) {
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 4d6ae23..c7bd2205 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -205,7 +205,8 @@
 		}
 
 		if (buf->len < max_size) {
-			if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) {
+			if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
+				driver->logging_mode == DIAG_MULTI_MODE) {
 				ch = &diag_md[DIAG_LOCAL_PROC];
 				for (i = 0; ch != NULL &&
 						i < ch->num_tbl_entries; i++) {
@@ -478,7 +479,8 @@
 			flag_buf_1 = 1;
 			temp_fwdinfo_cpd = fwd_info->buf_1;
 			if (fwd_info->type == TYPE_DATA) {
-				for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+				for (i = 0; (i <= (fwd_info->num_pd - 2)) &&
+					fwd_info->buf_upd[i][0]; i++)
 					temp_buf_upd[i] =
 					fwd_info->buf_upd[i][0]->data_raw;
 			}
@@ -487,7 +489,8 @@
 			flag_buf_2 = 1;
 			temp_fwdinfo_cpd = fwd_info->buf_2;
 			if (fwd_info->type == TYPE_DATA) {
-				for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+				for (i = 0; (i <= (fwd_info->num_pd - 2)) &&
+					fwd_info->buf_upd[i][1]; i++)
 					temp_buf_upd[i] =
 					fwd_info->buf_upd[i][1]->data_raw;
 			}
@@ -557,6 +560,8 @@
 				else
 					temp_fwdinfo_upd =
 						fwd_info->buf_upd[i][1];
+				if (!temp_fwdinfo_upd)
+					break;
 				temp_fwdinfo_upd->ctxt &= 0x00FFFFFF;
 				temp_fwdinfo_upd->ctxt |=
 					(SET_PD_CTXT(ctxt_upd[i]));
@@ -1631,6 +1636,10 @@
 fail_return:
 	diag_ws_release();
 	atomic_set(&temp_buf->in_busy, 0);
+	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+	"Buffer for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
+		fwd_info->peripheral, fwd_info->type,
+		GET_BUF_NUM(temp_buf->ctxt));
 }
 
 static void diagfwd_queue_read(struct diagfwd_info *fwd_info)
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index bf9b99d..514c0ad 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -401,8 +401,8 @@
 {
 	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
 	const struct pll_vco *vco;
-	u32 l, off = pll->offset;
-	u64 a;
+	u32 l = 0, off = pll->offset;
+	u64 a = 0;
 
 	rate = alpha_pll_round_rate(pll, rate, prate, &l, &a);
 	vco = alpha_pll_find_vco(pll, rate);
@@ -668,9 +668,9 @@
 {
 	struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
 	unsigned long rrate;
-	u32 regval, l, off = pll->offset;
-	u64 a;
-	int ret;
+	u32 regval = 0, l = 0, off = pll->offset;
+	u64 a = 0;
+	int ret = 0;
 
 	ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &regval);
 	if (ret)
@@ -1146,8 +1146,8 @@
 	unsigned long rrate;
 	bool is_enabled;
 	int ret;
-	u32 l, val, off = pll->offset;
-	u64 a;
+	u32 l = 0, val = 0, off = pll->offset;
+	u64 a = 0;
 
 	rrate = alpha_pll_round_rate(pll, rate, prate, &l, &a);
 	/*
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index fb0b504..b6204cb 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -55,9 +55,6 @@
 #define VOLT_REG			0x114
 #define CORE_DCVS_CTRL			0xbc
 
-#define EFUSE_SHIFT(v1)			((v1) ? 3 : 2)
-#define EFUSE_MASK			0x7
-
 #define DCVS_PERF_STATE_DESIRED_REG_0_V1	0x780
 #define DCVS_PERF_STATE_DESIRED_REG_0_V2	0x920
 #define DCVS_PERF_STATE_DESIRED_REG(n, v1) \
@@ -77,6 +74,7 @@
 	u16 virtual_corner;
 	u16 open_loop_volt;
 	long frequency;
+	u16 ccount;
 };
 
 struct clk_osm {
@@ -90,11 +88,11 @@
 	u32 num_entries;
 	u32 cluster_num;
 	u32 core_num;
+	unsigned long rate;
 	u64 total_cycle_counter;
 	u32 prev_cycle_counter;
 	u32 max_core_count;
 	u32 mx_turbo_freq;
-	unsigned int cpr_rc;
 };
 
 static bool is_sdm845v1;
@@ -153,6 +151,24 @@
 	return -EINVAL;
 }
 
+static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct clk_osm *c = to_clk_osm(hw);
+
+	c->rate = rate;
+
+	return 0;
+}
+
+static unsigned long clk_osm_recalc_rate(struct clk_hw *hw,
+				unsigned long parent_rate)
+{
+	struct clk_osm *c = to_clk_osm(hw);
+
+	return c->rate;
+}
+
 static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate,
 				unsigned long *parent_rate)
 {
@@ -294,7 +310,7 @@
 	return cpuclk->osm_table[index].frequency;
 }
 
-static struct clk_ops clk_ops_l3_osm = {
+static const struct clk_ops clk_ops_l3_osm = {
 	.round_rate = clk_osm_round_rate,
 	.list_rate = clk_osm_list_rate,
 	.recalc_rate = l3_clk_recalc_rate,
@@ -302,8 +318,20 @@
 	.debug_init = clk_debug_measure_add,
 };
 
-static struct clk_ops clk_ops_core;
-static struct clk_ops clk_ops_cpu_osm;
+static const struct clk_ops clk_ops_core = {
+	.set_rate = clk_cpu_set_rate,
+	.round_rate = clk_cpu_round_rate,
+	.recalc_rate = clk_cpu_recalc_rate,
+	.debug_init = clk_debug_measure_add,
+};
+
+static const struct clk_ops clk_ops_cpu_osm = {
+	.set_rate = clk_osm_set_rate,
+	.round_rate = clk_osm_round_rate,
+	.recalc_rate = clk_osm_recalc_rate,
+	.list_rate = clk_osm_list_rate,
+	.debug_init = clk_debug_measure_add,
+};
 
 static struct clk_init_data osm_clks_init[] = {
 	[0] = {
@@ -639,7 +667,7 @@
 	struct clk_osm *c, *parent;
 	struct clk_hw *p_hw;
 	int ret;
-	unsigned int i;
+	unsigned int i, prev_cc = 0;
 	unsigned int xo_kHz;
 
 	c = osm_configure_policy(policy);
@@ -686,8 +714,12 @@
 		if (core_count != parent->max_core_count)
 			table[i].frequency = CPUFREQ_ENTRY_INVALID;
 
-		/* Two of the same frequencies means end of table */
-		if (i > 0 && table[i - 1].driver_data == table[i].driver_data) {
+		/*
+		 * Two of the same frequencies with the same core counts means
+		 * end of table.
+		 */
+		if (i > 0 && table[i - 1].driver_data == table[i].driver_data
+					&& prev_cc == core_count) {
 			struct cpufreq_frequency_table *prev = &table[i - 1];
 
 			if (prev->frequency == CPUFREQ_ENTRY_INVALID) {
@@ -697,6 +729,7 @@
 
 			break;
 		}
+		prev_cc = core_count;
 	}
 	table[i].frequency = CPUFREQ_TABLE_END;
 
@@ -940,6 +973,7 @@
 		data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE);
 		src = ((data & GENMASK(31, 30)) >> 30);
 		lval = (data & GENMASK(7, 0));
+		c->osm_table[i].ccount = CORE_COUNT_VAL(data);
 
 		if (!src)
 			c->osm_table[i].frequency = OSM_INIT_RATE;
@@ -956,8 +990,10 @@
 			 c->osm_table[i].virtual_corner,
 			 c->osm_table[i].open_loop_volt);
 
-		if (i > 0 && j == OSM_TABLE_SIZE && c->osm_table[i].frequency ==
-					c->osm_table[i - 1].frequency)
+		if (i > 0 && j == OSM_TABLE_SIZE &&
+				c->osm_table[i].frequency ==
+					c->osm_table[i - 1].frequency &&
+			c->osm_table[i].ccount == c->osm_table[i - 1].ccount)
 			j = i;
 	}
 
@@ -979,8 +1015,7 @@
 			return -ENOMEM;
 
 		for (i = 0; i < j; i++) {
-			if (c->osm_table[i].frequency < c->mx_turbo_freq ||
-								(c->cpr_rc > 1))
+			if (c->osm_table[i].frequency < c->mx_turbo_freq)
 				vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_NOM;
 			else
 				vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_TURBO;
@@ -1071,19 +1106,68 @@
 	perfcl_clk.max_core_count = 2;
 }
 
+/* Request MX supply if configured in device tree */
+static int clk_cpu_osm_request_mx_supply(struct device *dev)
+{
+	u32 *array;
+	int rc;
+
+	if (!of_find_property(dev->of_node, "qcom,mx-turbo-freq", NULL)) {
+		osm_clks_init[l3_clk.cluster_num].vdd_class = NULL;
+		osm_clks_init[pwrcl_clk.cluster_num].vdd_class = NULL;
+		return 0;
+	}
+
+	vdd_l3_mx_ao.regulator[0] = devm_regulator_get(dev, "vdd_l3_mx_ao");
+	if (IS_ERR(vdd_l3_mx_ao.regulator[0])) {
+		rc = PTR_ERR(vdd_l3_mx_ao.regulator[0]);
+		if (rc != -EPROBE_DEFER)
+			dev_err(dev, "Unable to get vdd_l3_mx_ao regulator, rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	vdd_pwrcl_mx_ao.regulator[0] = devm_regulator_get(dev,
+							"vdd_pwrcl_mx_ao");
+	if (IS_ERR(vdd_pwrcl_mx_ao.regulator[0])) {
+		rc = PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]);
+		if (rc != -EPROBE_DEFER)
+			dev_err(dev, "Unable to get vdd_pwrcl_mx_ao regulator, rc=%d\n",
+				rc);
+		return rc;
+	}
+
+	array = kcalloc(MAX_CLUSTER_CNT, sizeof(*array), GFP_KERNEL);
+	if (!array)
+		return -ENOMEM;
+
+	rc = of_property_read_u32_array(dev->of_node, "qcom,mx-turbo-freq",
+					array, MAX_CLUSTER_CNT);
+	if (rc) {
+		dev_err(dev, "unable to read qcom,mx-turbo-freq property, rc=%d\n",
+			rc);
+		kfree(array);
+		return rc;
+	}
+
+	l3_clk.mx_turbo_freq = array[l3_clk.cluster_num];
+	pwrcl_clk.mx_turbo_freq = array[pwrcl_clk.cluster_num];
+	perfcl_clk.mx_turbo_freq = array[perfcl_clk.cluster_num];
+
+	kfree(array);
+
+	return 0;
+}
+
 static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
 {
 	int rc = 0, i, cpu;
-	bool is_sdm670 = false;
-	u32 *array;
-	u32 val, pte_efuse;
-	void __iomem *vbase;
+	u32 val;
 	int num_clks = ARRAY_SIZE(osm_qcom_clk_hws);
 	struct clk *ext_xo_clk, *clk;
 	struct clk_osm *osm_clk;
 	struct device *dev = &pdev->dev;
 	struct clk_onecell_data *clk_data;
-	struct resource *res;
 	struct cpu_cycle_counter_cb cb = {
 		.get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter,
 	};
@@ -1103,68 +1187,12 @@
 					"qcom,clk-cpu-osm");
 
 	if (of_device_is_compatible(pdev->dev.of_node,
-					 "qcom,clk-cpu-osm-sdm670")) {
-		is_sdm670 = true;
+					 "qcom,clk-cpu-osm-sdm670"))
 		clk_cpu_osm_driver_sdm670_fixup();
-	}
 
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cpr_rc");
-	if (res) {
-		vbase = devm_ioremap(&pdev->dev, res->start,
-						resource_size(res));
-		if (!vbase) {
-			dev_err(&pdev->dev, "Unable to map in cpr_rc base\n");
-			return -ENOMEM;
-		}
-		pte_efuse = readl_relaxed(vbase);
-		l3_clk.cpr_rc = pwrcl_clk.cpr_rc = perfcl_clk.cpr_rc =
-			((pte_efuse >> EFUSE_SHIFT(is_sdm845v1 | is_sdm670))
-							& EFUSE_MASK);
-		pr_info("LOCAL_CPR_RC: %u\n", l3_clk.cpr_rc);
-		devm_iounmap(&pdev->dev, vbase);
-	} else {
-		dev_err(&pdev->dev,
-			"Unable to get platform resource for cpr_rc\n");
-		return -ENOMEM;
-	}
-
-	vdd_l3_mx_ao.regulator[0] = devm_regulator_get(&pdev->dev,
-						"vdd_l3_mx_ao");
-	if (IS_ERR(vdd_l3_mx_ao.regulator[0])) {
-		if (PTR_ERR(vdd_l3_mx_ao.regulator[0]) != -EPROBE_DEFER)
-			dev_err(&pdev->dev,
-				"Unable to get vdd_l3_mx_ao regulator\n");
-		return PTR_ERR(vdd_l3_mx_ao.regulator[0]);
-	}
-
-	vdd_pwrcl_mx_ao.regulator[0] = devm_regulator_get(&pdev->dev,
-						"vdd_pwrcl_mx_ao");
-	if (IS_ERR(vdd_pwrcl_mx_ao.regulator[0])) {
-		if (PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]) != -EPROBE_DEFER)
-			dev_err(&pdev->dev,
-				"Unable to get vdd_pwrcl_mx_ao regulator\n");
-		return PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]);
-	}
-
-	array = devm_kcalloc(&pdev->dev, MAX_CLUSTER_CNT, sizeof(*array),
-							GFP_KERNEL);
-	if (!array)
-		return -ENOMEM;
-
-	rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,mx-turbo-freq",
-							array, MAX_CLUSTER_CNT);
-	if (rc) {
-		dev_err(&pdev->dev, "unable to find qcom,mx-turbo-freq property, rc=%d\n",
-							rc);
-		devm_kfree(&pdev->dev, array);
+	rc = clk_cpu_osm_request_mx_supply(dev);
+	if (rc)
 		return rc;
-	}
-
-	l3_clk.mx_turbo_freq = array[l3_clk.cluster_num];
-	pwrcl_clk.mx_turbo_freq = array[pwrcl_clk.cluster_num];
-	perfcl_clk.mx_turbo_freq = array[perfcl_clk.cluster_num];
-
-	devm_kfree(&pdev->dev, array);
 
 	clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
 								GFP_KERNEL);
@@ -1220,16 +1248,6 @@
 	spin_lock_init(&pwrcl_clk.lock);
 	spin_lock_init(&perfcl_clk.lock);
 
-	clk_ops_core = clk_dummy_ops;
-	clk_ops_core.set_rate = clk_cpu_set_rate;
-	clk_ops_core.round_rate = clk_cpu_round_rate;
-	clk_ops_core.recalc_rate = clk_cpu_recalc_rate;
-
-	clk_ops_cpu_osm = clk_dummy_ops;
-	clk_ops_cpu_osm.round_rate = clk_osm_round_rate;
-	clk_ops_cpu_osm.list_rate = clk_osm_list_rate;
-	clk_ops_cpu_osm.debug_init = clk_debug_measure_add;
-
 	/* Register OSM l3, pwr and perf clocks with Clock Framework */
 	for (i = 0; i < num_clks; i++) {
 		if (!osm_qcom_clk_hws[i])
diff --git a/drivers/clk/qcom/gcc-sdxpoorwills.c b/drivers/clk/qcom/gcc-sdxpoorwills.c
index 1b5cf61..a62a9a8 100644
--- a/drivers/clk/qcom/gcc-sdxpoorwills.c
+++ b/drivers/clk/qcom/gcc-sdxpoorwills.c
@@ -1353,6 +1353,19 @@
 	},
 };
 
+static struct clk_branch gcc_pcie_0_clkref_clk = {
+	.halt_reg = 0x88004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x88004,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_pcie_0_clkref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
 static struct clk_branch gcc_pcie_aux_clk = {
 	.halt_reg = 0x37020,
 	.halt_check = BRANCH_HALT_VOTED,
@@ -1695,14 +1708,26 @@
 	},
 };
 
-static struct clk_branch gcc_usb3_phy_pipe_clk = {
-	.halt_reg = 0xb054,
-	.halt_check = BRANCH_HALT,
+static struct clk_gate2 gcc_usb3_phy_pipe_clk = {
+	.udelay = 500,
 	.clkr = {
 		.enable_reg = 0xb054,
 		.enable_mask = BIT(0),
 		.hw.init = &(struct clk_init_data){
 			.name = "gcc_usb3_phy_pipe_clk",
+			.ops = &clk_gate2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_usb3_prim_clkref_clk = {
+	.halt_reg = 0x88000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x88000,
+		.enable_mask = BIT(0),
+		.hw.init = &(struct clk_init_data){
+			.name = "gcc_usb3_prim_clkref_clk",
 			.ops = &clk_branch2_ops,
 		},
 	},
@@ -1782,6 +1807,7 @@
 	[GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
 	[GCC_MSS_GPLL0_DIV_CLK_SRC] = &gcc_mss_gpll0_div_clk_src.clkr,
 	[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
+	[GCC_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.clkr,
 	[GCC_PCIE_AUX_CLK] = &gcc_pcie_aux_clk.clkr,
 	[GCC_PCIE_AUX_PHY_CLK_SRC] = &gcc_pcie_aux_phy_clk_src.clkr,
 	[GCC_PCIE_CFG_AHB_CLK] = &gcc_pcie_cfg_ahb_clk.clkr,
@@ -1813,6 +1839,7 @@
 	[GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
 	[GCC_USB3_PHY_AUX_CLK_SRC] = &gcc_usb3_phy_aux_clk_src.clkr,
 	[GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+	[GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr,
 	[GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
 	[GPLL0] = &gpll0.clkr,
 	[GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
@@ -1837,6 +1864,8 @@
 	[GCC_SDCC1_BCR] = { 0xf000 },
 	[GCC_SPMI_FETCHER_BCR] = { 0x3f000 },
 	[GCC_USB30_BCR] = { 0xb000 },
+	[GCC_USB3_PHY_BCR] = { 0xc000 },
+	[GCC_USB3PHY_PHY_BCR] = { 0xc004 },
 	[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 },
 };
 
@@ -1903,7 +1932,7 @@
 {
 	return platform_driver_register(&gcc_sdxpoorwills_driver);
 }
-core_initcall(gcc_sdxpoorwills_init);
+subsys_initcall(gcc_sdxpoorwills_init);
 
 static void __exit gcc_sdxpoorwills_exit(void)
 {
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index dd02a8f..3f9fcd9 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -33,24 +33,52 @@
 /* Register Offsets from PLL base address */
 #define PLL_ANALOG_CONTROLS_ONE			0x000
 #define PLL_ANALOG_CONTROLS_TWO			0x004
+#define PLL_INT_LOOP_SETTINGS			0x008
+#define PLL_INT_LOOP_SETTINGS_TWO		0x00c
 #define PLL_ANALOG_CONTROLS_THREE		0x010
+#define PLL_ANALOG_CONTROLS_FOUR		0x014
+#define PLL_INT_LOOP_CONTROLS			0x018
 #define PLL_DSM_DIVIDER				0x01c
 #define PLL_FEEDBACK_DIVIDER			0x020
 #define PLL_SYSTEM_MUXES			0x024
+#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES	0x028
 #define PLL_CMODE				0x02c
 #define PLL_CALIBRATION_SETTINGS		0x030
+#define PLL_BAND_SEL_CAL_TIMER_LOW		0x034
+#define PLL_BAND_SEL_CAL_TIMER_HIGH		0x038
+#define PLL_BAND_SEL_CAL_SETTINGS		0x03c
+#define PLL_BAND_SEL_MIN			0x040
+#define PLL_BAND_SEL_MAX			0x044
+#define PLL_BAND_SEL_PFILT			0x048
+#define PLL_BAND_SEL_IFILT			0x04c
+#define PLL_BAND_SEL_CAL_SETTINGS_TWO		0x050
 #define PLL_BAND_SEL_CAL_SETTINGS_THREE		0x054
+#define PLL_BAND_SEL_CAL_SETTINGS_FOUR		0x058
+#define PLL_BAND_SEL_ICODE_HIGH			0x05c
+#define PLL_BAND_SEL_ICODE_LOW			0x060
 #define PLL_FREQ_DETECT_SETTINGS_ONE		0x064
 #define PLL_PFILT				0x07c
 #define PLL_IFILT				0x080
+#define PLL_GAIN				0x084
+#define PLL_ICODE_LOW				0x088
+#define PLL_ICODE_HIGH				0x08c
+#define PLL_LOCKDET				0x090
 #define PLL_OUTDIV				0x094
+#define PLL_FASTLOCK_CONTROL			0x098
+#define PLL_PASS_OUT_OVERRIDE_ONE		0x09c
+#define PLL_PASS_OUT_OVERRIDE_TWO		0x0a0
 #define PLL_CORE_OVERRIDE			0x0a4
 #define PLL_CORE_INPUT_OVERRIDE			0x0a8
+#define PLL_RATE_CHANGE				0x0ac
+#define PLL_PLL_DIGITAL_TIMERS			0x0b0
 #define PLL_PLL_DIGITAL_TIMERS_TWO		0x0b4
+#define PLL_DEC_FRAC_MUXES			0x0c8
 #define PLL_DECIMAL_DIV_START_1			0x0cc
 #define PLL_FRAC_DIV_START_LOW_1		0x0d0
 #define PLL_FRAC_DIV_START_MID_1		0x0d4
 #define PLL_FRAC_DIV_START_HIGH_1		0x0d8
+#define PLL_MASH_CONTROL			0x0ec
+#define PLL_SSC_MUX_CONTROL			0x108
 #define PLL_SSC_STEPSIZE_LOW_1			0x10c
 #define PLL_SSC_STEPSIZE_HIGH_1			0x110
 #define PLL_SSC_DIV_PER_LOW_1			0x114
@@ -64,9 +92,16 @@
 #define PLL_PLL_BAND_SET_RATE_1			0x154
 #define PLL_PLL_INT_GAIN_IFILT_BAND_1		0x15c
 #define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1	0x164
+#define PLL_FASTLOCK_EN_BAND			0x16c
+#define PLL_FREQ_TUNE_ACCUM_INIT_MUX		0x17c
 #define PLL_PLL_LOCK_OVERRIDE			0x180
 #define PLL_PLL_LOCK_DELAY			0x184
+#define PLL_PLL_LOCK_MIN_DELAY			0x188
 #define PLL_CLOCK_INVERTERS			0x18c
+#define PLL_SPARE_AND_JPC_OVERRIDES		0x190
+#define PLL_BIAS_CONTROL_1			0x194
+#define PLL_BIAS_CONTROL_2			0x198
+#define PLL_ALOG_OBSV_BUS_CTRL_1		0x19c
 #define PLL_COMMON_STATUS_ONE			0x1a0
 
 /* Register Offsets from PHY base address */
@@ -249,7 +284,7 @@
 	if (rc)
 		pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
 	else
-		*val = (MDSS_PLL_REG_R(rsc->pll_base, reg) & 0x3);
+		*val = (MDSS_PLL_REG_R(rsc->phy_base, reg) & 0x3);
 
 	(void)mdss_pll_resource_enable(rsc, false);
 	return rc;
@@ -503,6 +538,49 @@
 	MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f);
 }
 
+static void dsi_pll_init_val(struct mdss_pll_resources *rsc)
+{
+	void __iomem *pll_base = rsc->pll_base;
+
+	MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x10);
+	MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x3f);
+	MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x80);
+	MDSS_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x02);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x82);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0xff);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x00);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x25);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x4f);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0a);
+	MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_GAIN, 0x42);
+	MDSS_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00);
+	MDSS_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00);
+	MDSS_PLL_REG_W(pll_base, PLL_LOCKDET, 0x30);
+	MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x04);
+	MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00);
+	MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00);
+	MDSS_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x01);
+	MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x08);
+	MDSS_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00);
+	MDSS_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x03);
+	MDSS_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_EN_BAND, 0x03);
+	MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x19);
+	MDSS_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x0);
+	MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x40);
+	MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x20);
+	MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x0);
+}
+
 static void dsi_pll_commit(struct dsi_pll_10nm *pll,
 			   struct mdss_pll_resources *rsc)
 {
@@ -559,6 +637,8 @@
 		return rc;
 	}
 
+	dsi_pll_init_val(rsc);
+
 	dsi_pll_setup_config(pll, rsc);
 
 	dsi_pll_calc_dec_frac(pll, rsc);
@@ -741,12 +821,32 @@
 		pr_err("dsi pll resources not available\n");
 		return;
 	}
-	pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
-	pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE);
-	pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0,
-			pll->cached_cfg1, pll->cached_outdiv);
 
-	pll->vco_cached_rate = clk_hw_get_rate(hw);
+	/*
+	 * During unprepare in continuous splash use case we want driver
+	 * to pick all dividers instead of retaining bootloader configurations.
+	 */
+	if (!pll->handoff_resources) {
+		pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base,
+							PHY_CMN_CLK_CFG0);
+		pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base,
+							PLL_PLL_OUTDIV_RATE);
+		pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0,
+					pll->cached_cfg1, pll->cached_outdiv);
+
+		pll->vco_cached_rate = clk_hw_get_rate(hw);
+	}
+
+	/*
+	 * When continuous splash screen feature is enabled, we need to cache
+	 * the mux configuration for the pixel_clk_src mux clock. The clock
+	 * framework does not call back to re-configure the mux value if it is
+	 * does not change.For such usecases, we need to ensure that the cached
+	 * value is programmed prior to PLL being locked
+	 */
+	if (pll->handoff_resources)
+		pll->cached_cfg1 = MDSS_PLL_REG_R(pll->phy_base,
+							PHY_CMN_CLK_CFG1);
 	dsi_pll_disable(vco);
 	mdss_pll_resource_enable(pll, false);
 }
@@ -1026,8 +1126,8 @@
 	.reg_read = pll_reg_read,
 };
 
-static struct regmap_bus pclk_mux_regmap_bus = {
-	.reg_read = phy_reg_read,
+static struct regmap_bus pclk_src_mux_regmap_bus = {
+	.reg_read = pclk_mux_read_sel,
 	.reg_write = pclk_mux_write_sel,
 };
 
@@ -1472,7 +1572,7 @@
 				pll_res, &dsi_pll_10nm_config);
 		dsi0pll_pclk_mux.clkr.regmap = rmap;
 
-		rmap = devm_regmap_init(&pdev->dev, &pclk_mux_regmap_bus,
+		rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus,
 				pll_res, &dsi_pll_10nm_config);
 		dsi0pll_pclk_src_mux.clkr.regmap = rmap;
 		rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
@@ -1510,11 +1610,11 @@
 				pll_res, &dsi_pll_10nm_config);
 		dsi1pll_pclk_src.clkr.regmap = rmap;
 
-		rmap = devm_regmap_init(&pdev->dev, &pclk_mux_regmap_bus,
+		rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
 				pll_res, &dsi_pll_10nm_config);
 		dsi1pll_pclk_mux.clkr.regmap = rmap;
 
-		rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
+		rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus,
 				pll_res, &dsi_pll_10nm_config);
 		dsi1pll_pclk_src_mux.clkr.regmap = rmap;
 		rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
diff --git a/drivers/cpufreq/qcom-cpufreq.c b/drivers/cpufreq/qcom-cpufreq.c
index d310380..90fac32 100644
--- a/drivers/cpufreq/qcom-cpufreq.c
+++ b/drivers/cpufreq/qcom-cpufreq.c
@@ -410,7 +410,7 @@
 	if (!IS_ERR(ftbl)) {
 		for_each_possible_cpu(cpu)
 			per_cpu(freq_table, cpu) = ftbl;
-		return 0;
+		goto out_register;
 	}
 
 	/*
@@ -450,6 +450,7 @@
 		per_cpu(freq_table, cpu) = ftbl;
 	}
 
+out_register:
 	ret = register_pm_notifier(&msm_cpufreq_pm_notifier);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 0ddb47f..f2c2985 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -83,6 +83,7 @@
 			dsi_ctrl_hw_14_reg_dump_to_buffer;
 		ctrl->ops.schedule_dma_cmd = NULL;
 		ctrl->ops.get_cont_splash_status = NULL;
+		ctrl->ops.kickoff_command_non_embedded_mode = NULL;
 		break;
 	case DSI_CTRL_VERSION_2_0:
 		ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map;
@@ -97,6 +98,7 @@
 		ctrl->ops.clamp_disable = NULL;
 		ctrl->ops.schedule_dma_cmd = NULL;
 		ctrl->ops.get_cont_splash_status = NULL;
+		ctrl->ops.kickoff_command_non_embedded_mode = NULL;
 		break;
 	case DSI_CTRL_VERSION_2_2:
 		ctrl->ops.phy_reset_config = dsi_ctrl_hw_22_phy_reset_config;
@@ -113,6 +115,8 @@
 		ctrl->ops.clamp_enable = NULL;
 		ctrl->ops.clamp_disable = NULL;
 		ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd;
+		ctrl->ops.kickoff_command_non_embedded_mode =
+			dsi_ctrl_hw_kickoff_non_embedded_mode;
 		break;
 	default:
 		break;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 735f61f..f7756dc 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -213,6 +213,9 @@
 ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
 					  char *buf,
 					  u32 size);
+void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl,
+					struct dsi_ctrl_cmd_dma_info *cmd,
+					u32 flags);
 
 /* Definitions specific to 2.2 DSI controller hardware */
 bool dsi_ctrl_hw_22_get_cont_splash_status(struct dsi_ctrl_hw *ctrl);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 1f10e3c..609ae52 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -940,6 +940,62 @@
 	udelay(sleep_ms * 1000);
 }
 
+void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl,
+		u32 cmd_len,
+		u32 *flags)
+{
+	/**
+	 * Setup the mode of transmission
+	 * override cmd fetch mode during secure session
+	 */
+	if (dsi_ctrl->secure_mode) {
+		*flags &= ~DSI_CTRL_CMD_FETCH_MEMORY;
+		*flags |= DSI_CTRL_CMD_FIFO_STORE;
+		pr_debug("[%s] override to TPG during secure session\n",
+				dsi_ctrl->name);
+		return;
+	}
+
+	/* Check to see if cmd len plus header is greater than fifo size */
+	if ((cmd_len + 4) > DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES) {
+		*flags |= DSI_CTRL_CMD_NON_EMBEDDED_MODE;
+		pr_debug("[%s] override to non-embedded mode,cmd len =%d\n",
+				dsi_ctrl->name, cmd_len);
+		return;
+	}
+}
+
+int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl,
+		u32 cmd_len,
+		u32 *flags)
+{
+	int rc = 0;
+
+	if (*flags & DSI_CTRL_CMD_FIFO_STORE) {
+		/* if command size plus header is greater than fifo size */
+		if ((cmd_len + 4) > DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE) {
+			pr_err("Cannot transfer Cmd in FIFO config\n");
+			return -ENOTSUPP;
+		}
+		if (!dsi_ctrl->hw.ops.kickoff_fifo_command) {
+			pr_err("Cannot transfer command,ops not defined\n");
+			return -ENOTSUPP;
+		}
+	}
+
+	if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+		if (*flags & DSI_CTRL_CMD_BROADCAST) {
+			pr_err("Non embedded not supported with broadcast\n");
+			return -ENOTSUPP;
+		}
+		if (!dsi_ctrl->hw.ops.kickoff_command_non_embedded_mode) {
+			pr_err(" Cannot transfer command,ops not defined\n");
+			return -ENOTSUPP;
+		}
+	}
+	return rc;
+}
+
 static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
 			  const struct mipi_dsi_msg *msg,
 			  u32 flags)
@@ -955,12 +1011,34 @@
 	u8 *cmdbuf;
 	struct dsi_mode_info *timing;
 
-	/* override cmd fetch mode during secure session */
-	if (dsi_ctrl->secure_mode) {
-		flags &= ~DSI_CTRL_CMD_FETCH_MEMORY;
-		flags |= DSI_CTRL_CMD_FIFO_STORE;
-		pr_debug("[%s] override to TPG during secure session\n",
-				dsi_ctrl->name);
+	/* Select the tx mode to transfer the command */
+	dsi_message_setup_tx_mode(dsi_ctrl, msg->tx_len, &flags);
+
+	/* Validate the mode before sending the command */
+	rc = dsi_message_validate_tx_mode(dsi_ctrl, msg->tx_len, &flags);
+	if (rc) {
+		pr_err(" Cmd tx validation failed, cannot transfer cmd\n");
+		rc = -ENOTSUPP;
+		goto error;
+	}
+
+	if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+		cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
+		cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
+			true : false;
+		cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
+			true : false;
+		cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
+			true : false;
+		cmd_mem.datatype = msg->type;
+		cmd_mem.length = msg->tx_len;
+
+		dsi_ctrl->cmd_len = msg->tx_len;
+		memcpy(dsi_ctrl->vaddr, msg->tx_buf, msg->tx_len);
+		pr_debug(" non-embedded mode , size of command =%zd\n",
+					msg->tx_len);
+
+		goto kickoff;
 	}
 
 	rc = mipi_dsi_create_packet(&packet, msg);
@@ -969,16 +1047,6 @@
 		goto error;
 	}
 
-	/* fail cmds more than the supported size in TPG mode */
-	if ((flags & DSI_CTRL_CMD_FIFO_STORE) &&
-			(msg->tx_len > DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE)) {
-		pr_err("[%s] TPG cmd size:%zd not supported, secure:%d\n",
-				dsi_ctrl->name, msg->tx_len,
-				dsi_ctrl->secure_mode);
-		rc = -ENOTSUPP;
-		goto error;
-	}
-
 	rc = dsi_ctrl_copy_and_pad_cmd(dsi_ctrl,
 			&packet,
 			&buffer,
@@ -993,6 +1061,7 @@
 		buffer[3] |= BIT(7);//set the last cmd bit in header.
 
 	if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
+		/* Embedded mode config is selected */
 		cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
 		cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
 			true : false;
@@ -1026,6 +1095,7 @@
 				  true : false;
 	}
 
+kickoff:
 	timing = &(dsi_ctrl->host_config.video_timing);
 	if (timing)
 		line_no += timing->v_back_porch + timing->v_sync_width +
@@ -1045,9 +1115,18 @@
 
 	if (flags & DSI_CTRL_CMD_DEFER_TRIGGER) {
 		if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
-			dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
+			if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+				dsi_ctrl->hw.ops.
+					kickoff_command_non_embedded_mode(
+							&dsi_ctrl->hw,
 							&cmd_mem,
 							hw_flags);
+			} else {
+				dsi_ctrl->hw.ops.kickoff_command(
+						&dsi_ctrl->hw,
+						&cmd_mem,
+						hw_flags);
+			}
 		} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
 			dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
 							      &cmd,
@@ -1065,9 +1144,18 @@
 		reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);
 
 		if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
-			dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
-						      &cmd_mem,
-						      hw_flags);
+			if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+				dsi_ctrl->hw.ops.
+					kickoff_command_non_embedded_mode(
+							&dsi_ctrl->hw,
+							&cmd_mem,
+							hw_flags);
+			} else {
+				dsi_ctrl->hw.ops.kickoff_command(
+						&dsi_ctrl->hw,
+						&cmd_mem,
+						hw_flags);
+			}
 		} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
 			dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
 							      &cmd,
@@ -1106,6 +1194,16 @@
 			dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw,
 					BIT(DSI_FIFO_OVERFLOW), false);
 		dsi_ctrl->hw.ops.reset_cmd_fifo(&dsi_ctrl->hw);
+
+		/*
+		 * DSI 2.2 needs a soft reset whenever we send non-embedded
+		 * mode command followed by embedded mode. Otherwise it will
+		 * result in smmu write faults with DSI as client.
+		 */
+		if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+			dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
+			dsi_ctrl->cmd_len = 0;
+		}
 	}
 error:
 	if (buffer)
@@ -2682,6 +2780,11 @@
 		if (dsi_ctrl->hw.ops.mask_error_intr)
 			dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw,
 					BIT(DSI_FIFO_OVERFLOW), false);
+
+		if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+			dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
+			dsi_ctrl->cmd_len = 0;
+		}
 	}
 
 	mutex_unlock(&dsi_ctrl->ctrl_lock);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index f5b08a0..80b91ca 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -37,6 +37,7 @@
  *				   and transfer it.
  * @DSI_CTRL_CMD_LAST_COMMAND:     Trigger the DMA cmd transfer if this is last
  *				   command in the batch.
+ * @DSI_CTRL_CMD_NON_EMBEDDED_MODE:Trasfer cmd packets in non embedded mode.
  */
 #define DSI_CTRL_CMD_READ             0x1
 #define DSI_CTRL_CMD_BROADCAST        0x2
@@ -45,6 +46,12 @@
 #define DSI_CTRL_CMD_FIFO_STORE       0x10
 #define DSI_CTRL_CMD_FETCH_MEMORY     0x20
 #define DSI_CTRL_CMD_LAST_COMMAND     0x40
+#define DSI_CTRL_CMD_NON_EMBEDDED_MODE 0x80
+
+/* DSI embedded mode fifo size
+ * If the command is greater than 256 bytes it is sent in non-embedded mode.
+ */
+#define DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES 256
 
 /* max size supported for dsi cmd transfer using TPG */
 #define DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE 64
@@ -680,4 +687,20 @@
  */
 int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on);
 
+/**
+ * @dsi_ctrl:        DSI controller handle.
+ * cmd_len:	     Length of command.
+ * flags:	     Config mode flags.
+ */
+void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len,
+		u32 *flags);
+
+/**
+ * @dsi_ctrl:        DSI controller handle.
+ * cmd_len:	     Length of command.
+ * flags:	     Config mode flags.
+ */
+int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len,
+		u32 *flags);
+
 #endif /* _DSI_CTRL_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index c77065c..567f289 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -296,6 +296,7 @@
  * struct dsi_ctrl_cmd_dma_info - command buffer information
  * @offset:        IOMMU VA for command buffer address.
  * @length:        Length of the command buffer.
+ * @datatype:      Datatype of cmd.
  * @en_broadcast:  Enable broadcast mode if set to true.
  * @is_master:     Is master in broadcast mode.
  * @use_lpm:       Use low power mode for command transmission.
@@ -303,6 +304,7 @@
 struct dsi_ctrl_cmd_dma_info {
 	u32 offset;
 	u32 length;
+	u8  datatype;
 	bool en_broadcast;
 	bool is_master;
 	bool use_lpm;
@@ -497,6 +499,25 @@
 				u32 flags);
 
 	/**
+	 * kickoff_command_non_embedded_mode() - cmd in non embedded mode
+	 * @ctrl:          Pointer to the controller host hardware.
+	 * @cmd:           Command information.
+	 * @flags:         Modifiers for command transmission.
+	 *
+	 * If command length is greater than DMA FIFO size of 256 bytes we use
+	 * this non- embedded mode.
+	 * The controller hardware is programmed with address and size of the
+	 * command buffer. The transmission is kicked off if
+	 * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is
+	 * set, caller should make a separate call to trigger_command_dma() to
+	 * transmit the command.
+	 */
+
+	void (*kickoff_command_non_embedded_mode)(struct dsi_ctrl_hw *ctrl,
+				struct dsi_ctrl_cmd_dma_info *cmd,
+				u32 flags);
+
+	/**
 	 * kickoff_fifo_command() - transmits a command using FIFO in dsi
 	 *                          hardware.
 	 * @ctrl:          Pointer to the controller host hardware.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c
index 650c2e0..d94d6f7b 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c
@@ -79,3 +79,48 @@
 	reg = DSI_R32(ctrl, DSI_SCRATCH_REGISTER_1);
 	return reg == 0x1 ? true : false;
 }
+
+/*
+ * dsi_ctrl_hw_kickoff_non_embedded_mode()-Kickoff cmd  in non-embedded mode
+ * @ctrl:                  - Pointer to the controller host hardware.
+ * @dsi_ctrl_cmd_dma_info: - command buffer information.
+ * @flags:		   - DSI CTRL Flags.
+ */
+void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl,
+				    struct dsi_ctrl_cmd_dma_info *cmd,
+				    u32 flags)
+{
+	u32 reg = 0;
+
+	reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL);
+
+	reg &= ~BIT(31);/* disable broadcast */
+	reg &= ~BIT(30);
+
+	if (cmd->use_lpm)
+		reg |= BIT(26);
+	else
+		reg &= ~BIT(26);
+
+	/* Select non EMBEDDED_MODE, pick the packet header from register */
+	reg &= ~BIT(28);
+	reg |= BIT(24);/* long packet */
+	reg |= BIT(29);/* wc_sel = 1 */
+	reg |= (((cmd->datatype) & 0x03f) << 16);/* data type */
+	DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg);
+
+	/* Enable WRITE_WATERMARK_DISABLE and READ_WATERMARK_DISABLE bits */
+	reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL);
+	reg |= BIT(20);
+	reg |= BIT(16);
+	DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg);
+
+	DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset);
+	DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, ((cmd->length) & 0xFFFFFF));
+
+	/* wait for writes to complete before kick off */
+	wmb();
+
+	if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER))
+		DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1);
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index c2c8f57..c753c80 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -612,9 +612,17 @@
 	else
 		reg &= ~BIT(26);
 
-	reg |= BIT(28);
+	reg |= BIT(28);/* Select embedded mode */
+	reg &= ~BIT(24);/* packet type */
+	reg &= ~BIT(29);/* WC_SEL to 0 */
 	DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg);
 
+	reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL);
+	reg &= ~BIT(20);/* Enable write watermark*/
+	reg &= ~BIT(16);/* Enable read watermark */
+
+
+	DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg);
 	DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset);
 	DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, (cmd->length & 0xFFFFFF));
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 2c758a2..d92a71d 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -214,6 +214,135 @@
 	return rc;
 }
 
+static void dsi_display_aspace_cb_locked(void *cb_data, bool is_detach)
+{
+	struct dsi_display *display;
+	struct dsi_display_ctrl *display_ctrl;
+	int rc, cnt;
+
+	if (!cb_data) {
+		pr_err("aspace cb called with invalid cb_data\n");
+		return;
+	}
+	display = (struct dsi_display *)cb_data;
+
+	/*
+	 * acquire panel_lock to make sure no commands are in-progress
+	 * while detaching the non-secure context banks
+	 */
+	dsi_panel_acquire_panel_lock(display->panel);
+
+	if (is_detach) {
+		/* invalidate the stored iova */
+		display->cmd_buffer_iova = 0;
+
+		/* return the virtual address mapping */
+		msm_gem_put_vaddr_locked(display->tx_cmd_buf);
+		msm_gem_vunmap(display->tx_cmd_buf);
+
+	} else {
+		rc = msm_gem_get_iova_locked(display->tx_cmd_buf,
+				display->aspace, &(display->cmd_buffer_iova));
+		if (rc) {
+			pr_err("failed to get the iova rc %d\n", rc);
+			goto end;
+		}
+
+		display->vaddr =
+			(void *) msm_gem_get_vaddr_locked(display->tx_cmd_buf);
+
+		if (IS_ERR_OR_NULL(display->vaddr)) {
+			pr_err("failed to get va rc %d\n", rc);
+			goto end;
+		}
+	}
+
+	for (cnt = 0; cnt < display->ctrl_count; cnt++) {
+		display_ctrl = &display->ctrl[cnt];
+		display_ctrl->ctrl->cmd_buffer_size = display->cmd_buffer_size;
+		display_ctrl->ctrl->cmd_buffer_iova = display->cmd_buffer_iova;
+		display_ctrl->ctrl->vaddr = display->vaddr;
+	}
+
+end:
+	/* release panel_lock */
+	dsi_panel_release_panel_lock(display->panel);
+}
+
+/* Allocate memory for cmd dma tx buffer */
+static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
+{
+	int rc = 0, cnt = 0;
+	struct dsi_display_ctrl *display_ctrl;
+
+	mutex_lock(&display->drm_dev->struct_mutex);
+	display->tx_cmd_buf = msm_gem_new(display->drm_dev,
+			SZ_4K,
+			MSM_BO_UNCACHED);
+	mutex_unlock(&display->drm_dev->struct_mutex);
+
+	if ((display->tx_cmd_buf) == NULL) {
+		pr_err("Failed to allocate cmd tx buf memory\n");
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	display->cmd_buffer_size = SZ_4K;
+
+	display->aspace = msm_gem_smmu_address_space_get(
+			display->drm_dev, MSM_SMMU_DOMAIN_UNSECURE);
+	if (!display->aspace) {
+		pr_err("failed to get aspace\n");
+		rc = -EINVAL;
+		goto free_gem;
+	}
+	/* register to aspace */
+	rc = msm_gem_address_space_register_cb(display->aspace,
+			dsi_display_aspace_cb_locked, (void *)display);
+	if (rc) {
+		pr_err("failed to register callback %d", rc);
+		goto free_gem;
+	}
+
+	rc = msm_gem_get_iova(display->tx_cmd_buf, display->aspace,
+				&(display->cmd_buffer_iova));
+	if (rc) {
+		pr_err("failed to get the iova rc %d\n", rc);
+		goto free_aspace_cb;
+	}
+
+	display->vaddr =
+		(void *) msm_gem_get_vaddr(display->tx_cmd_buf);
+	if (IS_ERR_OR_NULL(display->vaddr)) {
+		pr_err("failed to get va rc %d\n", rc);
+		rc = -EINVAL;
+		goto put_iova;
+	}
+
+	for (cnt = 0; cnt < display->ctrl_count; cnt++) {
+		display_ctrl = &display->ctrl[cnt];
+		display_ctrl->ctrl->cmd_buffer_size = SZ_4K;
+		display_ctrl->ctrl->cmd_buffer_iova =
+					display->cmd_buffer_iova;
+		display_ctrl->ctrl->vaddr = display->vaddr;
+		display_ctrl->ctrl->tx_cmd_buf = display->tx_cmd_buf;
+	}
+
+	return rc;
+
+put_iova:
+	msm_gem_put_iova(display->tx_cmd_buf, display->aspace);
+free_aspace_cb:
+	msm_gem_address_space_unregister_cb(display->aspace,
+			dsi_display_aspace_cb_locked, display);
+free_gem:
+	mutex_lock(&display->drm_dev->struct_mutex);
+	msm_gem_free_object(display->tx_cmd_buf);
+	mutex_unlock(&display->drm_dev->struct_mutex);
+error:
+	return rc;
+}
+
 static bool dsi_display_validate_reg_read(struct dsi_panel *panel)
 {
 	int i, j = 0;
@@ -330,6 +459,14 @@
 
 	m_ctrl = &display->ctrl[display->cmd_master_idx];
 
+	if (display->tx_cmd_buf == NULL) {
+		rc = dsi_host_alloc_cmd_tx_buffer(display);
+		if (rc) {
+			pr_err("failed to allocate cmd tx buffer memory\n");
+			goto done;
+		}
+	}
+
 	rc = dsi_display_cmd_engine_enable(display);
 	if (rc) {
 		pr_err("cmd engine enable failed\n");
@@ -358,9 +495,9 @@
 			goto exit;
 		}
 	}
-
 exit:
 	dsi_display_cmd_engine_disable(display);
+done:
 	return rc;
 }
 
@@ -1943,62 +2080,6 @@
 	return rc;
 }
 
-static void dsi_display_aspace_cb_locked(void *cb_data, bool is_detach)
-{
-	struct dsi_display *display;
-	struct dsi_display_ctrl *display_ctrl;
-	int rc, cnt;
-
-	if (!cb_data) {
-		pr_err("aspace cb called with invalid cb_data\n");
-		return;
-	}
-	display = (struct dsi_display *)cb_data;
-
-	/*
-	 * acquire panel_lock to make sure no commands are in-progress
-	 * while detaching the non-secure context banks
-	 */
-	dsi_panel_acquire_panel_lock(display->panel);
-
-	if (is_detach) {
-		/* invalidate the stored iova */
-		display->cmd_buffer_iova = 0;
-
-		/* return the virtual address mapping */
-		msm_gem_put_vaddr_locked(display->tx_cmd_buf);
-		msm_gem_vunmap(display->tx_cmd_buf);
-
-	} else {
-		rc = msm_gem_get_iova_locked(display->tx_cmd_buf,
-				display->aspace, &(display->cmd_buffer_iova));
-		if (rc) {
-			pr_err("failed to get the iova rc %d\n", rc);
-			goto end;
-		}
-
-		display->vaddr =
-			(void *) msm_gem_get_vaddr_locked(display->tx_cmd_buf);
-
-		if (IS_ERR_OR_NULL(display->vaddr)) {
-			pr_err("failed to get va rc %d\n", rc);
-			goto end;
-		}
-	}
-
-	for (cnt = 0; cnt < display->ctrl_count; cnt++) {
-		display_ctrl = &display->ctrl[cnt];
-		display_ctrl->ctrl->cmd_buffer_size = display->cmd_buffer_size;
-		display_ctrl->ctrl->cmd_buffer_iova = display->cmd_buffer_iova;
-		display_ctrl->ctrl->vaddr = display->vaddr;
-		display_ctrl->ctrl->secure_mode = is_detach ? true : false;
-	}
-
-end:
-	/* release panel_lock */
-	dsi_panel_release_panel_lock(display->panel);
-}
-
 static int dsi_host_attach(struct mipi_dsi_host *host,
 			   struct mipi_dsi_device *dsi)
 {
@@ -2015,8 +2096,7 @@
 				 const struct mipi_dsi_msg *msg)
 {
 	struct dsi_display *display = to_dsi_display(host);
-	struct dsi_display_ctrl *display_ctrl;
-	int rc = 0, cnt = 0;
+	int rc = 0;
 
 	if (!host || !msg) {
 		pr_err("Invalid params\n");
@@ -2046,58 +2126,11 @@
 	}
 
 	if (display->tx_cmd_buf == NULL) {
-		mutex_lock(&display->drm_dev->struct_mutex);
-		display->tx_cmd_buf = msm_gem_new(display->drm_dev,
-				SZ_4K,
-				MSM_BO_UNCACHED);
-		mutex_unlock(&display->drm_dev->struct_mutex);
-
-		display->cmd_buffer_size = SZ_4K;
-
-		if ((display->tx_cmd_buf) == NULL) {
-			pr_err("value of display->tx_cmd_buf is NULL");
+		rc = dsi_host_alloc_cmd_tx_buffer(display);
+		if (rc) {
+			pr_err("failed to allocate cmd tx buffer memory\n");
 			goto error_disable_cmd_engine;
 		}
-
-		display->aspace = msm_gem_smmu_address_space_get(
-				display->drm_dev, MSM_SMMU_DOMAIN_UNSECURE);
-		if (!display->aspace) {
-			pr_err("failed to get aspace\n");
-			rc = -EINVAL;
-			goto free_gem;
-		}
-
-		/* register to aspace */
-		rc = msm_gem_address_space_register_cb(display->aspace,
-				dsi_display_aspace_cb_locked, (void *)display);
-		if (rc) {
-			pr_err("failed to register callback %d", rc);
-			goto free_gem;
-		}
-
-		rc = msm_gem_get_iova(display->tx_cmd_buf, display->aspace,
-					&(display->cmd_buffer_iova));
-		if (rc) {
-			pr_err("failed to get the iova rc %d\n", rc);
-			goto free_aspace_cb;
-		}
-
-		display->vaddr =
-			(void *) msm_gem_get_vaddr(display->tx_cmd_buf);
-
-		if (IS_ERR_OR_NULL(display->vaddr)) {
-			pr_err("failed to get va rc %d\n", rc);
-			rc = -EINVAL;
-			goto put_iova;
-		}
-
-		for (cnt = 0; cnt < display->ctrl_count; cnt++) {
-			display_ctrl = &display->ctrl[cnt];
-			display_ctrl->ctrl->cmd_buffer_size = SZ_4K;
-			display_ctrl->ctrl->cmd_buffer_iova =
-						display->cmd_buffer_iova;
-			display_ctrl->ctrl->vaddr = display->vaddr;
-		}
 	}
 
 	if (display->ctrl_count > 1 && !(msg->flags & MIPI_DSI_MSG_UNICAST)) {
@@ -2129,16 +2162,6 @@
 		pr_err("[%s] failed to disable all DSI clocks, rc=%d\n",
 		       display->name, rc);
 	}
-	return rc;
-put_iova:
-	msm_gem_put_iova(display->tx_cmd_buf, display->aspace);
-free_aspace_cb:
-	msm_gem_address_space_unregister_cb(display->aspace,
-			dsi_display_aspace_cb_locked, display);
-free_gem:
-	mutex_lock(&display->drm_dev->struct_mutex);
-	msm_gem_free_object(display->tx_cmd_buf);
-	mutex_unlock(&display->drm_dev->struct_mutex);
 error:
 	return rc;
 }
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 133b4d5..7671496 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -506,7 +506,8 @@
 			goto error;
 		}
 		if (cmds->post_wait_ms)
-			msleep(cmds->post_wait_ms);
+			usleep_range(cmds->post_wait_ms*1000,
+					((cmds->post_wait_ms*1000)+10));
 		cmds++;
 	}
 error:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c b/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c
index e2219aa..5635346 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_pwr.c
@@ -341,6 +341,11 @@
 {
 	int rc = 0;
 
+	if (!regs->vregs) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
 	if (enable) {
 		if (regs->refcount == 0) {
 			rc = dsi_pwr_enable_vregs(regs, true);
@@ -350,7 +355,8 @@
 		regs->refcount++;
 	} else {
 		if (regs->refcount == 0) {
-			pr_err("Unbalanced regulator off\n");
+			pr_err("Unbalanced regulator off:%s\n",
+					regs->vregs->vreg_name);
 		} else {
 			regs->refcount--;
 			if (regs->refcount == 0) {
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index f8c3df5..a015379 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -104,12 +104,13 @@
 
 		msm_obj->pages = p;
 
-		/* For non-cached buffers, ensure the new pages are clean
-		 * because display controller, GPU, etc. are not coherent:
+		/*
+		 * Make sure to flush the CPU cache for newly allocated memory
+		 * so we don't get ourselves into trouble with a dirty cache
 		 */
 		if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
-			dma_map_sg(dev->dev, msm_obj->sgt->sgl,
-					msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+			dma_sync_sg_for_device(dev->dev, msm_obj->sgt->sgl,
+				msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
 	}
 
 	return msm_obj->pages;
@@ -120,12 +121,6 @@
 	struct msm_gem_object *msm_obj = to_msm_bo(obj);
 
 	if (msm_obj->pages) {
-		/* For non-cached buffers, ensure the new pages are clean
-		 * because display controller, GPU, etc. are not coherent:
-		 */
-		if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
-			dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl,
-					msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
 		sg_free_table(msm_obj->sgt);
 		kfree(msm_obj->sgt);
 
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 0baba62..e2d937b 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -490,12 +490,10 @@
 	return rc;
 }
 
-static int _sde_connector_update_bl_scale(struct sde_connector *c_conn, int idx)
+static int _sde_connector_update_bl_scale(struct sde_connector *c_conn)
 {
-	struct drm_connector conn;
 	struct dsi_display *dsi_display;
 	struct dsi_backlight_config *bl_config;
-	uint64_t value;
 	int rc = 0;
 
 	if (!c_conn) {
@@ -503,7 +501,6 @@
 		return -EINVAL;
 	}
 
-	conn = c_conn->base;
 	dsi_display = c_conn->display;
 	if (!dsi_display || !dsi_display->panel) {
 		SDE_ERROR("Invalid params(s) dsi_display %pK, panel %pK\n",
@@ -513,22 +510,16 @@
 	}
 
 	bl_config = &dsi_display->panel->bl_config;
-	value = sde_connector_get_property(conn.state, idx);
 
-	if (idx == CONNECTOR_PROP_BL_SCALE) {
-		if (value > MAX_BL_SCALE_LEVEL)
-			bl_config->bl_scale = MAX_BL_SCALE_LEVEL;
-		else
-			bl_config->bl_scale = (u32)value;
-	} else if (idx == CONNECTOR_PROP_AD_BL_SCALE) {
-		if (value > MAX_AD_BL_SCALE_LEVEL)
-			bl_config->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL;
-		else
-			bl_config->bl_scale_ad = (u32)value;
-	} else {
-		SDE_DEBUG("invalid idx %d\n", idx);
-		return 0;
-	}
+	if (c_conn->bl_scale > MAX_BL_SCALE_LEVEL)
+		bl_config->bl_scale = MAX_BL_SCALE_LEVEL;
+	else
+		bl_config->bl_scale = c_conn->bl_scale;
+
+	if (c_conn->bl_scale_ad > MAX_AD_BL_SCALE_LEVEL)
+		bl_config->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL;
+	else
+		bl_config->bl_scale_ad = c_conn->bl_scale_ad;
 
 	SDE_DEBUG("bl_scale = %u, bl_scale_ad = %u, bl_level = %u\n",
 		bl_config->bl_scale, bl_config->bl_scale_ad,
@@ -570,7 +561,7 @@
 			break;
 		case CONNECTOR_PROP_BL_SCALE:
 		case CONNECTOR_PROP_AD_BL_SCALE:
-			_sde_connector_update_bl_scale(c_conn, idx);
+			_sde_connector_update_bl_scale(c_conn);
 			break;
 		default:
 			/* nothing to do for most properties */
@@ -578,6 +569,12 @@
 		}
 	}
 
+	/* Special handling for postproc properties */
+	if (c_conn->bl_scale_dirty) {
+		_sde_connector_update_bl_scale(c_conn);
+		c_conn->bl_scale_dirty = false;
+	}
+
 	if (!c_conn->ops.pre_kickoff)
 		return 0;
 
@@ -1041,6 +1038,19 @@
 		if (rc)
 			SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
 		break;
+	/* CONNECTOR_PROP_BL_SCALE and CONNECTOR_PROP_AD_BL_SCALE are
+	 * color-processing properties. These two properties require
+	 * special handling since they don't quite fit the current standard
+	 * atomic set property framework.
+	 */
+	case CONNECTOR_PROP_BL_SCALE:
+		c_conn->bl_scale = val;
+		c_conn->bl_scale_dirty = true;
+		break;
+	case CONNECTOR_PROP_AD_BL_SCALE:
+		c_conn->bl_scale_ad = val;
+		c_conn->bl_scale_dirty = true;
+		break;
 	default:
 		break;
 	}
@@ -1913,6 +1923,10 @@
 		0x0, 0, MAX_AD_BL_SCALE_LEVEL, MAX_AD_BL_SCALE_LEVEL,
 		CONNECTOR_PROP_AD_BL_SCALE);
 
+	c_conn->bl_scale_dirty = false;
+	c_conn->bl_scale = MAX_BL_SCALE_LEVEL;
+	c_conn->bl_scale_ad = MAX_AD_BL_SCALE_LEVEL;
+
 	/* 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 f6dee6b..b92c342 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -287,6 +287,9 @@
  * @bl_device: backlight device node
  * @status_work: work object to perform status checks
  * @force_panel_dead: variable to trigger forced ESD recovery
+ * @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed
+ * @bl_scale: BL scale value for ABA feature
+ * @bl_scale_ad: BL scale value for AD feature
  */
 struct sde_connector {
 	struct drm_connector base;
@@ -323,6 +326,10 @@
 	struct backlight_device *bl_device;
 	struct delayed_work status_work;
 	u32 force_panel_dead;
+
+	bool bl_scale_dirty;
+	u32 bl_scale;
+	u32 bl_scale_ad;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 6b36745..3879d4d 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -170,6 +170,15 @@
 	}
 
 	SDE_EVT32(crtc->base.id, perf->core_clk_rate);
+	trace_sde_perf_calc_crtc(crtc->base.id,
+			perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+			perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+			perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI],
+			perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+			perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+			perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI],
+			perf->core_clk_rate);
+
 	SDE_DEBUG(
 		"crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n",
 			crtc->base.id, perf->core_clk_rate,
@@ -552,19 +561,32 @@
 			 * 2. new bandwidth vote - "ab or ib vote" is lower
 			 *    than current vote at end of commit or stop.
 			 */
-			if ((params_changed && ((new->bw_ctl[i] >
-						old->bw_ctl[i]) ||
-				  (new->max_per_pipe_ib[i] >
-						old->max_per_pipe_ib[i]))) ||
-			    (!params_changed && ((new->bw_ctl[i] <
-						old->bw_ctl[i]) ||
-				  (new->max_per_pipe_ib[i] <
-						old->max_per_pipe_ib[i])))) {
+
+			if ((params_changed &&
+				(new->bw_ctl[i] > old->bw_ctl[i])) ||
+			    (!params_changed &&
+				(new->bw_ctl[i] < old->bw_ctl[i]))) {
+
 				SDE_DEBUG(
 					"crtc=%d p=%d new_bw=%llu,old_bw=%llu\n",
 					crtc->base.id, params_changed,
 					new->bw_ctl[i], old->bw_ctl[i]);
 				old->bw_ctl[i] = new->bw_ctl[i];
+				update_bus |= BIT(i);
+			}
+
+			if ((params_changed &&
+				(new->max_per_pipe_ib[i] >
+				 old->max_per_pipe_ib[i])) ||
+			    (!params_changed &&
+				(new->max_per_pipe_ib[i] <
+				old->max_per_pipe_ib[i]))) {
+
+				SDE_DEBUG(
+					"crtc=%d p=%d new_ib=%llu,old_ib=%llu\n",
+					crtc->base.id, params_changed,
+					new->max_per_pipe_ib[i],
+					old->max_per_pipe_ib[i]);
 				old->max_per_pipe_ib[i] =
 						new->max_per_pipe_ib[i];
 				update_bus |= BIT(i);
@@ -608,11 +630,14 @@
 		update_clk = 1;
 	}
 	trace_sde_perf_crtc_update(crtc->base.id,
-				new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC],
-				new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC],
-				new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI],
-				new->core_clk_rate, stop_req,
-				update_bus, update_clk);
+		new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+		new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+		new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+		new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+		new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI],
+		new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI],
+		new->core_clk_rate, stop_req,
+		update_bus, update_clk, params_changed);
 
 	for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
 		if (update_bus & BIT(i))
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 4d09642..b6888df 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -199,6 +199,7 @@
  * @rsc_config:			rsc configuration for display vtotal, fps, etc.
  * @cur_conn_roi:		current connector roi
  * @prv_conn_roi:		previous connector roi to optimize if unchanged
+ * @crtc			pointer to drm_crtc
  */
 struct sde_encoder_virt {
 	struct drm_encoder base;
@@ -243,6 +244,7 @@
 	struct sde_rsc_cmd_config rsc_config;
 	struct sde_rect cur_conn_roi;
 	struct sde_rect prv_conn_roi;
+	struct drm_crtc *crtc;
 };
 
 #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -1315,14 +1317,23 @@
 	struct drm_display_mode *adj_mode;
 	struct sde_rect roi;
 
-	if (!drm_enc || !drm_enc->crtc || !drm_enc->crtc->state)
+	if (!drm_enc) {
+		SDE_ERROR("invalid encoder parameter\n");
 		return -EINVAL;
+	}
+
 	sde_enc = to_sde_encoder_virt(drm_enc);
-
-	if (!sde_enc->cur_master)
+	if (!sde_enc->crtc || !sde_enc->crtc->state) {
+		SDE_ERROR("invalid crtc parameter\n");
 		return -EINVAL;
+	}
 
-	adj_mode = &sde_enc->base.crtc->state->adjusted_mode;
+	if (!sde_enc->cur_master) {
+		SDE_ERROR("invalid cur_master parameter\n");
+		return -EINVAL;
+	}
+
+	adj_mode = &sde_enc->cur_master->cached_mode;
 	drm_conn = sde_enc->cur_master->connector;
 
 	_sde_encoder_get_connector_roi(sde_enc, &roi);
@@ -1367,8 +1378,8 @@
 			sde_enc->prv_conn_roi.y,
 			sde_enc->prv_conn_roi.w,
 			sde_enc->prv_conn_roi.h,
-			sde_enc->base.crtc->state->adjusted_mode.hdisplay,
-			sde_enc->base.crtc->state->adjusted_mode.vdisplay);
+			sde_enc->cur_master->cached_mode.hdisplay,
+			sde_enc->cur_master->cached_mode.vdisplay);
 
 	if (sde_kms_rect_is_equal(&sde_enc->cur_conn_roi,
 			&sde_enc->prv_conn_roi))
@@ -1501,14 +1512,20 @@
 	struct drm_crtc *primary_crtc;
 	int pipe = -1;
 	int rc = 0;
+	int wait_refcount;
 
-	if (!drm_enc || !drm_enc->crtc || !drm_enc->dev) {
-		SDE_ERROR("invalid arguments\n");
+	if (!drm_enc || !drm_enc->dev) {
+		SDE_ERROR("invalid encoder arguments\n");
 		return -EINVAL;
 	}
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
-	crtc = drm_enc->crtc;
+	crtc = sde_enc->crtc;
+
+	if (!sde_enc->crtc) {
+		SDE_ERROR("invalid crtc parameter\n");
+		return -EINVAL;
+	}
 	disp_info = &sde_enc->disp_info;
 	rsc_config = &sde_enc->rsc_config;
 
@@ -1583,6 +1600,12 @@
 		return ret;
 	}
 
+	if (wait_vblank_crtc_id)
+		wait_refcount =
+			sde_rsc_client_get_vsync_refcount(sde_enc->rsc_client);
+	SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id, wait_refcount,
+			SDE_EVTLOG_FUNC_ENTRY);
+
 	if (crtc->base.id != wait_vblank_crtc_id) {
 		primary_crtc = drm_crtc_find(drm_enc->dev, wait_vblank_crtc_id);
 		if (!primary_crtc) {
@@ -1620,6 +1643,11 @@
 		SDE_EVT32(DRMID(drm_enc), wait_vblank_crtc_id, wait_count,
 				SDE_EVTLOG_ERROR);
 
+	if (wait_refcount)
+		sde_rsc_client_reset_vsync_refcount(sde_enc->rsc_client);
+	SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id, wait_refcount,
+			SDE_EVTLOG_FUNC_EXIT);
+
 	return ret;
 }
 
@@ -1697,10 +1725,21 @@
 		struct drm_encoder *drm_enc, bool enable)
 {
 	struct sde_encoder_rsc_config rsc_cfg = { 0 };
+	struct sde_encoder_virt *sde_enc;
+
+	if (!drm_enc) {
+		SDE_ERROR("invalid encoder argument\n");
+		return;
+	}
+	sde_enc = to_sde_encoder_virt(drm_enc);
+	if (!sde_enc->crtc) {
+		SDE_ERROR("invalid crtc\n");
+		return;
+	}
 
 	if (enable) {
 		rsc_cfg.inline_rotate_prefill =
-				sde_crtc_get_inline_prefill(drm_enc->crtc);
+				sde_crtc_get_inline_prefill(sde_enc->crtc);
 
 		_sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
 	} else {
@@ -1788,9 +1827,9 @@
 	int ret;
 	bool is_vid_mode = false;
 
-	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
-			!drm_enc->crtc) {
-		SDE_ERROR("invalid parameters\n");
+	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
+		SDE_ERROR("invalid encoder parameters, sw_event:%u\n",
+				sw_event);
 		return -EINVAL;
 	}
 	sde_enc = to_sde_encoder_virt(drm_enc);
@@ -1798,12 +1837,6 @@
 	is_vid_mode = sde_enc->disp_info.capabilities &
 						MSM_DISPLAY_CAP_VID_MODE;
 
-	if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) {
-		SDE_ERROR("invalid crtc index\n");
-		return -EINVAL;
-	}
-	disp_thread = &priv->disp_thread[drm_enc->crtc->index];
-
 	/*
 	 * when idle_pc is not supported, process only KICKOFF, STOP and MODESET
 	 * events and return early for other events (ie wb display).
@@ -1877,6 +1910,18 @@
 		break;
 
 	case SDE_ENC_RC_EVENT_FRAME_DONE:
+		if (!sde_enc->crtc) {
+			SDE_ERROR("invalid crtc, sw_event:%u\n", sw_event);
+			return -EINVAL;
+		}
+
+		if (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) {
+			SDE_ERROR("invalid crtc index :%u\n",
+					sde_enc->crtc->index);
+			return -EINVAL;
+		}
+		disp_thread = &priv->disp_thread[sde_enc->crtc->index];
+
 		/*
 		 * mutex lock is not used as this event happens at interrupt
 		 * context. And locking is not required as, the other events
@@ -1895,7 +1940,7 @@
 		 * schedule off work item only when there are no
 		 * frames pending
 		 */
-		if (sde_crtc_frame_pending(drm_enc->crtc) > 1) {
+		if (sde_crtc_frame_pending(sde_enc->crtc) > 1) {
 			SDE_DEBUG_ENC(sde_enc, "skip schedule work");
 			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
 				SDE_EVTLOG_FUNC_CASE2);
@@ -2380,6 +2425,16 @@
 		return;
 	}
 
+	/*
+	 * cache the crtc in sde_enc on enable for duration of use case
+	 * for correctly servicing asynchronous irq events and timers
+	 */
+	if (!drm_enc->crtc) {
+		SDE_ERROR("invalid crtc\n");
+		return;
+	}
+	sde_enc->crtc = drm_enc->crtc;
+
 	ret = _sde_encoder_get_mode_info(drm_enc, &mode_info);
 	if (ret) {
 		SDE_ERROR_ENC(sde_enc, "failed to get mode info\n");
@@ -2539,6 +2594,11 @@
 	}
 
 	sde_enc->cur_master = NULL;
+	/*
+	 * clear the cached crtc in sde_enc on use case finish, after all the
+	 * outstanding events and timers have been completed
+	 */
+	sde_enc->crtc = NULL;
 
 	SDE_DEBUG_ENC(sde_enc, "encoder disabled\n");
 
@@ -3264,12 +3324,7 @@
 	ktime_t cur_time;
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
-
-	if (!drm_enc->crtc || !drm_enc->crtc->state) {
-		SDE_ERROR("crtc/crtc state object is NULL\n");
-		return -EINVAL;
-	}
-	mode = &drm_enc->crtc->state->adjusted_mode;
+	mode = &sde_enc->cur_master->cached_mode;
 
 	line_time = _sde_encoder_calculate_linetime(sde_enc, mode);
 	if (!line_time)
@@ -3307,23 +3362,27 @@
 	struct msm_drm_private *priv;
 	struct msm_drm_thread *event_thread;
 
-	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
-			!drm_enc->crtc) {
-		SDE_ERROR("invalid parameters\n");
+	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
+		SDE_ERROR("invalid encoder parameters\n");
 		return;
 	}
 
 	sde_enc = to_sde_encoder_virt(drm_enc);
 	priv = drm_enc->dev->dev_private;
-
-	if (drm_enc->crtc->index >= ARRAY_SIZE(priv->event_thread)) {
-		SDE_ERROR("invalid crtc index\n");
+	if (!sde_enc->crtc) {
+		SDE_ERROR("invalid crtc");
 		return;
 	}
-	event_thread = &priv->event_thread[drm_enc->crtc->index];
+
+	if (sde_enc->crtc->index >= ARRAY_SIZE(priv->event_thread)) {
+		SDE_ERROR("invalid crtc index:%u\n",
+				sde_enc->crtc->index);
+		return;
+	}
+	event_thread = &priv->event_thread[sde_enc->crtc->index];
 	if (!event_thread) {
 		SDE_ERROR("event_thread not found for crtc:%d\n",
-				drm_enc->crtc->index);
+				sde_enc->crtc->index);
 		return;
 	}
 
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index cfe2126..a877eb5 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -379,6 +379,7 @@
  * @end_time:		End time of writeback latest request
  * @bo_disable:		Buffer object(s) to use during the disabling state
  * @fb_disable:		Frame buffer to use during the disabling state
+ * @crtc		Pointer to drm_crtc
  */
 struct sde_encoder_phys_wb {
 	struct sde_encoder_phys base;
@@ -403,6 +404,7 @@
 	ktime_t end_time;
 	struct drm_gem_object *bo_disable[SDE_MAX_PLANES];
 	struct drm_framebuffer *fb_disable;
+	struct drm_crtc *crtc;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 42cf015..9a90075 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -124,7 +124,12 @@
 	}
 
 	wb_enc = to_sde_encoder_phys_wb(phys_enc);
-	crtc = phys_enc->parent->crtc;
+	if (!wb_enc->crtc) {
+		SDE_ERROR("invalid crtc");
+		return;
+	}
+
+	crtc = wb_enc->crtc;
 
 	if (!wb_enc->hw_wb || !wb_enc->hw_wb->caps) {
 		SDE_ERROR("invalid writeback hardware\n");
@@ -1141,6 +1146,12 @@
 	wb_enc->wb_dev = sde_wb_connector_get_wb(connector);
 
 	phys_enc->enable_state = SDE_ENC_ENABLED;
+
+	/*
+	 * cache the crtc in wb_enc on enable for duration of use case
+	 * for correctly servicing asynchronous irq events and timers
+	 */
+	wb_enc->crtc = phys_enc->parent->crtc;
 }
 
 /**
@@ -1186,6 +1197,7 @@
 	sde_encoder_phys_wb_wait_for_commit_done(phys_enc);
 exit:
 	phys_enc->enable_state = SDE_ENC_DISABLED;
+	wb_enc->crtc = NULL;
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 426ecf1..4437987 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -610,6 +610,35 @@
 	SDE_REG_WRITE(c, CTL_TOP, intf_cfg);
 }
 
+static inline u32 sde_hw_ctl_read_ctl_top(struct sde_hw_ctl *ctx)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 ctl_top;
+
+	if (!ctx) {
+		pr_err("Invalid input argument\n");
+		return 0;
+	}
+	c = &ctx->hw;
+	ctl_top = SDE_REG_READ(c, CTL_TOP);
+	return ctl_top;
+}
+
+static inline u32 sde_hw_ctl_read_ctl_layers(struct sde_hw_ctl *ctx, int index)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 ctl_top;
+
+	if (!ctx) {
+		pr_err("Invalid input argument\n");
+		return 0;
+	}
+	c = &ctx->hw;
+	ctl_top = SDE_REG_READ(c, CTL_LAYER(index));
+	pr_debug("Ctl_layer value = 0x%x\n", ctl_top);
+	return ctl_top;
+}
+
 static void sde_hw_ctl_setup_sbuf_cfg(struct sde_hw_ctl *ctx,
 	struct sde_ctl_sbuf_cfg *cfg)
 {
@@ -640,6 +669,8 @@
 	ops->get_flush_register = sde_hw_ctl_get_flush_register;
 	ops->trigger_start = sde_hw_ctl_trigger_start;
 	ops->trigger_pending = sde_hw_ctl_trigger_pending;
+	ops->read_ctl_top = sde_hw_ctl_read_ctl_top;
+	ops->read_ctl_layers = sde_hw_ctl_read_ctl_layers;
 	ops->setup_intf_cfg = sde_hw_ctl_intf_cfg;
 	ops->reset = sde_hw_ctl_reset_control;
 	ops->hard_reset = sde_hw_ctl_hard_reset;
@@ -663,27 +694,6 @@
 	}
 };
 
-#define CTL_BASE_OFFSET	0x2000
-#define CTL_TOP_OFFSET(index) (CTL_BASE_OFFSET + (0x200 * (index)) + CTL_TOP)
-
-void sde_get_ctl_top_for_cont_splash(void __iomem *mmio,
-		struct ctl_top *top, int index)
-{
-	if (!mmio || !top) {
-		SDE_ERROR("invalid input parameters\n");
-		return;
-	}
-
-	top->value = readl_relaxed(mmio + CTL_TOP_OFFSET(index));
-	top->intf_sel = (top->value >> 4) & 0xf;
-	top->pp_sel = (top->value >> 8) & 0x7;
-	top->dspp_sel = (top->value >> 11) & 0x3;
-	top->mode_sel = (top->value >> 17) & 0x1;
-
-	SDE_DEBUG("ctl[%d]_top->0x%x,pp_sel=0x%x,dspp_sel=0x%x,intf_sel=0x%x\n",
-	       index, top->value, top->pp_sel, top->dspp_sel, top->intf_sel);
-}
-
 static struct sde_hw_blk_ops sde_hw_ops = {
 	.start = NULL,
 	.stop = NULL,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index f8594da..a9bd104 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -201,6 +201,23 @@
 		enum sde_rot blk);
 
 	/**
+	 * read CTL_TOP register value and return
+	 * the data.
+	 * @ctx		: ctl path ctx pointer
+	 * @return	: CTL top register value
+	 */
+	u32 (*read_ctl_top)(struct sde_hw_ctl *ctx);
+
+	/**
+	 * read CTL layers register value and return
+	 * the data.
+	 * @ctx       : ctl path ctx pointer
+	 * @index       : layer index for this ctl path
+	 * @return	: CTL layers register value
+	 */
+	u32 (*read_ctl_layers)(struct sde_hw_ctl *ctx, int index);
+
+	/**
 	 * Set all blend stages to disabled
 	 * @ctx       : ctl path ctx pointer
 	 */
@@ -269,15 +286,6 @@
 		void __iomem *mmio);
 
 /**
- * sde_get_ctl_top_for_cont_splash - retrieve the current LM blocks
- * @mmio: mapped register io address of MDP
- * @top: pointer to the current "ctl_top" structure thats needs update
- * @index: ctl_top index
- */
-void sde_get_ctl_top_for_cont_splash(void __iomem *mmio,
-		struct ctl_top *top, int index);
-
-/**
  * sde_hw_ctl - convert base object sde_hw_base to container
  * @hw: Pointer to base hardware block
  * return: Pointer to hardware block container
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 134db51..4e677c2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -278,43 +278,6 @@
 	}
 };
 
-#define CTL_BASE_OFFSET	0x2000
-#define CTL_TOP_LM_OFFSET(index, lm)	\
-	(CTL_BASE_OFFSET + (0x200 * index) + (lm * 0x4))
-
-int sde_get_ctl_lm_for_cont_splash(void __iomem *mmio, int max_lm_cnt,
-		u8 lm_cnt, u8 *lm_ids, struct ctl_top *top, int index)
-{
-	int j;
-	struct sde_splash_lm_hw *lm;
-
-	if (!mmio || !top || !lm_ids) {
-		SDE_ERROR("invalid input parameters\n");
-		return 0;
-	}
-
-	lm = top->lm;
-	for (j = 0; j < max_lm_cnt; j++) {
-		lm[top->ctl_lm_cnt].lm_reg_value = readl_relaxed(mmio
-			      + CTL_TOP_LM_OFFSET(index, j));
-		SDE_DEBUG("ctl[%d]_top --> lm[%d]=0x%x, j=%d\n",
-			index, top->ctl_lm_cnt,
-			lm[top->ctl_lm_cnt].lm_reg_value, j);
-		SDE_DEBUG("lm_cnt = %d\n", lm_cnt);
-		if (lm[top->ctl_lm_cnt].lm_reg_value) {
-			lm[top->ctl_lm_cnt].ctl_id = index;
-			lm_ids[lm_cnt++] = j + LM_0;
-			lm[top->ctl_lm_cnt].lm_id = j + LM_0;
-			SDE_DEBUG("ctl_id=%d, lm[%d].lm_id = %d\n",
-				lm[top->ctl_lm_cnt].ctl_id,
-				top->ctl_lm_cnt,
-				lm[top->ctl_lm_cnt].lm_id);
-			top->ctl_lm_cnt++;
-		}
-	}
-	return top->ctl_lm_cnt;
-}
-
 static struct sde_hw_blk_ops sde_hw_ops = {
 	.start = NULL,
 	.stop = NULL,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
index a2307ec..8a146bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
@@ -117,19 +117,6 @@
 }
 
 /**
- * sde_get_ctl_lm_for_cont_splash - retrieve the current LM blocks
- * @mmio: mapped register io address of MDP
- * @max_lm_cnt: number of LM blocks supported in the hw
- * @lm_cnt: number of LM blocks already active
- * @lm_ids: pointer to store the active LM block IDs
- * @top: pointer to the current "ctl_top" structure
- * @index: ctl_top index
- * return: number of active LM blocks for this CTL block
- */
-int sde_get_ctl_lm_for_cont_splash(void __iomem *mmio, int max_lm_cnt,
-		u8 lm_cnt, u8 *lm_ids, struct ctl_top *top, int index);
-
-/**
  * sde_hw_lm_init(): Initializes the mixer hw driver object.
  * should be called once before accessing every mixer.
  * @idx:  mixer index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index 3125ebf..7977294 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -581,6 +581,7 @@
  * @ctl_top_cnt:stores the active number of MDSS "top" blks of the current mode
  * @lm_cnt:	stores the active number of MDSS "LM" blks for the current mode
  * @dsc_cnt:	stores the active number of MDSS "dsc" blks for the current mode
+ * @cont_splash_en:	Stores the cont_splash status (enabled/disbled)
  */
 struct sde_splash_data {
 	bool smmu_handoff_pending;
@@ -593,6 +594,7 @@
 	u8 ctl_top_cnt;
 	u8 lm_cnt;
 	u8 dsc_cnt;
+	bool cont_splash_en;
 };
 
 #endif  /* _SDE_HW_MDSS_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index 050e21b..2a03785 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -162,6 +162,17 @@
 	SDE_REG_WRITE(c, PP_DSC_MODE, 1);
 }
 
+static u32 sde_hw_pp_get_dsc_status(struct sde_hw_pingpong *pp)
+{
+	struct sde_hw_blk_reg_map *c;
+
+	if (!pp)
+		return 0;
+
+	c = &pp->hw;
+	return SDE_REG_READ(c, PP_DSC_MODE);
+}
+
 static void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp)
 {
 	struct sde_hw_blk_reg_map *c;
@@ -342,6 +353,7 @@
 	ops->setup_dsc = sde_hw_pp_setup_dsc;
 	ops->enable_dsc = sde_hw_pp_dsc_enable;
 	ops->disable_dsc = sde_hw_pp_dsc_disable;
+	ops->get_dsc_status = sde_hw_pp_get_dsc_status;
 	ops->get_autorefresh = sde_hw_pp_get_autorefresh_config;
 	ops->poll_timeout_wr_ptr = sde_hw_pp_poll_timeout_wr_ptr;
 	ops->get_line_count = sde_hw_pp_get_line_count;
@@ -357,49 +369,6 @@
 	}
 };
 
-#define MDP_PP_DSC_OFFSET(index) (0x71000 + (0x800 * index) + 0x0a0)
-#define MDP_PP_AUTOREFRESH_OFFSET(index) (0x71000 + (0x800 * index) + 0x030)
-
-int sde_get_pp_dsc_for_cont_splash(void __iomem *mmio,
-			int max_dsc_cnt, u8 *dsc_ids)
-{
-	int index;
-	int value, dsc_cnt = 0;
-
-	if (!mmio || !dsc_ids) {
-		SDE_ERROR("invalid input parameters\n");
-		return 0;
-	}
-
-	SDE_DEBUG("max_dsc_cnt = %d\n", max_dsc_cnt);
-	for (index = 0; index < max_dsc_cnt; index++) {
-		value = readl_relaxed(mmio
-			      + MDP_PP_DSC_OFFSET(index));
-		SDE_DEBUG("DSC[%d]=0x%x\n",
-					index, value);
-		SDE_DEBUG("dsc_cnt = %d\n", dsc_cnt);
-		if (value) {
-			dsc_ids[dsc_cnt] = index + DSC_0;
-			dsc_cnt++;
-		}
-		value = readl_relaxed(mmio
-			      + MDP_PP_AUTOREFRESH_OFFSET(index));
-		SDE_DEBUG("AUTOREFRESH[%d]=0x%x\n",
-					index, value);
-		if (value) {
-			SDE_DEBUG("Disabling autoreferesh\n");
-			writel_relaxed(0x0, mmio
-				+ MDP_PP_AUTOREFRESH_OFFSET(index));
-			/*
-			 * Wait for one frame update so that auto refresh
-			 * disable is through
-			 */
-			usleep_range(16000, 20000);
-		}
-	}
-	return dsc_cnt;
-}
-
 static struct sde_hw_blk_ops sde_hw_ops = {
 	.start = NULL,
 	.stop = NULL,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
index fef49f4..4911658 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
@@ -128,6 +128,12 @@
 	void (*disable_dsc)(struct sde_hw_pingpong *pp);
 
 	/**
+	 * Get DSC status
+	 * @Return: register value of DSC config
+	 */
+	u32 (*get_dsc_status)(struct sde_hw_pingpong *pp);
+
+	/**
 	 * Program the dither hw block
 	 */
 	int (*setup_dither)(struct sde_hw_pingpong *pp, void *cfg, size_t len);
@@ -161,16 +167,6 @@
 }
 
 /**
- * sde_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks
- * @mmio: mapped register io address of MDP
- * @max_dsc_cnt: number of DSC blocks supported in the hw
- * @dsc_ids: pointer to store the active DSC block IDs
- * return: number of active DSC blocks
- */
-int sde_get_pp_dsc_for_cont_splash(void __iomem *mmio,
-		int max_dsc_cnt, u8 *dsc_ids);
-
-/**
  * sde_hw_pingpong_init - initializes the pingpong driver for the passed
  *	pingpong idx.
  * @idx:  Pingpong index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
index 90a2ca9..6e6a542 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
@@ -266,10 +266,14 @@
 
 	/* no need to register sub-range in sde dbg, dump entire vbif io base */
 
+	mutex_init(&c->mutex);
+
 	return c;
 }
 
 void sde_hw_vbif_destroy(struct sde_hw_vbif *vbif)
 {
+	if (vbif)
+		mutex_destroy(&vbif->mutex);
 	kfree(vbif);
 }
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
index 84f0e04..3b650fe 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.h
@@ -111,6 +111,12 @@
 
 	/* ops */
 	struct sde_hw_vbif_ops ops;
+
+	/*
+	 * vbif is common across all displays, lock to serialize access.
+	 * must be take by client before using any ops
+	 */
+	struct mutex mutex;
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c
index 10435da..e25d8fb 100644
--- a/drivers/gpu/drm/msm/sde/sde_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_irq.c
@@ -104,7 +104,7 @@
 	}
 
 	/* disable irq until power event enables it */
-	if (!sde_kms->cont_splash_en)
+	if (!sde_kms->splash_data.cont_splash_en)
 		irq_set_status_flags(sde_kms->irq_num, IRQ_NOAUTOEN);
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index a54e39a9..f4b362f 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -666,9 +666,9 @@
 
 	SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT);
 
-	if (sde_kms->cont_splash_en) {
+	if (sde_kms->splash_data.cont_splash_en) {
 		SDE_DEBUG("Disabling cont_splash feature\n");
-		sde_kms->cont_splash_en = false;
+		sde_kms->splash_data.cont_splash_en = false;
 		sde_power_resource_enable(&priv->phandle,
 				sde_kms->core_client, false);
 		SDE_DEBUG("removing Vote for MDP Resources\n");
@@ -2165,7 +2165,7 @@
 		return -EINVAL;
 	}
 
-	if (!sde_kms->cont_splash_en) {
+	if (!sde_kms->splash_data.cont_splash_en) {
 		DRM_INFO("cont_splash feature not enabled\n");
 		return rc;
 	}
@@ -2489,68 +2489,6 @@
 	return ret;
 }
 
-/* the caller api needs to turn on clock before calling this function */
-static int _sde_kms_cont_splash_res_init(struct sde_kms *sde_kms)
-{
-	struct sde_mdss_cfg *cat;
-	struct drm_device *dev;
-	struct msm_drm_private *priv;
-	struct sde_splash_data *splash_data;
-	int i;
-	int ctl_top_cnt;
-
-	if (!sde_kms || !sde_kms->catalog) {
-		SDE_ERROR("invalid kms\n");
-		return -EINVAL;
-	}
-	cat = sde_kms->catalog;
-	dev = sde_kms->dev;
-	priv = dev->dev_private;
-	splash_data = &sde_kms->splash_data;
-	SDE_DEBUG("mixer_count=%d, ctl_count=%d, dsc_count=%d\n",
-			cat->mixer_count,
-			cat->ctl_count,
-			cat->dsc_count);
-
-	ctl_top_cnt = cat->ctl_count;
-
-	if (ctl_top_cnt > ARRAY_SIZE(splash_data->top)) {
-		SDE_ERROR("Mismatch in ctl_top array size\n");
-		return -EINVAL;
-	}
-	for (i = 0; i < ctl_top_cnt; i++) {
-		sde_get_ctl_top_for_cont_splash(sde_kms->mmio,
-				&splash_data->top[i], i);
-		if (splash_data->top[i].intf_sel) {
-			splash_data->lm_cnt +=
-				sde_get_ctl_lm_for_cont_splash
-					(sde_kms->mmio,
-					sde_kms->catalog->mixer_count,
-					splash_data->lm_cnt,
-					splash_data->lm_ids,
-					&splash_data->top[i], i);
-			splash_data->ctl_ids[splash_data->ctl_top_cnt]
-							= i + CTL_0;
-			splash_data->ctl_top_cnt++;
-			sde_kms->cont_splash_en = true;
-		}
-	}
-
-	/* Skip DSC blk reads if cont_splash is disabled */
-	if (!sde_kms->cont_splash_en)
-		return 0;
-
-	splash_data->dsc_cnt =
-		sde_get_pp_dsc_for_cont_splash(sde_kms->mmio,
-				sde_kms->catalog->dsc_count,
-				splash_data->dsc_ids);
-	SDE_DEBUG("splash_data: ctl_top_cnt=%d, lm_cnt=%d, dsc_cnt=%d\n",
-		splash_data->ctl_top_cnt, splash_data->lm_cnt,
-		splash_data->dsc_cnt);
-
-	return 0;
-}
-
 static void sde_kms_handle_power_event(u32 event_type, void *usr)
 {
 	struct sde_kms *sde_kms = usr;
@@ -2663,6 +2601,7 @@
 	struct sde_kms *sde_kms;
 	struct drm_device *dev;
 	struct msm_drm_private *priv;
+	struct sde_rm *rm = NULL;
 	bool splash_mem_found = false;
 	int i, rc = -EINVAL;
 
@@ -2787,12 +2726,24 @@
 
 	sde_dbg_init_dbg_buses(sde_kms->core_rev);
 
+	rm = &sde_kms->rm;
+	rc = sde_rm_init(rm, sde_kms->catalog, sde_kms->mmio,
+			sde_kms->dev);
+	if (rc) {
+		SDE_ERROR("rm init failed: %d\n", rc);
+		goto power_error;
+	}
+
+	sde_kms->rm_init = true;
+
 	/*
 	 * Attempt continuous splash handoff only if reserved
 	 * splash memory is found.
 	 */
 	if (splash_mem_found)
-		_sde_kms_cont_splash_res_init(sde_kms);
+		sde_rm_cont_splash_res_init(&sde_kms->rm,
+					&sde_kms->splash_data,
+					sde_kms->catalog);
 
 	/* Initialize reg dma block which is a singleton */
 	rc = sde_reg_dma_init(sde_kms->reg_dma, sde_kms->catalog,
@@ -2807,16 +2758,6 @@
 		SDE_ERROR("sde_kms_mmu_init failed: %d\n", rc);
 		goto power_error;
 	}
-
-	rc = sde_rm_init(&sde_kms->rm, sde_kms->catalog, sde_kms->mmio,
-			sde_kms->dev);
-	if (rc) {
-		SDE_ERROR("rm init failed: %d\n", rc);
-		goto power_error;
-	}
-
-	sde_kms->rm_init = true;
-
 	sde_kms->hw_mdp = sde_rm_get_mdp(&sde_kms->rm);
 	if (IS_ERR_OR_NULL(sde_kms->hw_mdp)) {
 		rc = PTR_ERR(sde_kms->hw_mdp);
@@ -2925,7 +2866,7 @@
 		SDE_DEBUG("added genpd provider %s\n", sde_kms->genpd.name);
 	}
 
-	if (sde_kms->cont_splash_en)
+	if (sde_kms->splash_data.cont_splash_en)
 		SDE_DEBUG("Skipping MDP Resources disable\n");
 	else
 		sde_power_resource_enable(&priv->phandle,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index 501797b..48f85bf 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -216,7 +216,6 @@
 	struct sde_rm rm;
 	bool rm_init;
 	struct sde_splash_data splash_data;
-	bool cont_splash_en;
 	struct sde_hw_vbif *hw_vbif[VBIF_MAX];
 	struct sde_hw_mdp *hw_mdp;
 	int dsi_display_count;
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index c2c1f75..1b71a82 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -1129,6 +1129,204 @@
 	return ret;
 }
 
+/**
+ * sde_rm_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks
+ *	and disable autorefresh if enabled.
+ * @mmio: mapped register io address of MDP
+ * @max_dsc_cnt: number of DSC blocks supported in the hw
+ * @dsc_ids: pointer to store the active DSC block IDs
+ * return: number of active DSC blocks
+ */
+static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm,
+			int max_dsc_cnt, u8 *dsc_ids)
+{
+	int index = 0;
+	int value, dsc_cnt = 0;
+	struct sde_hw_autorefresh cfg;
+	struct sde_rm_hw_iter iter_pp;
+
+	if (!rm || !dsc_ids) {
+		SDE_ERROR("invalid input parameters\n");
+		return 0;
+	}
+
+	SDE_DEBUG("max_dsc_cnt = %d\n", max_dsc_cnt);
+	sde_rm_init_hw_iter(&iter_pp, 0, SDE_HW_BLK_PINGPONG);
+	while (_sde_rm_get_hw_locked(rm, &iter_pp)) {
+		struct sde_hw_pingpong *pp =
+				to_sde_hw_pingpong(iter_pp.blk->hw);
+
+		if (!pp->ops.get_dsc_status) {
+			SDE_ERROR("get_dsc_status ops not initialized\n");
+			return 0;
+		}
+		value = pp->ops.get_dsc_status(pp);
+		SDE_DEBUG("DSC[%d]=0x%x, dsc_cnt = %d\n",
+				index, value, dsc_cnt);
+		if (value) {
+			dsc_ids[dsc_cnt] = index + DSC_0;
+			dsc_cnt++;
+		}
+		index++;
+
+		if (!pp->ops.get_autorefresh) {
+			SDE_ERROR("get_autorefresh api not supported\n");
+			return 0;
+		}
+		memset(&cfg, 0, sizeof(cfg));
+		if (!pp->ops.get_autorefresh(pp, &cfg)
+				&& (cfg.enable)
+				&& (pp->ops.setup_autorefresh)) {
+			cfg.enable = false;
+			SDE_DEBUG("Disabling autoreferesh\n");
+			pp->ops.setup_autorefresh(pp, &cfg);
+			/*
+			 * Wait for one frame update so that
+			 * auto refresh disable is through
+			 */
+			usleep_range(16000, 20000);
+		}
+	}
+
+	return dsc_cnt;
+}
+
+/**
+ * _sde_rm_get_ctl_lm_for_cont_splash - retrieve the current LM blocks
+ * @ctl: Pointer to CTL hardware block
+ * @max_lm_cnt: number of LM blocks supported in the hw
+ * @lm_cnt: number of LM blocks already active
+ * @lm_ids: pointer to store the active LM block IDs
+ * @top: pointer to the current "ctl_top" structure
+ * @index: ctl_top index
+ * return: number of active LM blocks for this CTL block
+ */
+static int _sde_rm_get_ctl_lm_for_cont_splash(struct sde_hw_ctl *ctl,
+				int max_lm_cnt, u8 lm_cnt,
+				u8 *lm_ids, struct ctl_top *top,
+				int index)
+{
+	int j;
+	struct sde_splash_lm_hw *lm;
+
+	if (!ctl || !top || !lm_ids) {
+		SDE_ERROR("invalid input parameters\n");
+		return 0;
+	}
+
+	lm = top->lm;
+	for (j = 0; j < max_lm_cnt; j++) {
+		lm[top->ctl_lm_cnt].lm_reg_value =
+			ctl->ops.read_ctl_layers(ctl, j + LM_0);
+		SDE_DEBUG("ctl[%d]_top --> lm[%d]=0x%x, j=%d\n",
+			index, top->ctl_lm_cnt,
+			lm[top->ctl_lm_cnt].lm_reg_value, j);
+		SDE_DEBUG("lm_cnt = %d\n", lm_cnt);
+		if (lm[top->ctl_lm_cnt].lm_reg_value) {
+			lm[top->ctl_lm_cnt].ctl_id = index;
+			lm_ids[lm_cnt++] = j + LM_0;
+			lm[top->ctl_lm_cnt].lm_id = j + LM_0;
+			SDE_DEBUG("ctl_id=%d, lm[%d].lm_id = %d\n",
+				lm[top->ctl_lm_cnt].ctl_id,
+				top->ctl_lm_cnt,
+				lm[top->ctl_lm_cnt].lm_id);
+			top->ctl_lm_cnt++;
+		}
+	}
+	return top->ctl_lm_cnt;
+}
+
+/**
+ * _sde_rm_get_ctl_top_for_cont_splash - retrieve the current LM blocks
+ * @ctl: Pointer to CTL hardware block
+ * @top: pointer to the current "ctl_top" structure thats needs update
+ * @index: ctl_top index
+ */
+static void _sde_rm_get_ctl_top_for_cont_splash(struct sde_hw_ctl *ctl,
+		struct ctl_top *top)
+{
+	if (!ctl || !top) {
+		SDE_ERROR("invalid input parameters\n");
+		return;
+	}
+
+	if (!ctl->ops.read_ctl_top) {
+		SDE_ERROR("read_ctl_top not initialized\n");
+		return;
+	}
+
+	top->value = ctl->ops.read_ctl_top(ctl);
+	top->intf_sel = (top->value >> 4) & 0xf;
+	top->pp_sel = (top->value >> 8) & 0x7;
+	top->dspp_sel = (top->value >> 11) & 0x3;
+	top->mode_sel = (top->value >> 17) & 0x1;
+
+	SDE_DEBUG("id=%d,top->0x%x,pp_sel=0x%x,dspp_sel=0x%x,intf_sel=%d\n",
+				ctl->idx, top->value, top->pp_sel,
+				top->dspp_sel, top->intf_sel);
+}
+
+int sde_rm_cont_splash_res_init(struct sde_rm *rm,
+				struct sde_splash_data *splash_data,
+				struct sde_mdss_cfg *cat)
+{
+	struct sde_rm_hw_iter iter_c;
+	int index = 0, ctl_top_cnt;
+
+	if (!rm || !cat || !splash_data) {
+		SDE_ERROR("invalid input parameters\n");
+		return -EINVAL;
+	}
+
+	SDE_DEBUG("mixer_count=%d, ctl_count=%d, dsc_count=%d\n",
+			cat->mixer_count,
+			cat->ctl_count,
+			cat->dsc_count);
+
+	ctl_top_cnt = cat->ctl_count;
+
+	if (ctl_top_cnt > ARRAY_SIZE(splash_data->top)) {
+		SDE_ERROR("Mismatch in ctl_top array size\n");
+		return -EINVAL;
+	}
+
+	sde_rm_init_hw_iter(&iter_c, 0, SDE_HW_BLK_CTL);
+	while (_sde_rm_get_hw_locked(rm, &iter_c)) {
+		struct sde_hw_ctl *ctl = to_sde_hw_ctl(iter_c.blk->hw);
+
+		_sde_rm_get_ctl_top_for_cont_splash(ctl,
+					&splash_data->top[index]);
+		if (splash_data->top[index].intf_sel) {
+			splash_data->lm_cnt +=
+				_sde_rm_get_ctl_lm_for_cont_splash
+					(ctl,
+					cat->mixer_count,
+					splash_data->lm_cnt,
+					splash_data->lm_ids,
+					&splash_data->top[index], index);
+			splash_data->ctl_ids[splash_data->ctl_top_cnt]
+							= index + CTL_0;
+			splash_data->ctl_top_cnt++;
+			splash_data->cont_splash_en = true;
+		}
+		index++;
+	}
+
+	/* Skip DSC blk reads if cont_splash is disabled */
+	if (!splash_data->cont_splash_en)
+		return 0;
+
+	splash_data->dsc_cnt =
+		_sde_rm_get_pp_dsc_for_cont_splash(rm,
+				cat->dsc_count,
+				splash_data->dsc_ids);
+	SDE_DEBUG("splash_data: ctl_top_cnt=%d, lm_cnt=%d, dsc_cnt=%d\n",
+		splash_data->ctl_top_cnt, splash_data->lm_cnt,
+		splash_data->dsc_cnt);
+
+	return 0;
+}
+
 static int _sde_rm_make_next_rsvp_for_cont_splash(
 		struct sde_rm *rm,
 		struct drm_encoder *enc,
@@ -1484,7 +1682,7 @@
 	sde_kms = to_sde_kms(priv->kms);
 
 	/* Check if this is just a page-flip */
-	if (!sde_kms->cont_splash_en &&
+	if (!sde_kms->splash_data.cont_splash_en &&
 			!drm_atomic_crtc_needs_modeset(crtc_state))
 		return 0;
 
@@ -1536,7 +1734,7 @@
 	}
 
 	/* Check the proposed reservation, store it in hw's "next" field */
-	if (sde_kms->cont_splash_en) {
+	if (sde_kms->splash_data.cont_splash_en) {
 		SDE_DEBUG("cont_splash feature enabled\n");
 		ret = _sde_rm_make_next_rsvp_for_cont_splash
 			(rm, enc, crtc_state, conn_state, rsvp_nxt, &reqs);
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.h b/drivers/gpu/drm/msm/sde/sde_rm.h
index 0545609..b2dd87d 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.h
+++ b/drivers/gpu/drm/msm/sde/sde_rm.h
@@ -126,7 +126,7 @@
  */
 int sde_rm_init(struct sde_rm *rm,
 		struct sde_mdss_cfg *cat,
-		void *mmio,
+		void __iomem *mmio,
 		struct drm_device *dev);
 
 /**
@@ -207,6 +207,19 @@
 int sde_rm_check_property_topctl(uint64_t val);
 
 /**
+ * sde_rm_cont_splash_res_init - Read the current MDSS configuration
+ *	to update the splash data structure with the topology
+ *	configured by the bootloader.
+ * @rm: SDE Resource Manager handle
+ * @splash_data: Pointer to the splash_data structure to be updated.
+ * @cat: Pointer to the SDE catalog
+ * @Return: 0 on success or error
+ */
+int sde_rm_cont_splash_res_init(struct sde_rm *rm,
+				struct sde_splash_data *splash_data,
+				struct sde_mdss_cfg *cat);
+
+/**
  * sde_rm_update_topology - sets topology property of the connector
  * @conn_state: drm state of the connector
  * @topology: topology selected for the display
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index ef4cdeb..2909778 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -93,21 +93,24 @@
 )
 
 TRACE_EVENT(sde_perf_update_bus,
-	TP_PROTO(int client, unsigned long long ab_quota,
+	TP_PROTO(int client, u32 bus_id, unsigned long long ab_quota,
 	unsigned long long ib_quota),
-	TP_ARGS(client, ab_quota, ib_quota),
+	TP_ARGS(client, bus_id, ab_quota, ib_quota),
 	TP_STRUCT__entry(
 			__field(int, client)
+			__field(u32, bus_id);
 			__field(u64, ab_quota)
 			__field(u64, ib_quota)
 	),
 	TP_fast_assign(
 			__entry->client = client;
+			__entry->bus_id = bus_id;
 			__entry->ab_quota = ab_quota;
 			__entry->ib_quota = ib_quota;
 	),
-	TP_printk("Request client:%d ab=%llu ib=%llu",
+	TP_printk("Request client:%d bus_id:%d ab=%llu ib=%llu",
 			__entry->client,
+			__entry->bus_id,
 			__entry->ab_quota,
 			__entry->ib_quota)
 )
@@ -209,41 +212,111 @@
 )
 
 TRACE_EVENT(sde_perf_crtc_update,
-	TP_PROTO(u32 crtc, u64 bw_ctl_mnoc, u64 bw_ctl_llcc,
-			u64 bw_ctl_ebi, u32 core_clk_rate,
-			bool stop_req, u32 update_bus, u32 update_clk),
-	TP_ARGS(crtc, bw_ctl_mnoc, bw_ctl_llcc, bw_ctl_ebi, core_clk_rate,
-		stop_req, update_bus, update_clk),
+	TP_PROTO(u32 crtc,
+			u64 bw_ctl_mnoc, u64 per_pipe_ib_mnoc,
+			u64 bw_ctl_llcc, u64 per_pipe_ib_llcc,
+			u64 bw_ctl_ebi, u64 per_pipe_ib_ebi,
+			u32 core_clk_rate, bool stop_req,
+			u32 update_bus, u32 update_clk, int params),
+	TP_ARGS(crtc,
+		bw_ctl_mnoc, per_pipe_ib_mnoc,
+		bw_ctl_llcc, per_pipe_ib_llcc,
+		bw_ctl_ebi, per_pipe_ib_ebi,
+		core_clk_rate, stop_req,
+		update_bus, update_clk, params),
+	TP_STRUCT__entry(
+			__field(u32, crtc)
+			__field(u64, bw_ctl_mnoc)
+			__field(u64, per_pipe_ib_mnoc)
+			__field(u64, bw_ctl_llcc)
+			__field(u64, per_pipe_ib_llcc)
+			__field(u64, bw_ctl_ebi)
+			__field(u64, per_pipe_ib_ebi)
+			__field(u32, core_clk_rate)
+			__field(bool, stop_req)
+			__field(u32, update_bus)
+			__field(u32, update_clk)
+			__field(int, params)
+	),
+	TP_fast_assign(
+			__entry->crtc = crtc;
+			__entry->bw_ctl_mnoc = bw_ctl_mnoc;
+			__entry->per_pipe_ib_mnoc = per_pipe_ib_mnoc;
+			__entry->bw_ctl_llcc = bw_ctl_llcc;
+			__entry->per_pipe_ib_llcc = per_pipe_ib_llcc;
+			__entry->bw_ctl_ebi = bw_ctl_ebi;
+			__entry->per_pipe_ib_ebi = per_pipe_ib_ebi;
+			__entry->core_clk_rate = core_clk_rate;
+			__entry->stop_req = stop_req;
+			__entry->update_bus = update_bus;
+			__entry->update_clk = update_clk;
+			__entry->params = params;
+	),
+	 TP_printk(
+		"crtc=%d mnoc=[%llu %llu] llcc=[%llu %llu] ebi=[%llu %llu] clk=%u stop=%d ubus=%d uclk=%d %d",
+			__entry->crtc,
+			__entry->bw_ctl_mnoc,
+			__entry->per_pipe_ib_mnoc,
+			__entry->bw_ctl_llcc,
+			__entry->per_pipe_ib_llcc,
+			__entry->bw_ctl_ebi,
+			__entry->per_pipe_ib_ebi,
+			__entry->core_clk_rate,
+			__entry->stop_req,
+			__entry->update_bus,
+			__entry->update_clk,
+			__entry->params)
+);
+
+TRACE_EVENT(sde_perf_calc_crtc,
+	TP_PROTO(u32 crtc,
+			u64 bw_ctl_mnoc,
+			u64 bw_ctl_llcc,
+			u64 bw_ctl_ebi,
+			u64 ib_mnoc,
+			u64 ib_llcc,
+			u64 ib_ebi,
+			u32 core_clk_rate
+			),
+	TP_ARGS(crtc,
+			bw_ctl_mnoc,
+			bw_ctl_llcc,
+			bw_ctl_ebi,
+			ib_mnoc,
+			ib_llcc,
+			ib_ebi,
+			core_clk_rate),
 	TP_STRUCT__entry(
 			__field(u32, crtc)
 			__field(u64, bw_ctl_mnoc)
 			__field(u64, bw_ctl_llcc)
 			__field(u64, bw_ctl_ebi)
+			__field(u64, ib_mnoc)
+			__field(u64, ib_llcc)
+			__field(u64, ib_ebi)
 			__field(u32, core_clk_rate)
-			__field(bool, stop_req)
-			__field(u32, update_bus)
-			__field(u32, update_clk)
+
 	),
 	TP_fast_assign(
 			__entry->crtc = crtc;
 			__entry->bw_ctl_mnoc = bw_ctl_mnoc;
 			__entry->bw_ctl_llcc = bw_ctl_llcc;
 			__entry->bw_ctl_ebi = bw_ctl_ebi;
+			__entry->ib_mnoc = ib_mnoc;
+			__entry->ib_llcc = ib_llcc;
+			__entry->ib_ebi = ib_ebi;
 			__entry->core_clk_rate = core_clk_rate;
-			__entry->stop_req = stop_req;
-			__entry->update_bus = update_bus;
-			__entry->update_clk = update_clk;
 	),
 	 TP_printk(
-		"crtc=%d bw_mnoc=%llu bw_llcc=%llu bw_ebi=%llu clk_rate=%u stop_req=%d u_bus=%d u_clk=%d",
+		"crtc=%d mnoc=[%llu, %llu] llcc=[%llu %llu] ebi=[%llu, %llu] clk_rate=%u",
 			__entry->crtc,
 			__entry->bw_ctl_mnoc,
+			__entry->ib_mnoc,
 			__entry->bw_ctl_llcc,
+			__entry->ib_llcc,
 			__entry->bw_ctl_ebi,
-			__entry->core_clk_rate,
-			__entry->stop_req,
-			__entry->update_bus,
-			__entry->update_clk)
+			__entry->ib_ebi,
+			__entry->core_clk_rate)
 );
 
 #define SDE_ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
diff --git a/drivers/gpu/drm/msm/sde/sde_vbif.c b/drivers/gpu/drm/msm/sde/sde_vbif.c
index 0dbc027..c19ee82 100644
--- a/drivers/gpu/drm/msm/sde/sde_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_vbif.c
@@ -82,16 +82,22 @@
 		return -EINVAL;
 	}
 
+	mutex_lock(&vbif->mutex);
+
+	SDE_EVT32_VERBOSE(vbif->idx, xin_id);
+
 	/*
 	 * If status is 0, then make sure client clock is not gated
 	 * while halting by forcing it ON only if it was not previously
 	 * forced on. If status is 1 then its already halted.
 	 */
 	status = vbif->ops.get_halt_ctrl(vbif, xin_id);
-	if (status == 0)
-		forced_on = mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, true);
-	else
+	if (status) {
+		mutex_unlock(&vbif->mutex);
 		return 0;
+	}
+
+	forced_on = mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, true);
 
 	/* send halt request for unused plane's xin client */
 	vbif->ops.set_halt_ctrl(vbif, xin_id, true);
@@ -109,6 +115,8 @@
 	if (forced_on)
 		mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, false);
 
+	mutex_unlock(&vbif->mutex);
+
 	return rc;
 }
 
@@ -238,6 +246,10 @@
 			!vbif->ops.set_halt_ctrl)
 		return;
 
+	mutex_lock(&vbif->mutex);
+
+	SDE_EVT32_VERBOSE(vbif->idx, params->xin_id);
+
 	/* set write_gather_en for all write clients */
 	if (vbif->ops.set_write_gather_en && !params->rd)
 		vbif->ops.set_write_gather_en(vbif, params->xin_id);
@@ -265,6 +277,7 @@
 	if (forced_on)
 		mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
 exit:
+	mutex_unlock(&vbif->mutex);
 	return;
 }
 
@@ -300,6 +313,10 @@
 			!vbif->ops.set_halt_ctrl)
 		return false;
 
+	mutex_lock(&vbif->mutex);
+
+	SDE_EVT32_VERBOSE(vbif->idx, params->xin_id);
+
 	if (params->enable) {
 		forced_on = mdp->ops.setup_clk_force_ctrl(mdp,
 				params->clk_ctrl, true);
@@ -317,6 +334,8 @@
 					params->clk_ctrl, false);
 	}
 
+	mutex_unlock(&vbif->mutex);
+
 	return forced_on;
 }
 
@@ -361,6 +380,8 @@
 		return;
 	}
 
+	mutex_lock(&vbif->mutex);
+
 	forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true);
 
 	for (i = 0; i < qos_tbl->npriority_lvl; i++) {
@@ -373,6 +394,8 @@
 
 	if (forced_on)
 		mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false);
+
+	mutex_unlock(&vbif->mutex);
 }
 
 void sde_vbif_clear_errors(struct sde_kms *sde_kms)
@@ -388,12 +411,14 @@
 	for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
 		vbif = sde_kms->hw_vbif[i];
 		if (vbif && vbif->ops.clear_errors) {
+			mutex_lock(&vbif->mutex);
 			vbif->ops.clear_errors(vbif, &pnd, &src);
 			if (pnd || src) {
 				SDE_EVT32(i, pnd, src);
 				SDE_DEBUG("VBIF %d: pnd 0x%X, src 0x%X\n",
 						vbif->idx - VBIF_0, pnd, src);
 			}
+			mutex_unlock(&vbif->mutex);
 		}
 	}
 }
@@ -411,9 +436,11 @@
 	for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) {
 		vbif = sde_kms->hw_vbif[i];
 		if (vbif && vbif->cap && vbif->ops.set_mem_type) {
+			mutex_lock(&vbif->mutex);
 			for (j = 0; j < vbif->cap->memtype_count; j++)
 				vbif->ops.set_mem_type(
 						vbif, j, vbif->cap->memtype[j]);
+			mutex_unlock(&vbif->mutex);
 		}
 	}
 }
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 34a826d..4244c00 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -470,7 +470,7 @@
 
 	pclient->ab[bus_client] = ab_quota;
 	pclient->ib[bus_client] = ib_quota;
-	trace_sde_perf_update_bus(bus_client, ab_quota, ib_quota);
+	trace_sde_perf_update_bus(bus_client, bus_id, ab_quota, ib_quota);
 
 	list_for_each_entry(client, &phandle->power_client_clist, list) {
 		for (i = 0; i < SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX; i++) {
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index 82b1199..429ab01 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -561,6 +561,23 @@
 			msleep(PRIMARY_VBLANK_WORST_CASE_MS);
 		} else {
 			*wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+
+			/* increase refcount, so we wait for the next vsync */
+			atomic_inc(&rsc->rsc_vsync_wait);
+			SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait));
+		}
+	} else if (atomic_read(&rsc->rsc_vsync_wait)) {
+		SDE_EVT32(rsc->primary_client, rsc->current_state,
+			atomic_read(&rsc->rsc_vsync_wait));
+
+		/* Wait for the vsync, if the refcount is set */
+		rc = wait_event_timeout(rsc->rsc_vsync_waitq,
+			atomic_read(&rsc->rsc_vsync_wait) == 0,
+			msecs_to_jiffies(PRIMARY_VBLANK_WORST_CASE_MS*2));
+		if (!rc) {
+			pr_err("Timeout waiting for vsync\n");
+			SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait),
+				SDE_EVTLOG_ERROR);
 		}
 	}
 end:
@@ -600,6 +617,23 @@
 			msleep(PRIMARY_VBLANK_WORST_CASE_MS);
 		} else {
 			*wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+
+			/* increase refcount, so we wait for the next vsync */
+			atomic_inc(&rsc->rsc_vsync_wait);
+			SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait));
+		}
+	} else if (atomic_read(&rsc->rsc_vsync_wait)) {
+		SDE_EVT32(rsc->primary_client, rsc->current_state,
+			atomic_read(&rsc->rsc_vsync_wait));
+
+		/* Wait for the vsync, if the refcount is set */
+		rc = wait_event_timeout(rsc->rsc_vsync_waitq,
+			atomic_read(&rsc->rsc_vsync_wait) == 0,
+			msecs_to_jiffies(PRIMARY_VBLANK_WORST_CASE_MS*2));
+		if (!rc) {
+			pr_err("Timeout waiting for vsync\n");
+			SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait),
+				SDE_EVTLOG_ERROR);
 		}
 	}
 
@@ -608,6 +642,65 @@
 }
 
 /**
+ * sde_rsc_client_get_vsync_refcount() - returns the status of the vsync
+ * refcount, to signal if the client needs to reset the refcounting logic
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: value of the vsync refcount.
+ */
+int sde_rsc_client_get_vsync_refcount(
+		struct sde_rsc_client *caller_client)
+{
+	struct sde_rsc_priv *rsc;
+
+	if (!caller_client) {
+		pr_err("invalid client for rsc state update\n");
+		return -EINVAL;
+	} else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
+		pr_err("invalid rsc index\n");
+		return -EINVAL;
+	}
+
+	rsc = rsc_prv_list[caller_client->rsc_index];
+	if (!rsc)
+		return 0;
+
+	return atomic_read(&rsc->rsc_vsync_wait);
+}
+
+/**
+ * sde_rsc_client_reset_vsync_refcount() - reduces the refcounting
+ * logic that waits for the vsync.
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: zero if refcount was already zero.
+ */
+int sde_rsc_client_reset_vsync_refcount(
+		struct sde_rsc_client *caller_client)
+{
+	struct sde_rsc_priv *rsc;
+	int ret;
+
+	if (!caller_client) {
+		pr_err("invalid client for rsc state update\n");
+		return -EINVAL;
+	} else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
+		pr_err("invalid rsc index\n");
+		return -EINVAL;
+	}
+
+	rsc = rsc_prv_list[caller_client->rsc_index];
+	if (!rsc)
+		return 0;
+
+	ret = atomic_add_unless(&rsc->rsc_vsync_wait, -1, 0);
+	wake_up_all(&rsc->rsc_vsync_waitq);
+	SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait));
+
+	return ret;
+}
+
+/**
  * sde_rsc_client_is_state_update_complete() - check if state update is complete
  * RSC state transition is not complete until HW receives VBLANK signal. This
  * function checks RSC HW to determine whether that signal has been received.
@@ -1307,6 +1400,7 @@
 	INIT_LIST_HEAD(&rsc->client_list);
 	INIT_LIST_HEAD(&rsc->event_list);
 	mutex_init(&rsc->client_lock);
+	init_waitqueue_head(&rsc->rsc_vsync_waitq);
 
 	pr_info("sde rsc index:%d probed successfully\n",
 				SDE_RSC_INDEX + counter);
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
index 64b0216..5c62466 100644
--- a/drivers/gpu/drm/msm/sde_rsc_priv.h
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -149,6 +149,8 @@
  *			and ab/ib vote on display rsc
  * master_drm:		Primary client waits for vsync on this drm object based
  *			on crtc id
+ * rsc_vsync_wait:   Refcount to indicate if we have to wait for the vsync.
+ * rsc_vsync_waitq:   Queue to wait for the vsync.
  */
 struct sde_rsc_priv {
 	u32 version;
@@ -177,6 +179,8 @@
 	struct sde_rsc_client *primary_client;
 
 	struct drm_device *master_drm;
+	atomic_t rsc_vsync_wait;
+	wait_queue_head_t rsc_vsync_waitq;
 };
 
 /**
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index b9a2f8d..589417f 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -195,6 +195,35 @@
 	unsigned int ctxt_id;
 };
 
+static const unsigned int a6xx_hlsq_non_ctx_registers[] = {
+	0xBE00, 0xBE01, 0xBE04, 0xBE05, 0xBE08, 0xBE09, 0xBE10, 0xBE15,
+	0xBE20, 0xBE23,
+};
+
+static const unsigned int a6xx_sp_non_ctx_registers[] = {
+	0xAE00, 0xAE04, 0xAE0C, 0xAE0C, 0xAE0F, 0xAE2B, 0xAE30, 0xAE32,
+	0xAE35, 0xAE35, 0xAE3A, 0xAE3F, 0xAE50, 0xAE52,
+};
+
+static const unsigned int a6xx_tp_non_ctx_registers[] = {
+	0xB600, 0xB601, 0xB604, 0xB605, 0xB610, 0xB61B, 0xB620, 0xB623,
+};
+
+static struct a6xx_non_ctx_dbgahb_registers {
+	unsigned int regbase;
+	unsigned int statetype;
+	const unsigned int *regs;
+	unsigned int num_sets;
+	unsigned int offset;
+} a6xx_non_ctx_dbgahb[] = {
+	{ 0x0002F800, 0x40, a6xx_hlsq_non_ctx_registers,
+		ARRAY_SIZE(a6xx_hlsq_non_ctx_registers) / 2 },
+	{ 0x0002B800, 0x20, a6xx_sp_non_ctx_registers,
+		ARRAY_SIZE(a6xx_sp_non_ctx_registers) / 2 },
+	{ 0x0002D800, 0x0, a6xx_tp_non_ctx_registers,
+		ARRAY_SIZE(a6xx_tp_non_ctx_registers) / 2 },
+};
+
 static const unsigned int a6xx_vbif_ver_20xxxxxx_registers[] = {
 	/* VBIF */
 	0x3000, 0x3007, 0x300C, 0x3014, 0x3018, 0x302D, 0x3030, 0x3031,
@@ -210,6 +239,11 @@
 	0x3410, 0x3410, 0x3800, 0x3801,
 };
 
+static const unsigned int a6xx_gbif_registers[] = {
+	/* GBIF */
+	0x3C00, 0X3C0B, 0X3C40, 0X3C47, 0X3CC0, 0X3CD1,
+};
+
 static const unsigned int a6xx_gmu_gx_registers[] = {
 	/* GMU GX */
 	0x1A800, 0x1A800, 0x1A810, 0x1A813, 0x1A816, 0x1A816, 0x1A818, 0x1A81B,
@@ -303,15 +337,6 @@
 	/* VFD */
 	0xA600, 0xA601, 0xA603, 0xA603, 0xA60A, 0xA60A, 0xA610, 0xA617,
 	0xA630, 0xA630,
-	/* SP */
-	0xAE00, 0xAE04, 0xAE0C, 0xAE0C, 0xAE0F, 0xAE2B, 0xAE30, 0xAE32,
-	0xAE35, 0xAE35, 0xAE3A, 0xAE3F, 0xAE50, 0xAE52,
-	/* TP */
-	0xB600, 0xB601, 0xB604, 0xB605, 0xB610, 0xB61B, 0xB620, 0xB623,
-	/* HLSQ */
-	0xBE00, 0xBE01, 0xBE04, 0xBE05, 0xBE08, 0xBE09, 0xBE10, 0xBE15,
-	0xBE20, 0xBE23,
-
 };
 
 /*
@@ -827,6 +852,106 @@
 	return data_size + sizeof(*header);
 }
 
+static size_t a6xx_legacy_snapshot_non_ctx_dbgahb(struct kgsl_device *device,
+				u8 *buf, size_t remain, void *priv)
+{
+	struct kgsl_snapshot_regs *header =
+				(struct kgsl_snapshot_regs *)buf;
+	struct a6xx_non_ctx_dbgahb_registers *regs =
+				(struct a6xx_non_ctx_dbgahb_registers *)priv;
+	unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+	int count = 0;
+	unsigned int read_sel;
+	int i, j;
+
+	if (!device->snapshot_legacy)
+		return 0;
+
+	/* Figure out how many registers we are going to dump */
+	for (i = 0; i < regs->num_sets; i++) {
+		int start = regs->regs[i * 2];
+		int end = regs->regs[i * 2 + 1];
+
+		count += (end - start + 1);
+	}
+
+	if (remain < (count * 8) + sizeof(*header)) {
+		SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+		return 0;
+	}
+
+	header->count = count;
+
+	read_sel = (regs->statetype & 0xff) << 8;
+	kgsl_regwrite(device, A6XX_HLSQ_DBG_READ_SEL, read_sel);
+
+	for (i = 0; i < regs->num_sets; i++) {
+		unsigned int start = regs->regs[2 * i];
+		unsigned int end = regs->regs[2 * i + 1];
+
+		for (j = start; j <= end; j++) {
+			unsigned int val;
+
+			val = a6xx_read_dbgahb(device, regs->regbase, j);
+			*data++ = j;
+			*data++ = val;
+
+		}
+	}
+	return (count * 8) + sizeof(*header);
+}
+
+static size_t a6xx_snapshot_non_ctx_dbgahb(struct kgsl_device *device, u8 *buf,
+				size_t remain, void *priv)
+{
+	struct kgsl_snapshot_regs *header =
+				(struct kgsl_snapshot_regs *)buf;
+	struct a6xx_non_ctx_dbgahb_registers *regs =
+				(struct a6xx_non_ctx_dbgahb_registers *)priv;
+	unsigned int count = 0;
+	unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+	unsigned int i, k;
+	unsigned int *src;
+
+	if (crash_dump_valid == false)
+		return a6xx_legacy_snapshot_non_ctx_dbgahb(device, buf, remain,
+				regs);
+
+	if (remain < sizeof(*header)) {
+		SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+		return 0;
+	}
+
+	remain -= sizeof(*header);
+
+	src = (unsigned int *)(a6xx_crashdump_registers.hostptr + regs->offset);
+
+	for (i = 0; i < regs->num_sets; i++) {
+		unsigned int start;
+		unsigned int end;
+
+		start = regs->regs[2 * i];
+		end = regs->regs[(2 * i) + 1];
+
+		if (remain < (end - start + 1) * 8) {
+			SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+			goto out;
+		}
+
+		remain -= ((end - start) + 1) * 8;
+
+		for (k = start; k <= end; k++, count++) {
+			*data++ = k;
+			*data++ = *src++;
+		}
+	}
+out:
+	header->count = count;
+
+	/* Return the size of the section */
+	return (count * 8) + sizeof(*header);
+}
+
 static void a6xx_snapshot_dbgahb_regs(struct kgsl_device *device,
 				struct kgsl_snapshot *snapshot)
 {
@@ -846,6 +971,12 @@
 				a6xx_snapshot_cluster_dbgahb, &info);
 		}
 	}
+
+	for (i = 0; i < ARRAY_SIZE(a6xx_non_ctx_dbgahb); i++) {
+		kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_REGS, snapshot,
+			a6xx_snapshot_non_ctx_dbgahb, &a6xx_non_ctx_dbgahb[i]);
+	}
 }
 
 static size_t a6xx_legacy_snapshot_mvc(struct kgsl_device *device, u8 *buf,
@@ -1274,13 +1405,21 @@
 			snapshot, a6xx_snapshot_dbgc_debugbus_block,
 			(void *) &a6xx_dbgc_debugbus_blocks[i]);
 	}
-
-	/* Skip if GPU has GBIF */
-	if (!adreno_has_gbif(adreno_dev))
+	/*
+	 * GBIF has same debugbus as of other GPU blocks hence fall back to
+	 * default path if GPU uses GBIF.
+	 * GBIF uses exactly same ID as of VBIF so use it as it is.
+	 */
+	if (adreno_has_gbif(adreno_dev))
 		kgsl_snapshot_add_section(device,
-				KGSL_SNAPSHOT_SECTION_DEBUGBUS,
-				snapshot, a6xx_snapshot_vbif_debugbus_block,
-				(void *) &a6xx_vbif_debugbus_blocks);
+			KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+			snapshot, a6xx_snapshot_dbgc_debugbus_block,
+			(void *) &a6xx_vbif_debugbus_blocks);
+	else
+		kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+			snapshot, a6xx_snapshot_vbif_debugbus_block,
+			(void *) &a6xx_vbif_debugbus_blocks);
 
 	/* Dump the CX debugbus data if the block exists */
 	if (adreno_is_cx_dbgc_register(device, A6XX_CX_DBGC_CFG_DBGBUS_SEL_A)) {
@@ -1289,6 +1428,17 @@
 				KGSL_SNAPSHOT_SECTION_DEBUGBUS,
 				snapshot, a6xx_snapshot_cx_dbgc_debugbus_block,
 				(void *) &a6xx_cx_dbgc_debugbus_blocks[i]);
+			/*
+			 * Get debugbus for GBIF CX part if GPU has GBIF block
+			 * GBIF uses exactly same ID as of VBIF so use
+			 * it as it is.
+			 */
+			if (adreno_has_gbif(adreno_dev))
+				kgsl_snapshot_add_section(device,
+					KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+					snapshot,
+					a6xx_snapshot_cx_dbgc_debugbus_block,
+					(void *) &a6xx_vbif_debugbus_blocks);
 		}
 	}
 }
@@ -1429,6 +1579,10 @@
 		adreno_snapshot_vbif_registers(device, snapshot,
 			a6xx_vbif_snapshot_registers,
 			ARRAY_SIZE(a6xx_vbif_snapshot_registers));
+	else
+		adreno_snapshot_registers(device, snapshot,
+			a6xx_gbif_registers,
+			ARRAY_SIZE(a6xx_gbif_registers) / 2);
 
 	/* Try to run the crash dumper */
 	if (sptprac_on)
@@ -1594,6 +1748,40 @@
 	return qwords;
 }
 
+static int _a6xx_crashdump_init_non_ctx_dbgahb(uint64_t *ptr, uint64_t *offset)
+{
+	int qwords = 0;
+	unsigned int i, k;
+	unsigned int count;
+
+	for (i = 0; i < ARRAY_SIZE(a6xx_non_ctx_dbgahb); i++) {
+		struct a6xx_non_ctx_dbgahb_registers *regs =
+				&a6xx_non_ctx_dbgahb[i];
+
+		regs->offset = *offset;
+
+		/* Program the aperture */
+		ptr[qwords++] = (regs->statetype & 0xff) << 8;
+		ptr[qwords++] =	(((uint64_t)A6XX_HLSQ_DBG_READ_SEL << 44)) |
+					(1 << 21) | 1;
+
+		for (k = 0; k < regs->num_sets; k++) {
+			unsigned int start = regs->regs[2 * k];
+
+			count = REG_PAIR_COUNT(regs->regs, k);
+			ptr[qwords++] =
+				a6xx_crashdump_registers.gpuaddr + *offset;
+			ptr[qwords++] =
+				(((uint64_t)(A6XX_HLSQ_DBG_AHB_READ_APERTURE +
+					start - regs->regbase / 4) << 44)) |
+							count;
+
+			*offset += count * sizeof(unsigned int);
+		}
+	}
+	return qwords;
+}
+
 void a6xx_crashdump_init(struct adreno_device *adreno_dev)
 {
 	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
@@ -1685,6 +1873,26 @@
 		}
 	}
 
+	/*
+	 * Calculate the script and data size for non context debug
+	 * AHB registers
+	 */
+	for (i = 0; i < ARRAY_SIZE(a6xx_non_ctx_dbgahb); i++) {
+		struct a6xx_non_ctx_dbgahb_registers *regs =
+				&a6xx_non_ctx_dbgahb[i];
+
+		/* 16 bytes for programming the aperture */
+		script_size += 16;
+
+		/* Reading each pair of registers takes 16 bytes */
+		script_size += 16 * regs->num_sets;
+
+		/* A dword per register read from the cluster list */
+		for (k = 0; k < regs->num_sets; k++)
+			data_size += REG_PAIR_COUNT(regs->regs, k) *
+				sizeof(unsigned int);
+	}
+
 	/* Now allocate the script and data buffers */
 
 	/* The script buffers needs 2 extra qwords on the end */
@@ -1735,6 +1943,8 @@
 
 	ptr += _a6xx_crashdump_init_ctx_dbgahb(ptr, &offset);
 
+	ptr += _a6xx_crashdump_init_non_ctx_dbgahb(ptr, &offset);
+
 	*ptr++ = 0;
 	*ptr++ = 0;
 }
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index b81be8f..6876796 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -424,16 +424,6 @@
 		return ERR_PTR(ret);
 	}
 
-	if (gpudev->preemption_context_init) {
-		ret = gpudev->preemption_context_init(&drawctxt->base);
-		if (ret != 0) {
-			kgsl_context_detach(&drawctxt->base);
-			kgsl_context_put(&drawctxt->base);
-			kfree(drawctxt);
-			return ERR_PTR(ret);
-		}
-	}
-
 	kgsl_sharedmem_writel(device, &device->memstore,
 			KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
 			0);
@@ -445,6 +435,14 @@
 
 	INIT_LIST_HEAD(&drawctxt->active_node);
 
+	if (gpudev->preemption_context_init) {
+		ret = gpudev->preemption_context_init(&drawctxt->base);
+		if (ret != 0) {
+			kgsl_context_detach(&drawctxt->base);
+			return ERR_PTR(ret);
+		}
+	}
+
 	/* copy back whatever flags we dediced were valid */
 	*flags = drawctxt->base.flags;
 	return &drawctxt->base;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index ab3ab31..b354ef2 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -796,7 +796,7 @@
 	struct kgsl_iommu_context *ctx;
 	u64 ptbase;
 	u32 contextidr;
-	pid_t tid = 0;
+	pid_t pid = 0;
 	pid_t ptname;
 	struct _mem_entry prev, next;
 	int write;
@@ -851,7 +851,7 @@
 	if (context != NULL) {
 		/* save pagefault timestamp for GFT */
 		set_bit(KGSL_CONTEXT_PRIV_PAGEFAULT, &context->priv);
-		tid = context->tid;
+		pid = context->proc_priv->pid;
 	}
 
 	ctx->fault = 1;
@@ -872,7 +872,7 @@
 	contextidr = KGSL_IOMMU_GET_CTX_REG(ctx, CONTEXTIDR);
 
 	ptname = MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE) ?
-		KGSL_MMU_GLOBAL_PT : tid;
+		KGSL_MMU_GLOBAL_PT : pid;
 	/*
 	 * Trace needs to be logged before searching the faulting
 	 * address in free list as it takes quite long time in
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 5bd52e4..1a2aea9 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -731,7 +731,8 @@
 #define FLASH_VDIP_MARGIN	50000
 #define BOB_EFFICIENCY		900LL
 #define VIN_FLASH_MIN_UV	3300000LL
-static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led)
+static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led,
+					int *max_current)
 {
 	int ocv_uv, ibat_now, voltage_hdrm_mv, rc;
 	int rbatt_uohm = 0;
@@ -747,8 +748,10 @@
 	}
 
 	/* If no battery is connected, return max possible flash current */
-	if (!rbatt_uohm)
-		return FLASH_LED_MAX_TOTAL_CURRENT_MA;
+	if (!rbatt_uohm) {
+		*max_current = FLASH_LED_MAX_TOTAL_CURRENT_MA;
+		return 0;
+	}
 
 	rc = get_property_from_fg(led, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv);
 	if (rc < 0) {
@@ -785,7 +788,7 @@
 		/* Wait for LMH mitigation to take effect */
 		udelay(100);
 
-		return qpnp_flash_led_calc_max_current(led);
+		return qpnp_flash_led_calc_max_current(led, max_current);
 	}
 
 	/*
@@ -825,13 +828,14 @@
 	avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV);
 	pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n",
 		avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh);
-	return min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
+	*max_current = min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
 			(int)(div64_s64(avail_flash_ua, MCONV)));
+	return 0;
 }
 
-static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led)
+static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led,
+						int *thermal_current_lim)
 {
-	int thermal_current_lim = 0;
 	int rc;
 	u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
 
@@ -888,7 +892,7 @@
 
 	/* Look up current limit based on THERMAL_OTST status */
 	if (otst_status)
-		thermal_current_lim =
+		*thermal_current_lim =
 			led->pdata->thermal_derate_current[otst_status >> 1];
 
 	/* Restore THERMAL_THRESHx registers to original values */
@@ -913,23 +917,36 @@
 	if (rc < 0)
 		return rc;
 
-	return thermal_current_lim;
+	return 0;
 }
 
-static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led)
+static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led,
+						int *max_avail_current)
 {
-	int max_avail_current, thermal_current_lim = 0;
+	int thermal_current_lim = 0, rc;
 
 	led->trigger_lmh = false;
-	max_avail_current = qpnp_flash_led_calc_max_current(led);
-	if (led->pdata->thermal_derate_en)
-		thermal_current_lim =
-			qpnp_flash_led_calc_thermal_current_lim(led);
+	rc = qpnp_flash_led_calc_max_current(led, max_avail_current);
+	if (rc < 0) {
+		pr_err("Couldn't calculate max_avail_current, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (led->pdata->thermal_derate_en) {
+		rc = qpnp_flash_led_calc_thermal_current_lim(led,
+			&thermal_current_lim);
+		if (rc < 0) {
+			pr_err("Couldn't calculate thermal_current_lim, rc=%d\n",
+				rc);
+			return rc;
+		}
+	}
 
 	if (thermal_current_lim)
-		max_avail_current = min(max_avail_current, thermal_current_lim);
+		*max_avail_current = min(*max_avail_current,
+					thermal_current_lim);
 
-	return max_avail_current;
+	return 0;
 }
 
 static void qpnp_flash_led_aggregate_max_current(struct flash_node_data *fnode)
@@ -1237,12 +1254,11 @@
 	}
 
 	if (options & QUERY_MAX_CURRENT) {
-		rc = qpnp_flash_led_get_max_avail_current(led);
+		rc = qpnp_flash_led_get_max_avail_current(led, max_current);
 		if (rc < 0) {
 			pr_err("query max current failed, rc=%d\n", rc);
 			return rc;
 		}
-		*max_current = rc;
 	}
 
 	return 0;
@@ -1291,7 +1307,7 @@
 static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	int rc;
+	int rc, max_current = 0;
 	struct flash_switch_data *snode;
 	struct qpnp_flash_led *led;
 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -1299,11 +1315,11 @@
 	snode = container_of(led_cdev, struct flash_switch_data, cdev);
 	led = dev_get_drvdata(&snode->pdev->dev);
 
-	rc = qpnp_flash_led_get_max_avail_current(led);
+	rc = qpnp_flash_led_get_max_avail_current(led, &max_current);
 	if (rc < 0)
 		pr_err("query max current failed, rc=%d\n", rc);
 
-	return snprintf(buf, PAGE_SIZE, "%d\n", rc);
+	return snprintf(buf, PAGE_SIZE, "%d\n", max_current);
 }
 
 /* sysfs attributes exported by flash_led */
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
index f1dfc7c..00ead5d 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
@@ -585,7 +585,7 @@
 		if (rc) {
 			CAM_ERR(CAM_CPAS,
 				"Failed camnoc vote ab[%llu] ib[%llu] rc=%d",
-				0, camnoc_bw, rc);
+				(uint64_t)0, camnoc_bw, rc);
 			goto unlock_axi_port;
 		}
 	}
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
index bff42f4..e57066d 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
@@ -402,7 +402,7 @@
 		(struct cam_fd_hw_cmd_prestart_args *)user_data;
 
 	if (!blob_data || (blob_size == 0)) {
-		CAM_ERR(CAM_FD, "Invalid blob info %pK %d", blob_data,
+		CAM_ERR(CAM_FD, "Invalid blob info %pK %u", blob_data,
 			blob_size);
 		return -EINVAL;
 	}
@@ -417,7 +417,7 @@
 		uint32_t *get_raw_results = (uint32_t *)blob_data;
 
 		if (sizeof(uint32_t) != blob_size) {
-			CAM_ERR(CAM_FD, "Invalid blob size %d %d",
+			CAM_ERR(CAM_FD, "Invalid blob size %lu %u",
 				sizeof(uint32_t), blob_size);
 			return -EINVAL;
 		}
@@ -430,7 +430,7 @@
 			(struct cam_fd_soc_clock_bw_request *)blob_data;
 
 		if (sizeof(struct cam_fd_soc_clock_bw_request) != blob_size) {
-			CAM_ERR(CAM_FD, "Invalid blob size %d %d",
+			CAM_ERR(CAM_FD, "Invalid blob size %lu %u",
 				sizeof(struct cam_fd_soc_clock_bw_request),
 				blob_size);
 			return -EINVAL;
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
index 51c8e4a..640c6f6 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
@@ -127,7 +127,7 @@
 	time_left = wait_for_completion_timeout(&fd_core->reset_complete,
 		msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT));
 	if (time_left <= 0)
-		CAM_WARN(CAM_FD, "HW reset timeout time_left=%d", time_left);
+		CAM_WARN(CAM_FD, "HW reset timeout time_left=%ld", time_left);
 
 	CAM_DBG(CAM_FD, "FD Wrapper SW Sync Reset complete");
 
@@ -157,7 +157,7 @@
 	time_left = wait_for_completion_timeout(&fd_core->halt_complete,
 		msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT));
 	if (time_left <= 0)
-		CAM_WARN(CAM_FD, "HW halt timeout time_left=%d", time_left);
+		CAM_WARN(CAM_FD, "HW halt timeout time_left=%ld", time_left);
 
 	CAM_DBG(CAM_FD, "FD Wrapper Halt complete");
 
@@ -651,7 +651,7 @@
 	}
 
 	if (arg_size != sizeof(struct cam_fd_hw_init_args)) {
-		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+		CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
 			sizeof(struct cam_fd_hw_init_args));
 		return -EINVAL;
 	}
@@ -735,7 +735,7 @@
 	}
 
 	if (arg_size != sizeof(struct cam_fd_hw_deinit_args)) {
-		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+		CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
 			sizeof(struct cam_fd_hw_deinit_args));
 		return -EINVAL;
 	}
@@ -859,7 +859,7 @@
 	}
 
 	if (arg_size != sizeof(struct cam_fd_hw_cmd_start_args)) {
-		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+		CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
 			sizeof(struct cam_fd_hw_cmd_start_args));
 		return -EINVAL;
 	}
@@ -1010,7 +1010,7 @@
 	}
 
 	if (arg_size != sizeof(struct cam_fd_hw_reserve_args)) {
-		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+		CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
 			sizeof(struct cam_fd_hw_reserve_args));
 		return -EINVAL;
 	}
@@ -1079,7 +1079,7 @@
 	}
 
 	if (arg_size != sizeof(struct cam_fd_hw_release_args)) {
-		CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+		CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
 			sizeof(struct cam_fd_hw_release_args));
 		return -EINVAL;
 	}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index d407771..9bdde9c 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1008,8 +1008,7 @@
 		rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
 			&csid_res);
 		if (rc) {
-			CAM_ERR(CAM_ISP, "No more free hw mgr resource",
-				__func__);
+			CAM_ERR(CAM_ISP, "No more free hw mgr resource");
 			goto err;
 		}
 		cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
@@ -2015,6 +2014,7 @@
 	/* clean context */
 	list_del_init(&ctx->list);
 	ctx->ctx_in_use = 0;
+	ctx->is_rdi_only_context = 0;
 	CAM_DBG(CAM_ISP, "Exit...ctx id:%d",
 		ctx->ctx_index);
 	cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx);
@@ -2761,8 +2761,7 @@
 	CAM_DBG(CAM_ISP, "Enter");
 
 	if (!recovery_data) {
-		CAM_ERR(CAM_ISP, "recovery_data parameter is NULL",
-			__func__);
+		CAM_ERR(CAM_ISP, "recovery_data parameter is NULL");
 		return -EINVAL;
 	}
 	recovery_data->no_of_context = 0;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
index 44dc5c4..4bee732 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
@@ -88,7 +88,7 @@
  * @th_list_head:           List of handlers sorted by priority
  * @hdl_idx:                Unique identity of handler assigned on Subscribe.
  *                          Used to Unsubscribe.
- * @rw_lock:                Read-Write Lock for use by controller
+ * @lock:                   Lock for use by controller
  */
 struct cam_irq_controller {
 	const char                     *name;
@@ -101,7 +101,7 @@
 	struct list_head                evt_handler_list_head;
 	struct list_head                th_list_head[CAM_IRQ_PRIORITY_MAX];
 	uint32_t                        hdl_idx;
-	rwlock_t                        rw_lock;
+	spinlock_t                      lock;
 	struct cam_irq_th_payload       th_payload;
 };
 
@@ -208,7 +208,7 @@
 	for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++)
 		INIT_LIST_HEAD(&controller->th_list_head[i]);
 
-	rwlock_init(&controller->rw_lock);
+	spin_lock_init(&controller->lock);
 
 	controller->hdl_idx = 1;
 	*irq_controller = controller;
@@ -304,7 +304,7 @@
 
 	need_lock = !in_irq();
 	if (need_lock)
-		write_lock_irqsave(&controller->rw_lock, flags);
+		spin_lock_irqsave(&controller->lock, flags);
 	for (i = 0; i < controller->num_registers; i++) {
 		controller->irq_register_arr[i].top_half_enable_mask[priority]
 			|= evt_bit_mask_arr[i];
@@ -317,7 +317,7 @@
 			controller->irq_register_arr[i].mask_reg_offset);
 	}
 	if (need_lock)
-		write_unlock_irqrestore(&controller->rw_lock, flags);
+		spin_unlock_irqrestore(&controller->lock, flags);
 
 	list_add_tail(&evt_handler->list_node,
 		&controller->evt_handler_list_head);
@@ -363,7 +363,7 @@
 
 	need_lock = !in_irq();
 	if (need_lock)
-		write_lock_irqsave(&controller->rw_lock, flags);
+		spin_lock_irqsave(&controller->lock, flags);
 	for (i = 0; i < controller->num_registers; i++) {
 		controller->irq_register_arr[i].
 		top_half_enable_mask[evt_handler->priority] |=
@@ -378,7 +378,7 @@
 		controller->irq_register_arr[i].mask_reg_offset);
 	}
 	if (need_lock)
-		write_unlock_irqrestore(&controller->rw_lock, flags);
+		spin_unlock_irqrestore(&controller->lock, flags);
 
 	return rc;
 }
@@ -413,7 +413,7 @@
 
 	need_lock = !in_irq();
 	if (need_lock)
-		write_lock_irqsave(&controller->rw_lock, flags);
+		spin_lock_irqsave(&controller->lock, flags);
 	for (i = 0; i < controller->num_registers; i++) {
 		controller->irq_register_arr[i].
 		top_half_enable_mask[evt_handler->priority] &=
@@ -441,7 +441,7 @@
 				controller->global_clear_offset);
 	}
 	if (need_lock)
-		write_unlock_irqrestore(&controller->rw_lock, flags);
+		spin_unlock_irqrestore(&controller->lock, flags);
 
 	return rc;
 }
@@ -475,7 +475,7 @@
 
 	if (found) {
 		if (need_lock)
-			write_lock_irqsave(&controller->rw_lock, flags);
+			spin_lock_irqsave(&controller->lock, flags);
 		for (i = 0; i < controller->num_registers; i++) {
 			controller->irq_register_arr[i].
 				top_half_enable_mask[evt_handler->priority] &=
@@ -502,7 +502,7 @@
 					controller->global_clear_offset);
 		}
 		if (need_lock)
-			write_unlock_irqrestore(&controller->rw_lock, flags);
+			spin_unlock_irqrestore(&controller->lock, flags);
 
 		kfree(evt_handler->evt_bit_mask_arr);
 		kfree(evt_handler);
@@ -607,9 +607,9 @@
 	if (!controller)
 		return IRQ_NONE;
 
-	CAM_DBG(CAM_ISP, "locking controller %pK name %s rw_lock %pK",
-		controller, controller->name, &controller->rw_lock);
-	read_lock(&controller->rw_lock);
+	CAM_DBG(CAM_ISP, "locking controller %pK name %s lock %pK",
+		controller, controller->name, &controller->lock);
+	spin_lock(&controller->lock);
 	for (i = 0; i < controller->num_registers; i++) {
 		controller->irq_status_arr[i] = cam_io_r_mb(
 			controller->mem_base +
@@ -630,8 +630,8 @@
 					i, j, need_th_processing[j]);
 		}
 	}
-	CAM_DBG(CAM_ISP, "unlocked controller %pK name %s rw_lock %pK",
-		controller, controller->name, &controller->rw_lock);
+	CAM_DBG(CAM_ISP, "unlocked controller %pK name %s lock %pK",
+		controller, controller->name, &controller->lock);
 
 	CAM_DBG(CAM_ISP, "Status Registers read Successful");
 
@@ -648,7 +648,7 @@
 				&controller->th_list_head[i]);
 		}
 	}
-	read_unlock(&controller->rw_lock);
+	spin_unlock(&controller->lock);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index daf515a..4a7eb00 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -2778,7 +2778,8 @@
 		val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
 			csid_reg->csi2_reg->
 			csid_csi2_rx_captured_short_pkt_1_addr);
-		CAM_ERR(CAM_ISP, "CSID:%d short packet ECC :%d", val);
+		CAM_ERR(CAM_ISP, "CSID:%d short packet ECC :%d",
+			csid_hw->hw_intf->hw_idx, val);
 	}
 
 	if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) &&
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
index ed58b41..05ae7cc 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
@@ -172,7 +172,7 @@
 		cam_jpeg_dma_irq,
 		jpeg_dma_dev);
 	if (rc) {
-		CAM_ERR(CAM_JPEG, "%failed to init_soc %d", rc);
+		CAM_ERR(CAM_JPEG, "failed to init_soc %d", rc);
 		goto error_init_soc;
 	}
 
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
index d7a6504..9a711ec 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -119,7 +119,8 @@
 		rc = wait_for_completion_timeout(&cci_dev->
 			cci_master_info[master].report_q[queue], CCI_TIMEOUT);
 		if (rc <= 0) {
-			CAM_ERR(CAM_CCI, "Wait_for_completion_timeout %d");
+			CAM_ERR(CAM_CCI, "Wait_for_completion_timeout: rc: %d",
+				rc);
 			if (rc == 0)
 				rc = -ETIMEDOUT;
 			cam_cci_flush_queue(cci_dev, master);
@@ -312,7 +313,7 @@
 	if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
 		rc = cam_cci_lock_queue(cci_dev, master, queue, 0);
 		if (rc < 0) {
-			CAM_ERR(CAM_CCI, "failed line %d");
+			CAM_ERR(CAM_CCI, "failed rc: %d", rc);
 			return rc;
 		}
 		rc = cam_cci_wait_report_cmd(cci_dev, master, queue);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
index 72b1779..3abdd80 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
@@ -128,7 +128,6 @@
 			i2c_reg_settings.reg_setting = &i2c_reg_array;
 			rc = camera_io_dev_write(&e_ctrl->io_master_info,
 				&i2c_reg_settings);
-
 			if (rc) {
 				CAM_ERR(CAM_EEPROM,
 					"page disable failed rc %d",
@@ -410,10 +409,12 @@
 static int32_t cam_eeprom_parse_memory_map(
 	struct cam_eeprom_memory_block_t *data,
 	void *cmd_buf, int cmd_length, uint16_t *cmd_length_bytes,
-	int16_t num_map)
+	int *num_map)
 {
 	int32_t                            rc = 0;
+	int32_t                            cnt = 0;
 	int32_t                            processed_size = 0;
+	uint8_t                            generic_op_code;
 	struct cam_eeprom_memory_map_t    *map = data->map;
 	struct common_header              *cmm_hdr =
 		(struct common_header *)cmd_buf;
@@ -421,19 +422,30 @@
 	struct cam_cmd_i2c_random_wr      *i2c_random_wr = NULL;
 	struct cam_cmd_i2c_continuous_rd  *i2c_cont_rd = NULL;
 	struct cam_cmd_conditional_wait   *i2c_poll = NULL;
+	struct cam_cmd_unconditional_wait *i2c_uncond_wait = NULL;
 
+	generic_op_code = cmm_hdr->third_byte;
 	switch (cmm_hdr->cmd_type) {
 	case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR:
 		i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf;
-		cmd_length_in_bytes   = sizeof(struct cam_cmd_i2c_random_wr);
+		cmd_length_in_bytes   = sizeof(struct cam_cmd_i2c_random_wr) +
+			((i2c_random_wr->header.count - 1) *
+			sizeof(struct i2c_random_wr_payload));
 
-		map[num_map].page.addr =
-			i2c_random_wr->random_wr_payload[0].reg_addr;
-		map[num_map].page.addr_type = i2c_random_wr->header.addr_type;
-		map[num_map].page.data =
-			i2c_random_wr->random_wr_payload[0].reg_data;
-		map[num_map].page.data_type = i2c_random_wr->header.data_type;
-		map[num_map].page.valid_size = 1;
+		for (cnt = 0; cnt < (i2c_random_wr->header.count);
+			cnt++) {
+			map[*num_map + cnt].page.addr =
+				i2c_random_wr->random_wr_payload[cnt].reg_addr;
+			map[*num_map + cnt].page.addr_type =
+				i2c_random_wr->header.addr_type;
+			map[*num_map + cnt].page.data =
+				i2c_random_wr->random_wr_payload[cnt].reg_data;
+			map[*num_map + cnt].page.data_type =
+				i2c_random_wr->header.data_type;
+			map[*num_map + cnt].page.valid_size = 1;
+		}
+
+		*num_map += (i2c_random_wr->header.count - 1);
 		cmd_buf += cmd_length_in_bytes / sizeof(int32_t);
 		processed_size +=
 			cmd_length_in_bytes;
@@ -442,30 +454,62 @@
 		i2c_cont_rd = (struct cam_cmd_i2c_continuous_rd *)cmd_buf;
 		cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd);
 
-		map[num_map].mem.addr = i2c_cont_rd->reg_addr;
-		map[num_map].mem.addr_type = i2c_cont_rd->header.addr_type;
-		map[num_map].mem.data_type = i2c_cont_rd->header.data_type;
-		map[num_map].mem.valid_size =
+		map[*num_map].mem.addr = i2c_cont_rd->reg_addr;
+		map[*num_map].mem.addr_type = i2c_cont_rd->header.addr_type;
+		map[*num_map].mem.data_type = i2c_cont_rd->header.data_type;
+		map[*num_map].mem.valid_size =
 			i2c_cont_rd->header.count;
 		cmd_buf += cmd_length_in_bytes / sizeof(int32_t);
 		processed_size +=
 			cmd_length_in_bytes;
-		data->num_data += map[num_map].mem.valid_size;
+		data->num_data += map[*num_map].mem.valid_size;
 		break;
 	case CAMERA_SENSOR_CMD_TYPE_WAIT:
-		i2c_poll = (struct cam_cmd_conditional_wait *)cmd_buf;
-		cmd_length_in_bytes = sizeof(struct cam_cmd_conditional_wait);
+		if (generic_op_code ==
+			CAMERA_SENSOR_WAIT_OP_HW_UCND ||
+			generic_op_code ==
+			CAMERA_SENSOR_WAIT_OP_SW_UCND) {
+			i2c_uncond_wait =
+				(struct cam_cmd_unconditional_wait *)cmd_buf;
+			cmd_length_in_bytes =
+				sizeof(struct cam_cmd_unconditional_wait);
 
-		map[num_map].poll.addr = i2c_poll->reg_addr;
-		map[num_map].poll.addr_type = i2c_poll->addr_type;
-		map[num_map].poll.data = i2c_poll->reg_data;
-		map[num_map].poll.data_type = i2c_poll->data_type;
-		map[num_map].poll.delay = i2c_poll->timeout;
-		map[num_map].poll.valid_size = 1;
+			if (*num_map < 1) {
+				CAM_ERR(CAM_EEPROM,
+					"invalid map number, num_map=%d",
+					*num_map);
+				return -EINVAL;
+			}
+
+			/*
+			 * Though delay is added all of them, but delay will
+			 * be applicable to only one of them as only one of
+			 * them will have valid_size set to >= 1.
+			 */
+			map[*num_map - 1].mem.delay = i2c_uncond_wait->delay;
+			map[*num_map - 1].page.delay = i2c_uncond_wait->delay;
+			map[*num_map - 1].pageen.delay = i2c_uncond_wait->delay;
+		} else if (generic_op_code ==
+			CAMERA_SENSOR_WAIT_OP_COND) {
+			i2c_poll = (struct cam_cmd_conditional_wait *)cmd_buf;
+			cmd_length_in_bytes =
+				sizeof(struct cam_cmd_conditional_wait);
+
+			map[*num_map].poll.addr = i2c_poll->reg_addr;
+			map[*num_map].poll.addr_type = i2c_poll->addr_type;
+			map[*num_map].poll.data = i2c_poll->reg_data;
+			map[*num_map].poll.data_type = i2c_poll->data_type;
+			map[*num_map].poll.delay = i2c_poll->timeout;
+			map[*num_map].poll.valid_size = 1;
+		}
+		cmd_buf += cmd_length_in_bytes / sizeof(int32_t);
+		processed_size +=
+			cmd_length_in_bytes;
 		break;
 	default:
 		break;
 	}
+
 	*cmd_length_bytes = processed_size;
 	return rc;
 }
@@ -536,8 +580,8 @@
 			switch (cmm_hdr->cmd_type) {
 			case CAMERA_SENSOR_CMD_TYPE_I2C_INFO:
 				i2c_info = (struct cam_cmd_i2c_info *)cmd_buf;
-				num_map++;
-				map[num_map].saddr = i2c_info->slave_addr;
+				/* Configure the following map slave address */
+				map[num_map + 1].saddr = i2c_info->slave_addr;
 				rc = cam_eeprom_update_slaveInfo(e_ctrl,
 					cmd_buf);
 				cmd_length_in_bytes =
@@ -545,7 +589,6 @@
 				processed_cmd_buf_in_bytes +=
 					cmd_length_in_bytes;
 				cmd_buf += cmd_length_in_bytes/4;
-				e_ctrl->cal_data.num_map = num_map + 1;
 				break;
 			case CAMERA_SENSOR_CMD_TYPE_PWR_UP:
 			case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN:
@@ -564,10 +607,11 @@
 			case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR:
 			case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD:
 			case CAMERA_SENSOR_CMD_TYPE_WAIT:
+				num_map++;
 				rc = cam_eeprom_parse_memory_map(
 					&e_ctrl->cal_data, cmd_buf,
 					total_cmd_buf_in_bytes,
-					&cmd_length_in_bytes, num_map);
+					&cmd_length_in_bytes, &num_map);
 				processed_cmd_buf_in_bytes +=
 					cmd_length_in_bytes;
 				cmd_buf += cmd_length_in_bytes/4;
@@ -576,6 +620,7 @@
 				break;
 			}
 		}
+		e_ctrl->cal_data.num_map = num_map + 1;
 	}
 	return rc;
 }
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
index 55da264..c977fc4 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -17,7 +17,7 @@
 #include "cam_res_mgr_api.h"
 
 int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl,
-	enum cam_flash_state state)
+	bool regulator_enable)
 {
 	int rc = 0;
 
@@ -26,7 +26,7 @@
 		return -EINVAL;
 	}
 
-	if ((state == CAM_FLASH_STATE_START) &&
+	if (regulator_enable &&
 		(flash_ctrl->is_regulator_enabled == false)) {
 		rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,
 			ENABLE_REGULATOR, NULL);
@@ -37,7 +37,7 @@
 		}
 		flash_ctrl->is_regulator_enabled = true;
 		flash_ctrl->flash_state = CAM_FLASH_STATE_START;
-	} else if ((state == CAM_FLASH_STATE_STOP) &&
+	} else if ((!regulator_enable) &&
 		(flash_ctrl->is_regulator_enabled == true)) {
 		rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,
 			DISABLE_REGULATOR, NULL);
@@ -323,18 +323,13 @@
 						rc);
 					goto nrt_del_req;
 				}
-				fctrl->flash_state =
-						CAM_FLASH_STATE_LOW;
 			} else if (flash_data->opcode ==
 				CAMERA_SENSOR_FLASH_OP_OFF) {
-				if (fctrl->flash_state ==
-					CAM_FLASH_STATE_LOW) {
-					rc = cam_flash_off(fctrl);
-					if (rc)
-						CAM_ERR(CAM_FLASH,
-						"LED off failed: %d",
-						rc);
-				}
+				rc = cam_flash_off(fctrl);
+				if (rc)
+					CAM_ERR(CAM_FLASH,
+					"LED off failed: %d",
+					rc);
 			}
 		} else if (fctrl->nrt_info.cmn_attr.cmd_type ==
 			CAMERA_SENSOR_FLASH_CMD_TYPE_RER) {
@@ -360,8 +355,6 @@
 							"Fire Torch Failed");
 						goto nrt_del_req;
 					}
-					fctrl->flash_state =
-						CAM_FLASH_STATE_LOW;
 
 					usleep_range(
 					flash_data->led_on_delay_ms * 1000,
@@ -398,7 +391,6 @@
 						rc);
 					goto apply_setting_err;
 				}
-				fctrl->flash_state = CAM_FLASH_STATE_HIGH;
 			}
 		} else if ((flash_data->opcode ==
 			CAMERA_SENSOR_FLASH_OP_FIRELOW) &&
@@ -413,19 +405,15 @@
 						rc);
 					goto apply_setting_err;
 				}
-				fctrl->flash_state = CAM_FLASH_STATE_LOW;
 			}
 		} else if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) &&
 			(flash_data->cmn_attr.is_settings_valid) &&
 			(flash_data->cmn_attr.request_id == req_id)) {
-			if ((fctrl->flash_state == CAM_FLASH_STATE_LOW) ||
-				(fctrl->flash_state == CAM_FLASH_STATE_HIGH)) {
-				rc = cam_flash_off(fctrl);
-				if (rc) {
-					CAM_ERR(CAM_FLASH,
-						"Flash off failed %d", rc);
-					goto apply_setting_err;
-				}
+			rc = cam_flash_off(fctrl);
+			if (rc) {
+				CAM_ERR(CAM_FLASH,
+					"Flash off failed %d", rc);
+				goto apply_setting_err;
 			}
 		} else {
 			CAM_DBG(CAM_FLASH, "NOP opcode: req_id: %u", req_id);
@@ -553,6 +541,13 @@
 		case CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE: {
 			CAM_DBG(CAM_FLASH,
 				"CAMERA_FLASH_CMD_TYPE_OPS case called");
+			if (fctrl->flash_state != CAM_FLASH_STATE_START) {
+				CAM_ERR(CAM_FLASH,
+					"Rxed Update packets without linking");
+				fctrl->per_frame[frame_offset].
+					cmn_attr.is_settings_valid = false;
+				return -EINVAL;
+			}
 			flash_operation_info =
 				(struct cam_flash_set_on_off *) cmd_buf;
 			if (!flash_operation_info) {
@@ -668,6 +663,14 @@
 		break;
 	}
 	case CAM_PKT_NOP_OPCODE: {
+		if (fctrl->flash_state != CAM_FLASH_STATE_START) {
+			CAM_ERR(CAM_FLASH,
+				"Rxed Update packets without linking");
+			fctrl->per_frame[frame_offset].
+				cmn_attr.is_settings_valid = false;
+			return -EINVAL;
+		}
+
 		CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u",
 			csl_packet->header.request_id);
 		goto update_req_mgr;
@@ -739,9 +742,7 @@
 {
 	int rc = 0, i, j;
 
-	if ((fctrl->flash_state == CAM_FLASH_STATE_LOW) ||
-		(fctrl->flash_state == CAM_FLASH_STATE_HIGH))
-		cam_flash_off(fctrl);
+	cam_flash_off(fctrl);
 
 	for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
 		fctrl->per_frame[i].cmn_attr.request_id = 0;
@@ -760,7 +761,7 @@
 
 	if ((fctrl->flash_state == CAM_FLASH_STATE_START) &&
 		(fctrl->is_regulator_enabled == true)) {
-		rc = cam_flash_prepare(fctrl, CAM_FLASH_STATE_STOP);
+		rc = cam_flash_prepare(fctrl, false);
 		if (rc)
 			CAM_ERR(CAM_FLASH, "Disable Regulator Failed rc: %d",
 				rc);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.h
index d5ea04c..f73409a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.h
@@ -28,7 +28,7 @@
 int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush);
 int cam_flash_off(struct cam_flash_ctrl *fctrl);
 int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl,
-	enum cam_flash_state state);
+	bool regulator_enable);
 void cam_flash_shutdown(struct cam_flash_ctrl *flash_ctrl);
 int cam_flash_stop_dev(struct cam_flash_ctrl *flash_ctrl);
 int cam_flash_release_dev(struct cam_flash_ctrl *fctrl);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
index 2b371a3..e00d4fd 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
@@ -139,7 +139,7 @@
 			goto release_mutex;
 		}
 
-		rc = cam_flash_prepare(fctrl, CAM_FLASH_STATE_START);
+		rc = cam_flash_prepare(fctrl, true);
 		if (rc) {
 			CAM_ERR(CAM_FLASH,
 				"Enable Regulator Failed rc = %d", rc);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h
index bacf088..a1f8f67 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h
@@ -51,9 +51,6 @@
 	CAM_FLASH_STATE_INIT,
 	CAM_FLASH_STATE_ACQUIRE,
 	CAM_FLASH_STATE_START,
-	CAM_FLASH_STATE_LOW,
-	CAM_FLASH_STATE_HIGH,
-	CAM_FLASH_STATE_STOP,
 };
 
 /**
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 97158e4..ec37c84 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -165,6 +165,11 @@
 	}
 
 	case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: {
+		if (s_ctrl->sensor_state != CAM_SENSOR_START) {
+			CAM_ERR(CAM_SENSOR,
+				"Rxed Update packets without linking");
+			return -EINVAL;
+		}
 		i2c_reg_settings =
 			&i2c_data->
 			per_frame[csl_packet->header.request_id %
@@ -185,6 +190,12 @@
 	break;
 	}
 	case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: {
+		if (s_ctrl->sensor_state != CAM_SENSOR_START) {
+			CAM_ERR(CAM_SENSOR,
+				"Rxed Update packets without linking");
+			return -EINVAL;
+		}
+
 		cam_sensor_update_req_mgr(s_ctrl, csl_packet);
 		return rc;
 	}
@@ -1000,7 +1011,6 @@
 					return rc;
 				}
 			}
-			i2c_set->is_settings_valid = 0;
 		}
 	} else {
 		offset = req_id % MAX_PER_FRAME_ARRAY;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index d69ff47..7a6d7fd 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -15,8 +15,8 @@
 
 int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
 	uint32_t addr, uint16_t data, uint32_t data_mask,
-	enum camera_sensor_i2c_type data_type,
 	enum camera_sensor_i2c_type addr_type,
+	enum camera_sensor_i2c_type data_type,
 	uint32_t delay_ms)
 {
 	int16_t mask = data_mask & 0xFF;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
index f6620c0..ec5ed25 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
@@ -110,8 +110,8 @@
  */
 int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
 	uint32_t addr, uint16_t data, uint32_t data_mask,
-	enum camera_sensor_i2c_type data_type,
 	enum camera_sensor_i2c_type addr_type,
+	enum camera_sensor_i2c_type data_type,
 	uint32_t delay_ms);
 
 #include "cam_sensor_i2c.h"
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index 37784b4..535264d 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -421,7 +421,7 @@
 
 		if (power_setting[i].seq_type < SENSOR_MCLK ||
 			power_setting[i].seq_type >= SENSOR_SEQ_TYPE_MAX) {
-			CAM_ERR(CAM_SENSOR, "failed: Invalid Seq type\n",
+			CAM_ERR(CAM_SENSOR, "failed: Invalid Seq type: %d",
 				power_setting[i].seq_type);
 			return -EINVAL;
 		}
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
index f451155..26f2ba1 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
@@ -94,43 +94,19 @@
 	return name;
 }
 
-void cam_debug_log(unsigned int module_id, enum cam_debug_level dbg_level,
-	const char *func, const int line, const char *fmt, ...)
+void cam_debug_log(unsigned int module_id, const char *func, const int line,
+	const char *fmt, ...)
 {
 	char str_buffer[STR_BUFFER_MAX_LENGTH];
 	va_list args;
 
 	va_start(args, fmt);
 
-	switch (dbg_level) {
-	case CAM_LEVEL_DBG:
-		if (debug_mdl & module_id) {
-			vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
-			pr_info("CAM_DBG: %s: %s: %d: %s\n",
-				cam_get_module_name(module_id),
-				func, line, str_buffer);
-			va_end(args);
-		}
-		break;
-	case CAM_LEVEL_ERR:
+	if (debug_mdl & module_id) {
 		vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
-		pr_err("CAM_ERR: %s: %s: %d: %s\n",
-			cam_get_module_name(module_id), func, line, str_buffer);
+		pr_info("CAM_DBG: %s: %s: %d: %s\n",
+			cam_get_module_name(module_id),
+			func, line, str_buffer);
 		va_end(args);
-		break;
-	case CAM_LEVEL_INFO:
-		vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
-		pr_info("CAM_INFO: %s: %s: %d: %s\n",
-			cam_get_module_name(module_id), func, line, str_buffer);
-		va_end(args);
-		break;
-	case CAM_LEVEL_WARN:
-		vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
-		pr_warn("CAM_WARN: %s: %s: %d: %s\n",
-			cam_get_module_name(module_id), func, line, str_buffer);
-		va_end(args);
-		break;
-	default:
-		break;
 	}
 }
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
index c0160c4..4e97100 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
@@ -38,13 +38,6 @@
 
 #define STR_BUFFER_MAX_LENGTH  1024
 
-enum cam_debug_level {
-	CAM_LEVEL_INFO,
-	CAM_LEVEL_WARN,
-	CAM_LEVEL_ERR,
-	CAM_LEVEL_DBG,
-};
-
 /*
  *  cam_debug_log()
  *
@@ -52,15 +45,14 @@
  *               respective debug logs
  *
  * @module_id :  Respective Module ID which is calling this function
- * @dbg_level :  Debug level from cam_module_debug_level enum entries
  * @func      :  Function which is calling to print logs
  * @line      :  Line number associated with the function which is calling
  *               to print log
  * @fmt       :  Formatted string which needs to be print in the log
  *
  */
-void cam_debug_log(unsigned int module_id, enum cam_debug_level dbg_level,
-	const char *func, const int line, const char *fmt, ...);
+void cam_debug_log(unsigned int module_id, const char *func, const int line,
+	const char *fmt, ...);
 
 /*
  * cam_get_module_name()
@@ -80,8 +72,8 @@
  * @args     :  Arguments which needs to be print in log
  */
 #define CAM_ERR(__module, fmt, args...)                            \
-	cam_debug_log(__module, CAM_LEVEL_ERR, __func__, __LINE__, fmt, ##args)
-
+	pr_err("CAM_ERR: %s: %s: %d " fmt "\n",                     \
+		cam_get_module_name(__module), __func__,  __LINE__, ##args)
 /*
  * CAM_WARN
  * @brief    :  This Macro will print warning logs
@@ -91,8 +83,8 @@
  * @args     :  Arguments which needs to be print in log
  */
 #define CAM_WARN(__module, fmt, args...)                           \
-	cam_debug_log(__module, CAM_LEVEL_WARN, __func__, __LINE__, fmt, ##args)
-
+	pr_warn("CAM_WARN: %s: %s: %d " fmt "\n",                     \
+		cam_get_module_name(__module), __func__,  __LINE__, ##args)
 /*
  * CAM_INFO
  * @brief    :  This Macro will print Information logs
@@ -102,8 +94,8 @@
  * @args     :  Arguments which needs to be print in log
  */
 #define CAM_INFO(__module, fmt, args...)                           \
-	cam_debug_log(__module, CAM_LEVEL_INFO, __func__, __LINE__, fmt, ##args)
-
+	pr_info("CAM_INFO: %s: %s: %d " fmt "\n",                     \
+		cam_get_module_name(__module), __func__,  __LINE__, ##args)
 /*
  * CAM_DBG
  * @brief :     This Macro will print debug logs when enabled using GROUP
@@ -113,14 +105,14 @@
  * @args     :  Arguments which needs to be print in log
  */
 #define CAM_DBG(__module, fmt, args...)                            \
-	cam_debug_log(__module, CAM_LEVEL_DBG, __func__, __LINE__, fmt, ##args)
+	cam_debug_log(__module, __func__, __LINE__, fmt, ##args)
 
 /*
  * CAM_ERR_RATE_LIMIT
  * @brief :     This Macro will prevent error print logs with ratelimit
  */
 #define CAM_ERR_RATE_LIMIT(__module, fmt, args...)                 \
-	pr_err_ratelimited("CAM_ERR: %s: %s: %d" fmt "\n",            \
+	pr_err_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n",            \
 		cam_get_module_name(__module), __func__,  __LINE__, ##args)
 
 #endif /* _CAM_DEBUG_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
index aecce12..30ab075 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
@@ -211,7 +211,7 @@
 	rc = cam_mem_get_cpu_buf(cmd_buf->mem_handle, &cpu_addr, &buf_size);
 	if (rc || !cpu_addr || (buf_size == 0)) {
 		CAM_ERR(CAM_UTIL, "Failed in Get cpu addr, rc=%d, cpu_addr=%pK",
-			rc, cpu_addr);
+			rc, (void *)cpu_addr);
 		return rc;
 	}
 
@@ -219,7 +219,7 @@
 
 	CAM_DBG(CAM_UTIL,
 		"GenericCmdBuffer cpuaddr=%pK, blobptr=%pK, len=%d",
-		cpu_addr, blob_ptr, cmd_buf->length);
+		(void *)cpu_addr, (void *)blob_ptr, cmd_buf->length);
 
 	len_read = 0;
 	while (len_read < cmd_buf->length) {
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 07fb944..786107b 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
@@ -132,7 +132,7 @@
 	uint32_t clk_index, unsigned long clk_rate)
 {
 	if (!soc_info || (clk_index >= soc_info->num_clk) || (clk_rate == 0)) {
-		CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d %lld",
+		CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d %lu",
 			soc_info, clk_index, clk_rate);
 		return clk_rate;
 	}
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 dd0c04d..43d17d9 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -1337,7 +1337,23 @@
 int sde_rotator_inline_get_dst_pixfmt(struct platform_device *pdev,
 		u32 src_pixfmt, u32 *dst_pixfmt)
 {
-	return sde_rot_get_base_tilea5x_pixfmt(src_pixfmt, dst_pixfmt);
+	int rc;
+
+	if (!src_pixfmt || !dst_pixfmt)
+		return -EINVAL;
+
+	rc = sde_rot_get_base_tilea5x_pixfmt(src_pixfmt, dst_pixfmt);
+	if (rc)
+		return rc;
+
+	/*
+	 * Currently, NV21 tile is not supported as output; hence,
+	 * override with NV12 tile.
+	 */
+	if (*dst_pixfmt == SDE_PIX_FMT_Y_CRCB_H2V2_TILE)
+		*dst_pixfmt = SDE_PIX_FMT_Y_CBCR_H2V2_TILE;
+
+	return 0;
 }
 EXPORT_SYMBOL(sde_rotator_inline_get_dst_pixfmt);
 
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 01aa1e4..c94830a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -421,6 +421,7 @@
 static const u32 sde_hw_rotator_v4_inpixfmts_sbuf[] = {
 	SDE_PIX_FMT_Y_CBCR_H2V2_P010,
 	SDE_PIX_FMT_Y_CBCR_H2V2,
+	SDE_PIX_FMT_Y_CRCB_H2V2,
 	SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC,
 	SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC,
 	SDE_PIX_FMT_Y_CBCR_H2V2_UBWC,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 4c000b7..80914e8 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -5488,8 +5488,9 @@
 	input_height = inst->prop.height[OUTPUT_PORT];
 	input_width = inst->prop.width[OUTPUT_PORT];
 
-	if (input_width % 2 != 0 || input_height % 2 != 0 ||
-			output_width % 2 != 0 || output_height % 2 != 0) {
+	if (inst->session_type == MSM_VIDC_ENCODER && (input_width % 2 != 0 ||
+			input_height % 2 != 0 || output_width % 2 != 0 ||
+			output_height % 2 != 0)) {
 		dprintk(VIDC_ERR,
 			"Height and Width should be even numbers for NV12\n");
 		dprintk(VIDC_ERR,
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 4c4835d..a1ae681 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1943,7 +1943,7 @@
 }
 
 static int __qseecom_process_blocked_on_listener_smcinvoke(
-			struct qseecom_command_scm_resp *resp)
+			struct qseecom_command_scm_resp *resp, uint32_t app_id)
 {
 	struct qseecom_registered_listener_list *list_ptr;
 	int ret = 0;
@@ -1990,9 +1990,18 @@
 			&ireq, sizeof(ireq),
 			&continue_resp, sizeof(continue_resp));
 	if (ret) {
-		pr_err("scm_call for continue blocked req for session %d failed, ret %d\n",
-			session_id, ret);
-		goto exit;
+		/* retry with legacy cmd */
+		qseecom.smcinvoke_support = false;
+		ireq.app_or_session_id = app_id;
+		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+			&ireq, sizeof(ireq),
+			&continue_resp, sizeof(continue_resp));
+		qseecom.smcinvoke_support = true;
+		if (ret) {
+			pr_err("cont block req for app %d or session %d fail\n",
+				app_id, session_id);
+			goto exit;
+		}
 	}
 	resp->result = QSEOS_RESULT_INCOMPLETE;
 exit:
@@ -2009,7 +2018,7 @@
 			resp, ptr_app, data);
 	else
 		return __qseecom_process_blocked_on_listener_smcinvoke(
-			resp);
+			resp, data->client.app_id);
 }
 static int __qseecom_reentrancy_process_incomplete_cmd(
 					struct qseecom_dev_handle *data,
@@ -4790,6 +4799,9 @@
 	resp.resp_type = desc->ret[1]; /*incomplete:unused;blocked:session_id*/
 	resp.data = desc->ret[2];	/*listener_id*/
 
+	dummy_private_data.client.app_id = desc->ret[1];
+	dummy_app_entry.app_id = desc->ret[1];
+
 	mutex_lock(&app_access_lock);
 	if (qseecom.qsee_reentrancy_support)
 		ret = __qseecom_process_reentrancy(&resp, &dummy_app_entry,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c172be9..89edc6d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2320,8 +2320,10 @@
 	spin_unlock_irqrestore(&host->lock, flags);
 	remove_wait_queue(&host->wq, &wait);
 
-	if (pm)
+	if (pm) {
+		mmc_host_clk_hold(host);
 		pm_runtime_get_sync(mmc_dev(host));
+	}
 
 	if (host->ops->enable && !stop && host->claim_cnt == 1)
 		host->ops->enable(host);
@@ -2360,8 +2362,10 @@
 			mmc_delay(10);
 	} while (!claimed_host && retry_cnt--);
 
-	if (pm)
+	if (pm) {
+		mmc_host_clk_hold(host);
 		pm_runtime_get_sync(mmc_dev(host));
+	}
 
 	if (host->ops->enable && claimed_host && host->claim_cnt == 1)
 		host->ops->enable(host);
@@ -2396,6 +2400,7 @@
 		wake_up(&host->wq);
 		pm_runtime_mark_last_busy(mmc_dev(host));
 		pm_runtime_put_autosuspend(mmc_dev(host));
+		mmc_host_clk_release(host);
 	}
 }
 EXPORT_SYMBOL(mmc_release_host);
diff --git a/drivers/net/wireless/cnss_utils/cnss_utils.c b/drivers/net/wireless/cnss_utils/cnss_utils.c
index 4955130..77a58c8 100644
--- a/drivers/net/wireless/cnss_utils/cnss_utils.c
+++ b/drivers/net/wireless/cnss_utils/cnss_utils.c
@@ -13,8 +13,10 @@
 #define pr_fmt(fmt) "cnss_utils: " fmt
 
 #include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/etherdevice.h>
+#include <linux/debugfs.h>
 #include <net/cnss_utils.h>
 
 #define CNSS_MAX_CH_NUM 45
@@ -29,6 +31,7 @@
 };
 
 #define MAX_NO_OF_MAC_ADDR 4
+#define MAC_PREFIX_LEN 2
 struct cnss_wlan_mac_addr {
 	u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
 	u32 no_of_mac_addr_set;
@@ -50,6 +53,7 @@
 	struct cnss_wlan_mac_addr wlan_mac_addr;
 	struct cnss_wlan_mac_addr wlan_der_mac_addr;
 	enum cnss_utils_cc_src cc_source;
+	struct dentry *root_dentry;
 } *cnss_utils_priv;
 
 int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
@@ -317,6 +321,137 @@
 }
 EXPORT_SYMBOL(cnss_utils_get_cc_source);
 
+static ssize_t cnss_utils_mac_write(struct file *fp,
+				    const char __user *user_buf,
+				    size_t count, loff_t *off)
+{
+	struct cnss_utils_priv *priv =
+		((struct seq_file *)fp->private_data)->private;
+	char buf[128];
+	char *input, *mac_type, *mac_address;
+	u8 *dest_mac;
+	u8 val;
+	const char *delim = " \n";
+	size_t len = 0;
+	char temp[3] = "";
+
+	len = min_t(size_t, count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EINVAL;
+	buf[len] = '\0';
+
+	input = buf;
+
+	mac_type = strsep(&input, delim);
+	if (!mac_type)
+		return -EINVAL;
+	if (!input)
+		return -EINVAL;
+
+	mac_address = strsep(&input, delim);
+	if (!mac_address)
+		return -EINVAL;
+	if (strncmp("0x", mac_address, MAC_PREFIX_LEN)) {
+		pr_err("Invalid MAC prefix\n");
+		return -EINVAL;
+	}
+
+	len = strlen(mac_address);
+	mac_address += MAC_PREFIX_LEN;
+	len -= MAC_PREFIX_LEN;
+	if (len < ETH_ALEN * 2 || len > ETH_ALEN * 2 * MAX_NO_OF_MAC_ADDR ||
+	    len % (ETH_ALEN * 2) != 0) {
+		pr_err("Invalid MAC address length %zu\n", len);
+		return -EINVAL;
+	}
+
+	if (!strcmp("provisioned", mac_type)) {
+		dest_mac = &priv->wlan_mac_addr.mac_addr[0][0];
+		priv->wlan_mac_addr.no_of_mac_addr_set = len / (ETH_ALEN * 2);
+	} else if (!strcmp("derived", mac_type)) {
+		dest_mac = &priv->wlan_der_mac_addr.mac_addr[0][0];
+		priv->wlan_der_mac_addr.no_of_mac_addr_set =
+			len / (ETH_ALEN * 2);
+	} else {
+		pr_err("Invalid MAC address type %s\n", mac_type);
+		return -EINVAL;
+	}
+
+	while (len--) {
+		temp[0] = *mac_address++;
+		temp[1] = *mac_address++;
+		if (kstrtou8(temp, 16, &val))
+			return -EINVAL;
+		*dest_mac++ = val;
+	}
+	return count;
+}
+
+static int cnss_utils_mac_show(struct seq_file *s, void *data)
+{
+	u8 mac[6];
+	int i;
+	struct cnss_utils_priv *priv = s->private;
+	struct cnss_wlan_mac_addr *addr = NULL;
+
+	addr = &priv->wlan_mac_addr;
+	if (addr->no_of_mac_addr_set) {
+		seq_puts(s, "\nProvisioned MAC addresseses\n");
+		for (i = 0; i < addr->no_of_mac_addr_set; i++) {
+			ether_addr_copy(mac, addr->mac_addr[i]);
+			seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+				   mac[0], mac[1], mac[2],
+				   mac[3], mac[4], mac[5]);
+		}
+	}
+
+	addr = &priv->wlan_der_mac_addr;
+	if (addr->no_of_mac_addr_set) {
+		seq_puts(s, "\nDerived MAC addresseses\n");
+		for (i = 0; i < addr->no_of_mac_addr_set; i++) {
+			ether_addr_copy(mac, addr->mac_addr[i]);
+			seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+				   mac[0], mac[1], mac[2],
+				   mac[3], mac[4], mac[5]);
+		}
+	}
+
+	return 0;
+}
+
+static int cnss_utils_mac_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cnss_utils_mac_show, inode->i_private);
+}
+
+static const struct file_operations cnss_utils_mac_fops = {
+	.read		= seq_read,
+	.write		= cnss_utils_mac_write,
+	.release	= single_release,
+	.open		= cnss_utils_mac_open,
+	.owner		= THIS_MODULE,
+	.llseek		= seq_lseek,
+};
+
+static int cnss_utils_debugfs_create(struct cnss_utils_priv *priv)
+{
+	int ret = 0;
+	struct dentry *root_dentry;
+
+	root_dentry = debugfs_create_dir("cnss_utils", NULL);
+
+	if (IS_ERR(root_dentry)) {
+		ret = PTR_ERR(root_dentry);
+		pr_err("Unable to create debugfs %d\n", ret);
+		goto out;
+	}
+	priv->root_dentry = root_dentry;
+	debugfs_create_file("mac_address", 0600, root_dentry, priv,
+			    &cnss_utils_mac_fops);
+out:
+	return ret;
+}
+
 static int __init cnss_utils_init(void)
 {
 	struct cnss_utils_priv *priv = NULL;
@@ -329,7 +464,7 @@
 
 	mutex_init(&priv->unsafe_channel_list_lock);
 	spin_lock_init(&priv->dfs_nol_info_lock);
-
+	cnss_utils_debugfs_create(priv);
 	cnss_utils_priv = priv;
 
 	return 0;
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index ad3e1e7..ffcd001 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -743,6 +743,15 @@
 			continue;
 
 		event = hw_events->events[idx];
+		if (!event)
+			continue;
+
+		/*
+		 * Check if an attempt was made to free this event during
+		 * the CPU went offline.
+		 */
+		if (event->state == PERF_EVENT_STATE_ZOMBIE)
+			continue;
 
 		switch (cmd) {
 		case CPU_PM_ENTER:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
index ca022b5..b2f203a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
@@ -18,7 +18,7 @@
 /* internal to ipa */
 #define IPA_PM_MAX_CLIENTS 10
 #define IPA_PM_MAX_EX_CL 64
-#define IPA_PM_THRESHOLD_MAX 2
+#define IPA_PM_THRESHOLD_MAX 5
 #define IPA_PM_EXCEPTION_MAX 2
 #define IPA_PM_DEFERRED_TIMEOUT 100
 #define IPA_PM_STATE_MAX 7
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index fb29d00..86d50f6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -1205,25 +1205,25 @@
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 18, 12, 6, 9, IPA_EE_AP } },
+			{ 18, 11, 6, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_WLAN2_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 20, 14, 9, 9, IPA_EE_AP } },
+			{ 20, 13, 9, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_WLAN3_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 21, 15, 9, 9, IPA_EE_AP } },
+			{ 21, 14, 9, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_USB_CONS]            = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 19, 13, 9, 9, IPA_EE_AP } },
+			{ 19, 12, 9, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_USB_DPL_CONS]        = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
@@ -1291,19 +1291,19 @@
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 18, 12, 6, 9, IPA_EE_AP } },
+			{ 18, 11, 6, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_TEST3_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 20, 14, 9, 9, IPA_EE_AP } },
+			{ 20, 13, 9, 9, IPA_EE_AP } },
 	[IPA_4_0][IPA_CLIENT_TEST4_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 21, 15, 9, 9, IPA_EE_AP } },
+			{ 21, 14, 9, 9, IPA_EE_AP } },
 	/* Dummy consumer (pipe 31) is used in L2TP rt rule */
 	[IPA_4_0][IPA_CLIENT_DUMMY_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
@@ -1404,7 +1404,7 @@
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 19, 13, 9, 9, IPA_EE_AP } },
+			{ 19, 12, 9, 9, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_USB_DPL_CONS]        = {
 			true, IPA_v4_0_MHI_GROUP_DDR,
 			false,
@@ -1446,13 +1446,13 @@
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 20, 14, 9, 9, IPA_EE_AP } },
+			{ 20, 13, 9, 9, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = {
 			true, IPA_v4_0_MHI_GROUP_DMA,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 21, 15, 9, 9, IPA_EE_AP } },
+			{ 21, 14, 9, 9, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
@@ -1477,19 +1477,19 @@
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 18, 12, 6, 9, IPA_EE_AP } },
+			{ 18, 11, 6, 9, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_TEST3_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_DDR,
-			{ 20, 14, 9, 9, IPA_EE_AP } },
+			{ 20, 13, 9, 9, IPA_EE_AP } },
 	[IPA_4_0_MHI][IPA_CLIENT_TEST4_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
 			false,
 			IPA_DPS_HPS_SEQ_TYPE_INVALID,
 			QMB_MASTER_SELECT_PCIE,
-			{ 21, 15, 9, 9, IPA_EE_AP } },
+			{ 21, 14, 9, 9, IPA_EE_AP } },
 	/* Dummy consumer (pipe 31) is used in L2TP rt rule */
 	[IPA_4_0_MHI][IPA_CLIENT_DUMMY_CONS]          = {
 			true, IPA_v4_0_GROUP_UL_DL,
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 66d4b10..0444b67 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -2455,8 +2455,14 @@
 				ret);
 		goto config_err;
 	}
+
+	/*
+	 * for IPA 4.0 offline charge is not needed and we need to prevent
+	 * power collapse until IPA uC is loaded.
+	 */
 	atomic_set(&rmnet_ipa3_ctx->is_initialized, 1);
-	if (!atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
+	if (!atomic_read(&rmnet_ipa3_ctx->is_ssr) && ipa3_ctx->ipa_hw_type !=
+		IPA_HW_v4_0) {
 		/* offline charging mode */
 		ipa3_proxy_clk_unvote();
 	}
diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c
index f64e9de..4c0531f 100644
--- a/drivers/platform/msm/msm_11ad/msm_11ad.c
+++ b/drivers/platform/msm/msm_11ad/msm_11ad.c
@@ -33,16 +33,14 @@
 #include "wil_platform.h"
 #include "msm_11ad.h"
 
-#define WIGIG_VENDOR (0x1ae9)
-#define WIGIG_DEVICE (0x0310)
-
 #define SMMU_BASE	0x20000000 /* Device address range base */
 #define SMMU_SIZE	((SZ_1G * 4ULL) - SMMU_BASE)
 
 #define WIGIG_ENABLE_DELAY	50
 
 #define WIGIG_SUBSYS_NAME	"WIGIG"
-#define WIGIG_RAMDUMP_SIZE    0x200000 /* maximum ramdump size */
+#define WIGIG_RAMDUMP_SIZE_SPARROW	0x200000 /* maximum ramdump size */
+#define WIGIG_RAMDUMP_SIZE_TALYN	0x400000 /* maximum ramdump size */
 #define WIGIG_DUMP_FORMAT_VER   0x1
 #define WIGIG_DUMP_MAGIC_VER_V1 0x57474947
 #define VDD_MIN_UV	1028000
@@ -61,6 +59,18 @@
 static const char * const gpio_en_name = "qcom,wigig-en";
 static const char * const sleep_clk_en_name = "qcom,sleep-clk-en";
 
+struct wigig_pci {
+	struct pci_device_id pci_dev;
+	u32 ramdump_sz;
+};
+
+static const struct wigig_pci wigig_pci_tbl[] = {
+	{ .pci_dev = { PCI_DEVICE(0x1ae9, 0x0310) },
+	  .ramdump_sz = WIGIG_RAMDUMP_SIZE_SPARROW},
+	{ .pci_dev = { PCI_DEVICE(0x17cb, 0x1201) },
+	  .ramdump_sz = WIGIG_RAMDUMP_SIZE_TALYN},
+};
+
 struct msm11ad_vreg {
 	const char *name;
 	struct regulator *reg;
@@ -113,6 +123,7 @@
 	void *ramdump_addr;
 	struct msm_dump_data dump_data;
 	struct ramdump_device *ramdump_dev;
+	u32 ramdump_size;
 
 	/* external vregs and clocks */
 	struct msm11ad_vreg vdd;
@@ -859,7 +870,7 @@
 {
 	if (ctx->rops.ramdump && ctx->wil_handle) {
 		int rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
-					   WIGIG_RAMDUMP_SIZE);
+					   ctx->ramdump_size);
 		if (rc) {
 			dev_err(ctx->dev, "ramdump failed : %d\n", rc);
 			return -EINVAL;
@@ -898,7 +909,7 @@
 
 	memset(&segment, 0, sizeof(segment));
 	segment.v_address = ctx->ramdump_addr;
-	segment.size = WIGIG_RAMDUMP_SIZE;
+	segment.size = ctx->ramdump_size;
 
 	return do_ramdump(ctx->ramdump_dev, &segment, 1);
 }
@@ -961,14 +972,14 @@
 	}
 
 	/* register ramdump area */
-	ctx->ramdump_addr = kmalloc(WIGIG_RAMDUMP_SIZE, GFP_KERNEL);
+	ctx->ramdump_addr = kmalloc(ctx->ramdump_size, GFP_KERNEL);
 	if (!ctx->ramdump_addr) {
 		rc = -ENOMEM;
 		goto out_rc;
 	}
 
 	ctx->dump_data.addr = virt_to_phys(ctx->ramdump_addr);
-	ctx->dump_data.len = WIGIG_RAMDUMP_SIZE;
+	ctx->dump_data.len = ctx->ramdump_size;
 	dump_entry.id = MSM_DUMP_DATA_WIGIG;
 	dump_entry.addr = virt_to_phys(&ctx->dump_data);
 
@@ -1031,8 +1042,9 @@
 	struct device_node *rc_node;
 	struct pci_dev *pcidev = NULL;
 	u32 smmu_mapping[2];
-	int rc;
+	int rc, i;
 	u32 val;
+	bool pcidev_found = false;
 
 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
@@ -1118,7 +1130,7 @@
 	rc = msm_11ad_init_vregs(ctx);
 	if (rc) {
 		dev_err(ctx->dev, "msm_11ad_init_vregs failed: %d\n", rc);
-		goto out_bus_scale;
+		return rc;
 	}
 	rc = msm_11ad_enable_vregs(ctx);
 	if (rc) {
@@ -1161,21 +1173,32 @@
 		goto out_rc;
 	}
 	/* search for PCIE device in our domain */
-	do {
-		pcidev = pci_get_device(WIGIG_VENDOR, WIGIG_DEVICE, pcidev);
-		if (!pcidev)
-			break;
+	for (i = 0; i < ARRAY_SIZE(wigig_pci_tbl); ++i) {
+		do {
+			pcidev = pci_get_device(wigig_pci_tbl[i].pci_dev.vendor,
+						wigig_pci_tbl[i].pci_dev.device,
+						pcidev);
+			if (!pcidev)
+				break;
 
-		if (pci_domain_nr(pcidev->bus) == ctx->rc_index)
+			if (pci_domain_nr(pcidev->bus) == ctx->rc_index) {
+				ctx->ramdump_size = wigig_pci_tbl[i].ramdump_sz;
+				pcidev_found = true;
+				break;
+			}
+		} while (true);
+
+		if (pcidev_found)
 			break;
-	} while (true);
-	if (!pcidev) {
+	}
+	if (!pcidev_found) {
 		rc = -ENODEV;
-		dev_err(ctx->dev, "Wigig device %4x:%4x not found\n",
-			WIGIG_VENDOR, WIGIG_DEVICE);
+		dev_err(ctx->dev, "Wigig device not found\n");
 		goto out_rc;
 	}
 	ctx->pcidev = pcidev;
+	dev_dbg(ctx->dev, "Wigig device %4x:%4x found\n",
+		ctx->pcidev->vendor, ctx->pcidev->device);
 
 	rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number,
 				 pcidev, NULL, 0);
@@ -1267,8 +1290,6 @@
 	msm_11ad_release_clocks(ctx);
 	msm_11ad_disable_vregs(ctx);
 	msm_11ad_release_vregs(ctx);
-out_bus_scale:
-	msm_bus_cl_clear_pdata(ctx->bus_scale);
 
 	return rc;
 }
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index bca4be3..1e5e136 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -687,6 +687,7 @@
 	vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
 	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
 	vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
+	vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
 
 	cancel_delayed_work_sync(&chg->hvdcp_detect_work);
 
@@ -1461,14 +1462,18 @@
 	if (!chg->usb_icl_votable) {
 		chg->usb_icl_votable = find_votable("USB_ICL");
 
-		if (!chg->usb_icl_votable)
-			return -EINVAL;
+		if (!chg->usb_icl_votable) {
+			rc = -EINVAL;
+			goto unlock;
+		}
 	}
 	vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
 
 	rc = _smblib_vbus_regulator_enable(rdev);
 	if (rc >= 0)
 		chg->otg_en = true;
+	else
+		vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
 
 unlock:
 	mutex_unlock(&chg->otg_oc_lock);
@@ -4072,6 +4077,7 @@
 	vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
 	vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
 
+	vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
 	chg->vconn_attempts = 0;
 	chg->otg_attempts = 0;
 	chg->pulse_cnt = 0;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6afa0f5..ee1b322 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1046,6 +1046,27 @@
 	  control allows for voting on regulator state between multiple
 	  processors within the SoC.
 
+config REGULATOR_RPM_SMD
+	bool "RPM SMD regulator driver"
+	depends on OF
+	depends on MSM_RPM_SMD
+	help
+	  Compile in support for the RPM SMD regulator driver which is used for
+	  setting voltages and other parameters of the various power rails
+	  supplied by some Qualcomm PMICs. The RPM SMD regulator driver should
+	  be used on systems which contain an RPM which communicates with the
+	  application processor over SMD.
+
+config REGULATOR_SPM
+	bool "SPM regulator driver"
+	depends on SPMI
+	help
+	  Enable support for the SPM regulator driver which is used for
+	  setting voltages of processor supply regulators via the SPM module
+	  found inside chips of Qualcomm Technologies Inc. The SPM regulator
+	  driver can be used on QTI SoCs where the APSS processor cores are
+	  supplied by their own PMIC regulator.
+
 config REGULATOR_STUB
 	tristate "Stub Regulator"
 	help
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 59dea6e..b2bfba8 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -113,6 +113,8 @@
 obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
 obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
 obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
+obj-$(CONFIG_REGULATOR_RPM_SMD) += rpm-smd-regulator.o
+obj-$(CONFIG_REGULATOR_SPM) += spm-regulator.o
 
 obj-$(CONFIG_REGULATOR_CPR3) += cpr3-regulator.o cpr3-util.o
 obj-$(CONFIG_REGULATOR_CPR3_HMSS) += cpr3-hmss-regulator.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index e463117..1f60635 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4184,6 +4184,7 @@
 		debugfs_remove_recursive(rdev->debugfs);
 		if (rdev->debug_consumer)
 			rdev->debug_consumer->debugfs = NULL;
+		rdev->debugfs = NULL;
 		regulator_put(rdev->debug_consumer);
 	}
 }
@@ -4225,9 +4226,10 @@
 
 	regulator = regulator_get(NULL, rdev_get_name(rdev));
 	if (IS_ERR(regulator)) {
-		debugfs_remove_recursive(rdev->debugfs);
-		rdev_err(rdev, "regulator get failed, ret=%ld\n",
-			PTR_ERR(regulator));
+		rdev_deinit_debugfs(rdev);
+		if (PTR_ERR(regulator) != -EPROBE_DEFER)
+			rdev_err(rdev, "regulator get failed, ret=%ld\n",
+				 PTR_ERR(regulator));
 		return;
 	}
 	rdev->debug_consumer = regulator;
diff --git a/drivers/regulator/rpm-smd-regulator.c b/drivers/regulator/rpm-smd-regulator.c
new file mode 100644
index 0000000..b38db82
--- /dev/null
+++ b/drivers/regulator/rpm-smd-regulator.c
@@ -0,0 +1,1945 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+#include <soc/qcom/rpm-smd.h>
+
+/* Debug Definitions */
+
+enum {
+	RPM_VREG_DEBUG_REQUEST		= BIT(0),
+	RPM_VREG_DEBUG_FULL_REQUEST	= BIT(1),
+	RPM_VREG_DEBUG_DUPLICATE	= BIT(2),
+};
+
+static int rpm_vreg_debug_mask;
+module_param_named(
+	debug_mask, rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+);
+
+#define vreg_err(req, fmt, ...) \
+	pr_err("%s: " fmt, req->rdesc.name, ##__VA_ARGS__)
+
+/* RPM regulator request types */
+enum rpm_regulator_type {
+	RPM_REGULATOR_TYPE_LDO,
+	RPM_REGULATOR_TYPE_SMPS,
+	RPM_REGULATOR_TYPE_VS,
+	RPM_REGULATOR_TYPE_NCP,
+	RPM_REGULATOR_TYPE_BOB,
+	RPM_REGULATOR_TYPE_MAX,
+};
+
+/* RPM resource parameters */
+enum rpm_regulator_param_index {
+	RPM_REGULATOR_PARAM_ENABLE,
+	RPM_REGULATOR_PARAM_VOLTAGE,
+	RPM_REGULATOR_PARAM_CURRENT,
+	RPM_REGULATOR_PARAM_MODE_LDO,
+	RPM_REGULATOR_PARAM_MODE_SMPS,
+	RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE,
+	RPM_REGULATOR_PARAM_PIN_CTRL_MODE,
+	RPM_REGULATOR_PARAM_FREQUENCY,
+	RPM_REGULATOR_PARAM_HEAD_ROOM,
+	RPM_REGULATOR_PARAM_QUIET_MODE,
+	RPM_REGULATOR_PARAM_FREQ_REASON,
+	RPM_REGULATOR_PARAM_CORNER,
+	RPM_REGULATOR_PARAM_BYPASS,
+	RPM_REGULATOR_PARAM_FLOOR_CORNER,
+	RPM_REGULATOR_PARAM_LEVEL,
+	RPM_REGULATOR_PARAM_FLOOR_LEVEL,
+	RPM_REGULATOR_PARAM_MODE_BOB,
+	RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE1,
+	RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE2,
+	RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE3,
+	RPM_REGULATOR_PARAM_MAX,
+};
+
+enum rpm_regulator_smps_mode {
+	RPM_REGULATOR_SMPS_MODE_AUTO	= 0,
+	RPM_REGULATOR_SMPS_MODE_IPEAK	= 1,
+	RPM_REGULATOR_SMPS_MODE_PWM	= 2,
+};
+
+enum rpm_regulator_ldo_mode {
+	RPM_REGULATOR_LDO_MODE_IPEAK	= 0,
+	RPM_REGULATOR_LDO_MODE_HPM	= 1,
+};
+
+enum rpm_regulator_bob_mode {
+	RPM_REGULATOR_BOB_MODE_PASS	= 0,
+	RPM_REGULATOR_BOB_MODE_PFM	= 1,
+	RPM_REGULATOR_BOB_MODE_AUTO	= 2,
+	RPM_REGULATOR_BOB_MODE_PWM	= 3,
+};
+
+#define RPM_SET_CONFIG_ACTIVE			BIT(0)
+#define RPM_SET_CONFIG_SLEEP			BIT(1)
+#define RPM_SET_CONFIG_BOTH			(RPM_SET_CONFIG_ACTIVE \
+						 | RPM_SET_CONFIG_SLEEP)
+struct rpm_regulator_param {
+	char	*name;
+	char	*property_name;
+	u32	key;
+	u32	min;
+	u32	max;
+	u32	supported_regulator_types;
+};
+
+#define PARAM(_idx, _support_ldo, _support_smps, _support_vs, _support_ncp, \
+		_support_bob, _name, _min, _max, _property_name)	\
+	[RPM_REGULATOR_PARAM_##_idx] = { \
+		.name = _name, \
+		.property_name = _property_name, \
+		.min = _min, \
+		.max = _max, \
+		.supported_regulator_types = \
+			_support_ldo << RPM_REGULATOR_TYPE_LDO | \
+			_support_smps << RPM_REGULATOR_TYPE_SMPS | \
+			_support_vs << RPM_REGULATOR_TYPE_VS | \
+			_support_ncp << RPM_REGULATOR_TYPE_NCP | \
+			_support_bob << RPM_REGULATOR_TYPE_BOB, \
+	}
+
+static struct rpm_regulator_param params[RPM_REGULATOR_PARAM_MAX] = {
+	/*    ID               LDO SMPS VS  NCP BOB  name  min max          property-name */
+	PARAM(ENABLE,            1,  1,  1,  1,  1, "swen", 0, 1,          "qcom,init-enable"),
+	PARAM(VOLTAGE,           1,  1,  0,  1,  1, "uv",   0, 0x7FFFFFF,  "qcom,init-voltage"),
+	PARAM(CURRENT,           1,  1,  0,  0,  0, "ma",   0, 0x1FFF,     "qcom,init-current"),
+	PARAM(MODE_LDO,          1,  0,  0,  0,  0, "lsmd", 0, 1,          "qcom,init-ldo-mode"),
+	PARAM(MODE_SMPS,         0,  1,  0,  0,  0, "ssmd", 0, 2,          "qcom,init-smps-mode"),
+	PARAM(PIN_CTRL_ENABLE,   1,  1,  1,  0,  0, "pcen", 0, 0xF,        "qcom,init-pin-ctrl-enable"),
+	PARAM(PIN_CTRL_MODE,     1,  1,  1,  0,  0, "pcmd", 0, 0x1F,       "qcom,init-pin-ctrl-mode"),
+	PARAM(FREQUENCY,         0,  1,  0,  1,  0, "freq", 0, 31,         "qcom,init-frequency"),
+	PARAM(HEAD_ROOM,         1,  0,  0,  1,  0, "hr",   0, 0x7FFFFFFF, "qcom,init-head-room"),
+	PARAM(QUIET_MODE,        0,  1,  0,  0,  0, "qm",   0, 2,          "qcom,init-quiet-mode"),
+	PARAM(FREQ_REASON,       0,  1,  0,  1,  0, "resn", 0, 8,          "qcom,init-freq-reason"),
+	PARAM(CORNER,            1,  1,  0,  0,  0, "corn", 0, 6,          "qcom,init-voltage-corner"),
+	PARAM(BYPASS,            1,  0,  0,  0,  0, "bypa", 0, 1,          "qcom,init-disallow-bypass"),
+	PARAM(FLOOR_CORNER,      1,  1,  0,  0,  0, "vfc",  0, 6,          "qcom,init-voltage-floor-corner"),
+	PARAM(LEVEL,             1,  1,  0,  0,  0, "vlvl", 0, 0xFFFF,     "qcom,init-voltage-level"),
+	PARAM(FLOOR_LEVEL,       1,  1,  0,  0,  0, "vfl",  0, 0xFFFF,     "qcom,init-voltage-floor-level"),
+	PARAM(MODE_BOB,          0,  0,  0,  0,  1, "bobm", 0, 3,          "qcom,init-bob-mode"),
+	PARAM(PIN_CTRL_VOLTAGE1, 0,  0,  0,  0,  1, "pcv1", 0, 0x7FFFFFF,  "qcom,init-pin-ctrl-voltage1"),
+	PARAM(PIN_CTRL_VOLTAGE2, 0,  0,  0,  0,  1, "pcv2", 0, 0x7FFFFFF,  "qcom,init-pin-ctrl-voltage2"),
+	PARAM(PIN_CTRL_VOLTAGE3, 0,  0,  0,  0,  1, "pcv3", 0, 0x7FFFFFF,  "qcom,init-pin-ctrl-voltage3"),
+};
+
+struct rpm_regulator_mode_map {
+	int			ldo_mode;
+	int			smps_mode;
+};
+
+static struct rpm_regulator_mode_map mode_mapping[] = {
+	[RPM_REGULATOR_MODE_AUTO]
+		= {-1,				 RPM_REGULATOR_SMPS_MODE_AUTO},
+	[RPM_REGULATOR_MODE_IPEAK]
+		= {RPM_REGULATOR_LDO_MODE_IPEAK, RPM_REGULATOR_SMPS_MODE_IPEAK},
+	[RPM_REGULATOR_MODE_HPM]
+		= {RPM_REGULATOR_LDO_MODE_HPM,   RPM_REGULATOR_SMPS_MODE_PWM},
+};
+
+/* Indices for use with pin control enable via enable/disable feature. */
+#define RPM_VREG_PIN_CTRL_STATE_DISABLE	0
+#define RPM_VREG_PIN_CTRL_STATE_ENABLE	1
+#define RPM_VREG_PIN_CTRL_STATE_COUNT	2
+
+struct rpm_vreg_request {
+	u32			param[RPM_REGULATOR_PARAM_MAX];
+	u32			valid;
+	u32			modified;
+};
+
+struct rpm_vreg {
+	struct rpm_vreg_request	aggr_req_active;
+	struct rpm_vreg_request	aggr_req_sleep;
+	struct list_head	reg_list;
+	const char		*resource_name;
+	u32			resource_id;
+	bool			allow_atomic;
+	int			regulator_type;
+	int			hpm_min_load;
+	int			enable_time;
+	spinlock_t		slock;
+	struct mutex		mlock;
+	unsigned long		flags;
+	bool			sleep_request_sent;
+	bool			wait_for_ack_active;
+	bool			wait_for_ack_sleep;
+	bool			always_wait_for_ack;
+	bool			apps_only;
+	struct msm_rpm_request	*handle_active;
+	struct msm_rpm_request	*handle_sleep;
+};
+
+struct rpm_regulator {
+	struct regulator_desc	rdesc;
+	struct regulator_dev	*rdev;
+	struct rpm_vreg		*rpm_vreg;
+	struct list_head	list;
+	bool			set_active;
+	bool			set_sleep;
+	bool			always_send_voltage;
+	bool			always_send_current;
+	bool			use_pin_ctrl_for_enable;
+	struct rpm_vreg_request	req;
+	int			system_load;
+	int			min_uV;
+	int			max_uV;
+	u32			pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_COUNT];
+	enum rpm_regulator_param_index voltage_index;
+	int			voltage_offset;
+};
+
+/*
+ * This voltage in uV is returned by get_voltage functions when there is no way
+ * to determine the current voltage level.  It is needed because the regulator
+ * framework treats a 0 uV voltage as an error.
+ */
+#define VOLTAGE_UNKNOWN 1
+
+/*
+ * Regulator requests sent in the active set take effect immediately.  Requests
+ * sent in the sleep set take effect when the Apps processor transitions into
+ * RPM assisted power collapse.  For any given regulator, if an active set
+ * request is present, but not a sleep set request, then the active set request
+ * is used at all times, even when the Apps processor is power collapsed.
+ *
+ * The rpm-regulator-smd takes advantage of this default usage of the active set
+ * request by only sending a sleep set request if it differs from the
+ * corresponding active set request.
+ */
+#define RPM_SET_ACTIVE	MSM_RPM_CTX_ACTIVE_SET
+#define RPM_SET_SLEEP	MSM_RPM_CTX_SLEEP_SET
+
+static u32 rpm_vreg_string_to_int(const u8 *str)
+{
+	int i, len;
+	u32 output = 0;
+
+	len = strnlen(str, sizeof(u32));
+	for (i = 0; i < len; i++)
+		output |= str[i] << (i * 8);
+
+	return output;
+}
+
+static inline void rpm_vreg_lock(struct rpm_vreg *rpm_vreg)
+{
+	if (rpm_vreg->allow_atomic)
+		spin_lock_irqsave(&rpm_vreg->slock, rpm_vreg->flags);
+	else
+		mutex_lock(&rpm_vreg->mlock);
+}
+
+static inline void rpm_vreg_unlock(struct rpm_vreg *rpm_vreg)
+{
+	if (rpm_vreg->allow_atomic)
+		spin_unlock_irqrestore(&rpm_vreg->slock, rpm_vreg->flags);
+	else
+		mutex_unlock(&rpm_vreg->mlock);
+}
+
+static inline bool rpm_vreg_active_or_sleep_enabled(struct rpm_vreg *rpm_vreg)
+{
+	return (rpm_vreg->aggr_req_active.param[RPM_REGULATOR_PARAM_ENABLE]
+			&& (rpm_vreg->aggr_req_active.valid
+				& BIT(RPM_REGULATOR_PARAM_ENABLE)))
+	    || ((rpm_vreg->aggr_req_sleep.param[RPM_REGULATOR_PARAM_ENABLE])
+				&& (rpm_vreg->aggr_req_sleep.valid
+					& BIT(RPM_REGULATOR_PARAM_ENABLE)));
+}
+
+static inline bool rpm_vreg_shared_active_or_sleep_enabled_valid
+						(struct rpm_vreg *rpm_vreg)
+{
+	return !rpm_vreg->apps_only &&
+		((rpm_vreg->aggr_req_active.valid
+					& BIT(RPM_REGULATOR_PARAM_ENABLE))
+		 || (rpm_vreg->aggr_req_sleep.valid
+					& BIT(RPM_REGULATOR_PARAM_ENABLE)));
+}
+
+static const u32 power_level_params =
+	BIT(RPM_REGULATOR_PARAM_ENABLE) |
+	BIT(RPM_REGULATOR_PARAM_VOLTAGE) |
+	BIT(RPM_REGULATOR_PARAM_CURRENT) |
+	BIT(RPM_REGULATOR_PARAM_CORNER) |
+	BIT(RPM_REGULATOR_PARAM_BYPASS) |
+	BIT(RPM_REGULATOR_PARAM_FLOOR_CORNER) |
+	BIT(RPM_REGULATOR_PARAM_LEVEL) |
+	BIT(RPM_REGULATOR_PARAM_FLOOR_LEVEL);
+
+static bool rpm_vreg_ack_required(struct rpm_vreg *rpm_vreg, u32 set,
+				const u32 *prev_param, const u32 *param,
+				u32 prev_valid, u32 modified)
+{
+	u32 mask;
+	int i;
+
+	if (rpm_vreg->always_wait_for_ack
+	    || (set == RPM_SET_ACTIVE && rpm_vreg->wait_for_ack_active)
+	    || (set == RPM_SET_SLEEP && rpm_vreg->wait_for_ack_sleep))
+		return true;
+
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		mask = BIT(i);
+		if (modified & mask) {
+			if ((prev_valid & mask) && (power_level_params & mask)
+			    && (param[i] <= prev_param[i]))
+				continue;
+			else
+				return true;
+		}
+	}
+
+	return false;
+}
+
+static void rpm_vreg_check_param_max(struct rpm_regulator *regulator, int index,
+					u32 new_max)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+
+	if (regulator->set_active
+	    && (rpm_vreg->aggr_req_active.valid & BIT(index))
+	    && rpm_vreg->aggr_req_active.param[index] > new_max)
+		rpm_vreg->wait_for_ack_active = true;
+
+	if (regulator->set_sleep
+	    && (rpm_vreg->aggr_req_sleep.valid & BIT(index))
+	    && rpm_vreg->aggr_req_sleep.param[index] > new_max)
+		rpm_vreg->wait_for_ack_sleep = true;
+}
+
+/*
+ * This is used when voting for LPM or HPM by subtracting or adding to the
+ * hpm_min_load of a regulator.  It has units of uA.
+ */
+#define LOAD_THRESHOLD_STEP	1000
+
+static inline int rpm_vreg_hpm_min_uA(struct rpm_vreg *rpm_vreg)
+{
+	return rpm_vreg->hpm_min_load;
+}
+
+static inline int rpm_vreg_lpm_max_uA(struct rpm_vreg *rpm_vreg)
+{
+	return rpm_vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
+}
+
+#define MICRO_TO_MILLI(uV)	((uV) / 1000)
+#define MILLI_TO_MICRO(uV)	((uV) * 1000)
+
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define REQ_SENT	0
+#define REQ_PREV	1
+#define REQ_CACHED	2
+#define REQ_TYPES	3
+
+static void rpm_regulator_req(struct rpm_regulator *regulator, int set,
+				bool sent)
+{
+	char buf[DEBUG_PRINT_BUFFER_SIZE];
+	size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	struct rpm_vreg_request *aggr;
+	bool first;
+	u32 mask[REQ_TYPES] = {0, 0, 0};
+	const char *req_names[REQ_TYPES] = {"sent", "prev", "cached"};
+	int pos = 0;
+	int i, j;
+
+	aggr = (set == RPM_SET_ACTIVE)
+		? &rpm_vreg->aggr_req_active : &rpm_vreg->aggr_req_sleep;
+
+	if (rpm_vreg_debug_mask & RPM_VREG_DEBUG_DUPLICATE) {
+		mask[REQ_SENT] = aggr->modified;
+		mask[REQ_PREV] = aggr->valid & ~aggr->modified;
+	} else if (sent
+		   && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_FULL_REQUEST)) {
+		mask[REQ_SENT] = aggr->modified;
+		mask[REQ_PREV] = aggr->valid & ~aggr->modified;
+	} else if (sent && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_REQUEST)) {
+		mask[REQ_SENT] = aggr->modified;
+	}
+
+	if (!(mask[REQ_SENT] | mask[REQ_PREV]))
+		return;
+
+	if (set == RPM_SET_SLEEP && !rpm_vreg->sleep_request_sent) {
+		mask[REQ_CACHED] = mask[REQ_SENT] | mask[REQ_PREV];
+		mask[REQ_SENT] = 0;
+		mask[REQ_PREV] = 0;
+	}
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s%s: ",
+			KERN_INFO, __func__);
+
+	pos += scnprintf(buf + pos, buflen - pos, "%s %u (%s): s=%s",
+			rpm_vreg->resource_name, rpm_vreg->resource_id,
+			regulator->rdesc.name,
+			(set == RPM_SET_ACTIVE ? "act" : "slp"));
+
+	for (i = 0; i < REQ_TYPES; i++) {
+		if (mask[i])
+			pos += scnprintf(buf + pos, buflen - pos, "; %s: ",
+					req_names[i]);
+
+		first = true;
+		for (j = 0; j < RPM_REGULATOR_PARAM_MAX; j++) {
+			if (mask[i] & BIT(j)) {
+				pos += scnprintf(buf + pos, buflen - pos,
+					"%s%s=%u", (first ? "" : ", "),
+					params[j].name, aggr->param[j]);
+				first = false;
+			}
+		}
+	}
+
+	pos += scnprintf(buf + pos, buflen - pos, "\n");
+	printk(buf);
+}
+
+#define RPM_VREG_SET_PARAM(_regulator, _param, _val) \
+{ \
+	(_regulator)->req.param[RPM_REGULATOR_PARAM_##_param] = _val; \
+	(_regulator)->req.modified |= BIT(RPM_REGULATOR_PARAM_##_param); \
+} \
+
+static int rpm_vreg_add_kvp_to_request(struct rpm_vreg *rpm_vreg,
+				       const u32 *param, int idx, u32 set)
+{
+	struct msm_rpm_request *handle;
+
+	handle = (set == RPM_SET_ACTIVE	? rpm_vreg->handle_active
+					: rpm_vreg->handle_sleep);
+
+	if (rpm_vreg->allow_atomic)
+		return msm_rpm_add_kvp_data_noirq(handle, params[idx].key,
+						  (u8 *)&param[idx], 4);
+	else
+		return msm_rpm_add_kvp_data(handle, params[idx].key,
+					    (u8 *)&param[idx], 4);
+}
+
+static void rpm_vreg_check_modified_requests(const u32 *prev_param,
+		const u32 *param, u32 prev_valid, u32 *modified)
+{
+	u32 value_changed = 0;
+	int i;
+
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		if (param[i] != prev_param[i])
+			value_changed |= BIT(i);
+	}
+
+	/*
+	 * Only keep bits that are for changed parameters or previously
+	 * invalid parameters.
+	 */
+	*modified &= value_changed | ~prev_valid;
+}
+
+static int rpm_vreg_add_modified_requests(struct rpm_regulator *regulator,
+		u32 set, const u32 *param, u32 modified)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	int rc = 0;
+	int i;
+
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		/* Only send requests for modified parameters. */
+		if (modified & BIT(i)) {
+			rc = rpm_vreg_add_kvp_to_request(rpm_vreg, param, i,
+							set);
+			if (rc) {
+				vreg_err(regulator,
+					"add KVP failed: %s %u; %s, rc=%d\n",
+					rpm_vreg->resource_name,
+					rpm_vreg->resource_id, params[i].name,
+					rc);
+				return rc;
+			}
+		}
+	}
+
+	return rc;
+}
+
+static int rpm_vreg_send_request(struct rpm_regulator *regulator, u32 set,
+				bool wait_for_ack)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	struct msm_rpm_request *handle
+		= (set == RPM_SET_ACTIVE ? rpm_vreg->handle_active
+					: rpm_vreg->handle_sleep);
+	int rc = 0;
+	void *temp;
+
+	if (unlikely(rpm_vreg->allow_atomic)) {
+		rc = msm_rpm_wait_for_ack_noirq(msm_rpm_send_request_noirq(
+						  handle));
+	} else if (wait_for_ack) {
+		rc = msm_rpm_wait_for_ack(msm_rpm_send_request(handle));
+	} else {
+		temp = msm_rpm_send_request_noack(handle);
+		if (IS_ERR(temp))
+			rc = PTR_ERR(temp);
+	}
+
+	if (rc)
+		vreg_err(regulator,
+			"msm rpm send failed: %s %u; set=%s, rc=%d\n",
+			rpm_vreg->resource_name,
+			rpm_vreg->resource_id,
+			(set == RPM_SET_ACTIVE ? "act" : "slp"), rc);
+
+	return rc;
+}
+
+#define RPM_VREG_AGGR_MIN(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+	 = min(_param_aggr[RPM_REGULATOR_PARAM_##_idx], \
+		_param_reg[RPM_REGULATOR_PARAM_##_idx]); \
+}
+
+#define RPM_VREG_AGGR_MAX(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+	 = max(_param_aggr[RPM_REGULATOR_PARAM_##_idx], \
+		_param_reg[RPM_REGULATOR_PARAM_##_idx]); \
+}
+
+#define RPM_VREG_AGGR_SUM(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+		 += _param_reg[RPM_REGULATOR_PARAM_##_idx]; \
+}
+
+#define RPM_VREG_AGGR_OR(_idx, _param_aggr, _param_reg) \
+{ \
+	_param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+		|= _param_reg[RPM_REGULATOR_PARAM_##_idx]; \
+}
+
+/*
+ * Aggregation is performed on each parameter based on the way that the RPM
+ * aggregates that type internally between RPM masters.
+ */
+static void rpm_vreg_aggregate_params(u32 *param_aggr, const u32 *param_reg)
+{
+	RPM_VREG_AGGR_MAX(ENABLE, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(VOLTAGE, param_aggr, param_reg);
+	RPM_VREG_AGGR_SUM(CURRENT, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(MODE_LDO, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(MODE_SMPS, param_aggr, param_reg);
+	RPM_VREG_AGGR_OR(PIN_CTRL_ENABLE, param_aggr, param_reg);
+	RPM_VREG_AGGR_OR(PIN_CTRL_MODE, param_aggr, param_reg);
+	RPM_VREG_AGGR_MIN(FREQUENCY, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(HEAD_ROOM, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(QUIET_MODE, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(FREQ_REASON, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(CORNER, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(BYPASS, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(FLOOR_CORNER, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(LEVEL, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(FLOOR_LEVEL, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(MODE_BOB, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE1, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE2, param_aggr, param_reg);
+	RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE3, param_aggr, param_reg);
+}
+
+static int rpm_vreg_aggregate_requests(struct rpm_regulator *regulator)
+{
+	struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+	u32 param_active[RPM_REGULATOR_PARAM_MAX];
+	u32 param_sleep[RPM_REGULATOR_PARAM_MAX];
+	u32 modified_active, modified_sleep;
+	struct rpm_regulator *reg;
+	bool sleep_set_differs = false;
+	bool send_active = false;
+	bool send_sleep = false;
+	bool wait_for_ack;
+	int rc = 0;
+	int i;
+
+	memset(param_active, 0, sizeof(param_active));
+	memset(param_sleep, 0, sizeof(param_sleep));
+	modified_active = rpm_vreg->aggr_req_active.modified;
+	modified_sleep = rpm_vreg->aggr_req_sleep.modified;
+
+	/*
+	 * Aggregate all of the requests for this regulator in both active
+	 * and sleep sets.
+	 */
+	list_for_each_entry(reg, &rpm_vreg->reg_list, list) {
+		if (reg->set_active) {
+			rpm_vreg_aggregate_params(param_active, reg->req.param);
+			modified_active |= reg->req.modified;
+		}
+		if (reg->set_sleep) {
+			rpm_vreg_aggregate_params(param_sleep, reg->req.param);
+			modified_sleep |= reg->req.modified;
+		}
+	}
+
+	/*
+	 * Check if the aggregated sleep set parameter values differ from the
+	 * aggregated active set parameter values.
+	 */
+	if (!rpm_vreg->sleep_request_sent) {
+		for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+			if ((param_active[i] != param_sleep[i])
+			    && (modified_sleep & BIT(i))) {
+				sleep_set_differs = true;
+				break;
+			}
+		}
+	}
+
+	/* Add KVPs to the active set RPM request if they have new values. */
+	rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_active.param,
+		param_active, rpm_vreg->aggr_req_active.valid,
+		&modified_active);
+	rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_ACTIVE,
+		param_active, modified_active);
+	if (rc)
+		return rc;
+	send_active = modified_active;
+
+	/*
+	 * Sleep set configurations are only sent if they differ from the
+	 * active set values.  This is because the active set values will take
+	 * effect during rpm assisted power collapse in the absence of sleep set
+	 * values.
+	 *
+	 * However, once a sleep set request is sent for a given regulator,
+	 * additional sleep set requests must be sent in the future even if they
+	 * match the corresponding active set requests.
+	 */
+	if (rpm_vreg->sleep_request_sent || sleep_set_differs) {
+		/* Add KVPs to the sleep set RPM request if they are new. */
+		rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_sleep.param,
+			param_sleep, rpm_vreg->aggr_req_sleep.valid,
+			&modified_sleep);
+		rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_SLEEP,
+			param_sleep, modified_sleep);
+		if (rc)
+			return rc;
+		send_sleep = modified_sleep;
+	}
+
+	/* Send active set request to the RPM if it contains new KVPs. */
+	if (send_active) {
+		wait_for_ack = rpm_vreg_ack_required(rpm_vreg, RPM_SET_ACTIVE,
+					rpm_vreg->aggr_req_active.param,
+					param_active,
+					rpm_vreg->aggr_req_active.valid,
+					modified_active);
+		rc = rpm_vreg_send_request(regulator, RPM_SET_ACTIVE,
+						wait_for_ack);
+		if (rc)
+			return rc;
+		rpm_vreg->aggr_req_active.valid |= modified_active;
+		rpm_vreg->wait_for_ack_active = false;
+	}
+	/* Store the results of the aggregation. */
+	rpm_vreg->aggr_req_active.modified = modified_active;
+	memcpy(rpm_vreg->aggr_req_active.param, param_active,
+		sizeof(param_active));
+
+	/* Handle debug printing of the active set request. */
+	rpm_regulator_req(regulator, RPM_SET_ACTIVE, send_active);
+	if (send_active)
+		rpm_vreg->aggr_req_active.modified = 0;
+
+	/* Send sleep set request to the RPM if it contains new KVPs. */
+	if (send_sleep) {
+		wait_for_ack = rpm_vreg_ack_required(rpm_vreg, RPM_SET_SLEEP,
+					rpm_vreg->aggr_req_sleep.param,
+					param_sleep,
+					rpm_vreg->aggr_req_sleep.valid,
+					modified_sleep);
+		rc = rpm_vreg_send_request(regulator, RPM_SET_SLEEP,
+						wait_for_ack);
+		if (rc)
+			return rc;
+		else
+			rpm_vreg->sleep_request_sent = true;
+		rpm_vreg->aggr_req_sleep.valid |= modified_sleep;
+		rpm_vreg->wait_for_ack_sleep = false;
+	}
+	/* Store the results of the aggregation. */
+	rpm_vreg->aggr_req_sleep.modified = modified_sleep;
+	memcpy(rpm_vreg->aggr_req_sleep.param, param_sleep,
+		sizeof(param_sleep));
+
+	/* Handle debug printing of the sleep set request. */
+	rpm_regulator_req(regulator, RPM_SET_SLEEP, send_sleep);
+	if (send_sleep)
+		rpm_vreg->aggr_req_sleep.modified = 0;
+
+	/*
+	 * Loop over all requests for this regulator to update the valid and
+	 * modified values for use in future aggregation.
+	 */
+	list_for_each_entry(reg, &rpm_vreg->reg_list, list) {
+		reg->req.valid |= reg->req.modified;
+		reg->req.modified = 0;
+	}
+
+	return rc;
+}
+
+static int rpm_vreg_is_enabled(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	if (likely(!reg->use_pin_ctrl_for_enable))
+		return reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+	else
+		return reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE]
+			== reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_ENABLE];
+}
+
+static int rpm_vreg_enable(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc;
+	u32 prev_enable;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	if (likely(!reg->use_pin_ctrl_for_enable)) {
+		/* Enable using swen KVP. */
+		prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+		RPM_VREG_SET_PARAM(reg, ENABLE, 1);
+		rc = rpm_vreg_aggregate_requests(reg);
+		if (rc) {
+			vreg_err(reg, "enable failed, rc=%d", rc);
+			RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable);
+		}
+	} else {
+		/* Enable using pcen KVP. */
+		prev_enable
+			= reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE];
+		RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE,
+			reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_ENABLE]);
+		rc = rpm_vreg_aggregate_requests(reg);
+		if (rc) {
+			vreg_err(reg, "enable failed, rc=%d", rc);
+			RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE, prev_enable);
+		}
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_disable(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc;
+	u32 prev_enable;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	if (likely(!reg->use_pin_ctrl_for_enable)) {
+		/* Disable using swen KVP. */
+		prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+		RPM_VREG_SET_PARAM(reg, ENABLE, 0);
+		rc = rpm_vreg_aggregate_requests(reg);
+		if (rc) {
+			vreg_err(reg, "disable failed, rc=%d", rc);
+			RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable);
+		}
+	} else {
+		/* Disable using pcen KVP. */
+		prev_enable
+			= reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE];
+		RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE,
+			reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_DISABLE]);
+		rc = rpm_vreg_aggregate_requests(reg);
+		if (rc) {
+			vreg_err(reg, "disable failed, rc=%d", rc);
+			RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE, prev_enable);
+		}
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+#define RPM_VREG_SET_VOLTAGE(_regulator, _val) \
+{ \
+	(_regulator)->req.param[(_regulator)->voltage_index] = _val; \
+	(_regulator)->req.modified |= BIT((_regulator)->voltage_index); \
+} \
+
+static int rpm_vreg_set_voltage(struct regulator_dev *rdev, int min_uV,
+				int max_uV, unsigned *selector)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	int voltage;
+	u32 prev_voltage;
+
+	voltage = min_uV - reg->voltage_offset;
+
+	if (voltage < params[reg->voltage_index].min
+	    || voltage > params[reg->voltage_index].max) {
+		vreg_err(reg, "voltage=%d for key=%s is not within allowed range: [%u, %u]\n",
+			voltage, params[reg->voltage_index].name,
+			params[reg->voltage_index].min,
+			params[reg->voltage_index].max);
+		return -EINVAL;
+	}
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_voltage = reg->req.param[reg->voltage_index];
+	RPM_VREG_SET_VOLTAGE(reg, voltage);
+
+	rpm_vreg_check_param_max(reg, reg->voltage_index,
+				max_uV - reg->voltage_offset);
+
+	/*
+	 * Only send a new voltage if the regulator is currently enabled or
+	 * if the regulator has been configured to always send voltage updates.
+	 */
+	if (reg->always_send_voltage
+	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+	    || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
+		rc = rpm_vreg_aggregate_requests(reg);
+
+	if (rc) {
+		vreg_err(reg, "set voltage for key=%s failed, rc=%d",
+			params[reg->voltage_index].name, rc);
+		RPM_VREG_SET_VOLTAGE(reg, prev_voltage);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_get_voltage(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int uV;
+
+	uV = reg->req.param[reg->voltage_index] + reg->voltage_offset;
+	if (uV == 0)
+		uV = VOLTAGE_UNKNOWN;
+
+	return uV;
+}
+
+static int rpm_vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	u32 prev_current;
+	int prev_uA;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_current = reg->req.param[RPM_REGULATOR_PARAM_CURRENT];
+	prev_uA = MILLI_TO_MICRO(prev_current);
+
+	if (mode == REGULATOR_MODE_NORMAL) {
+		/* Make sure that request current is in HPM range. */
+		if (prev_uA < rpm_vreg_hpm_min_uA(reg->rpm_vreg))
+			RPM_VREG_SET_PARAM(reg, CURRENT,
+			    MICRO_TO_MILLI(rpm_vreg_hpm_min_uA(reg->rpm_vreg)));
+	} else if (REGULATOR_MODE_IDLE) {
+		/* Make sure that request current is in LPM range. */
+		if (prev_uA > rpm_vreg_lpm_max_uA(reg->rpm_vreg))
+			RPM_VREG_SET_PARAM(reg, CURRENT,
+			    MICRO_TO_MILLI(rpm_vreg_lpm_max_uA(reg->rpm_vreg)));
+	} else {
+		vreg_err(reg, "invalid mode: %u\n", mode);
+		rpm_vreg_unlock(reg->rpm_vreg);
+		return -EINVAL;
+	}
+
+	/*
+	 * Only send a new load current value if the regulator is currently
+	 * enabled or if the regulator has been configured to always send
+	 * current updates.
+	 */
+	if (reg->always_send_current
+	    || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+	    || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
+		rc = rpm_vreg_aggregate_requests(reg);
+
+	if (rc) {
+		vreg_err(reg, "set mode failed, rc=%d\n", rc);
+		RPM_VREG_SET_PARAM(reg, CURRENT, prev_current);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static unsigned int rpm_vreg_get_mode(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	return (reg->req.param[RPM_REGULATOR_PARAM_CURRENT]
+			>= MICRO_TO_MILLI(reg->rpm_vreg->hpm_min_load))
+		? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static unsigned int rpm_vreg_get_optimum_mode(struct regulator_dev *rdev,
+			int input_uV, int output_uV, int load_uA)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	u32 load_mA;
+
+	load_uA += reg->system_load;
+
+	load_mA = MICRO_TO_MILLI(load_uA);
+	if (load_mA > params[RPM_REGULATOR_PARAM_CURRENT].max)
+		load_mA = params[RPM_REGULATOR_PARAM_CURRENT].max;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+	RPM_VREG_SET_PARAM(reg, CURRENT, load_mA);
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return (load_uA >= reg->rpm_vreg->hpm_min_load)
+		? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static int rpm_vreg_set_bob_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	int rc;
+	u32 prev_mode;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+
+	prev_mode = reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB];
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PWM);
+		break;
+	case REGULATOR_MODE_NORMAL:
+		RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_AUTO);
+		break;
+	case REGULATOR_MODE_IDLE:
+		RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PFM);
+		break;
+	case REGULATOR_MODE_STANDBY:
+		RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PASS);
+		break;
+	default:
+		vreg_err(reg, "invalid mode: %u\n", mode);
+		rpm_vreg_unlock(reg->rpm_vreg);
+		return -EINVAL;
+	}
+
+	rc = rpm_vreg_aggregate_requests(reg);
+	if (rc) {
+		vreg_err(reg, "set BoB mode failed, rc=%d\n", rc);
+		RPM_VREG_SET_PARAM(reg, MODE_BOB, prev_mode);
+	}
+
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static unsigned int rpm_vreg_get_bob_mode(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+	unsigned int mode;
+
+	switch (reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB]) {
+	case RPM_REGULATOR_BOB_MODE_PWM:
+		mode = REGULATOR_MODE_FAST;
+		break;
+	case RPM_REGULATOR_BOB_MODE_AUTO:
+		mode = REGULATOR_MODE_NORMAL;
+		break;
+	case RPM_REGULATOR_BOB_MODE_PFM:
+		mode = REGULATOR_MODE_IDLE;
+		break;
+	case RPM_REGULATOR_BOB_MODE_PASS:
+		mode = REGULATOR_MODE_STANDBY;
+		break;
+	default:
+		vreg_err(reg, "BoB mode unknown\n");
+		mode = REGULATOR_MODE_NORMAL;
+	}
+
+	return mode;
+}
+
+static int rpm_vreg_enable_time(struct regulator_dev *rdev)
+{
+	struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+	return reg->rpm_vreg->enable_time;
+}
+
+static int rpm_vreg_send_defaults(struct rpm_regulator *reg)
+{
+	int rc;
+
+	rpm_vreg_lock(reg->rpm_vreg);
+	rc = rpm_vreg_aggregate_requests(reg);
+	if (rc)
+		vreg_err(reg, "RPM request failed, rc=%d", rc);
+	rpm_vreg_unlock(reg->rpm_vreg);
+
+	return rc;
+}
+
+static int rpm_vreg_configure_pin_control_enable(struct rpm_regulator *reg,
+		struct device_node *node)
+{
+	struct rpm_regulator_param *pcen_param =
+			&params[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE];
+	int rc, i;
+
+	if (!of_find_property(node, "qcom,enable-with-pin-ctrl", NULL))
+		return 0;
+
+	if (pcen_param->supported_regulator_types
+			& BIT(reg->rpm_vreg->regulator_type)) {
+		rc = of_property_read_u32_array(node,
+			"qcom,enable-with-pin-ctrl", reg->pin_ctrl_mask,
+			RPM_VREG_PIN_CTRL_STATE_COUNT);
+		if (rc) {
+			vreg_err(reg, "could not read qcom,enable-with-pin-ctrl, rc=%d\n",
+				rc);
+			return rc;
+		}
+
+		/* Verify that the mask values are valid. */
+		for (i = 0; i < RPM_VREG_PIN_CTRL_STATE_COUNT; i++) {
+			if (reg->pin_ctrl_mask[i] < pcen_param->min
+			    || reg->pin_ctrl_mask[i] > pcen_param->max) {
+				vreg_err(reg, "device tree property: qcom,enable-with-pin-ctrl[%d]=%u is outside allowed range [%u, %u]\n",
+					i, reg->pin_ctrl_mask[i],
+					pcen_param->min, pcen_param->max);
+				return -EINVAL;
+			}
+		}
+
+		reg->use_pin_ctrl_for_enable = true;
+	} else {
+		pr_warn("%s: regulator type=%d does not support device tree property: qcom,enable-with-pin-ctrl\n",
+			reg->rdesc.name, reg->rpm_vreg->regulator_type);
+	}
+
+	return 0;
+}
+
+/**
+ * rpm_regulator_get() - lookup and obtain a handle to an RPM regulator
+ * @dev: device for regulator consumer
+ * @supply: supply name
+ *
+ * Returns a struct rpm_regulator corresponding to the regulator producer,
+ * or ERR_PTR() containing errno.
+ *
+ * This function may only be called from nonatomic context.
+ */
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply)
+{
+	struct rpm_regulator *framework_reg;
+	struct rpm_regulator *priv_reg = NULL;
+	struct regulator *regulator;
+	struct rpm_vreg *rpm_vreg;
+
+	regulator = regulator_get(dev, supply);
+	if (IS_ERR(regulator)) {
+		pr_err("could not find regulator for: dev=%s, supply=%s, rc=%ld\n",
+			(dev ? dev_name(dev) : ""), (supply ? supply : ""),
+			PTR_ERR(regulator));
+		return ERR_CAST(regulator);
+	}
+
+	framework_reg = regulator_get_drvdata(regulator);
+	if (framework_reg == NULL) {
+		pr_err("regulator structure not found.\n");
+		regulator_put(regulator);
+		return ERR_PTR(-ENODEV);
+	}
+	regulator_put(regulator);
+
+	rpm_vreg = framework_reg->rpm_vreg;
+
+	priv_reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+	if (priv_reg == NULL) {
+		vreg_err(framework_reg,
+			"could not allocate memory for regulator\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/*
+	 * Allocate a regulator_dev struct so that framework callback functions
+	 * can be called from the private API functions.
+	 */
+	priv_reg->rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
+	if (priv_reg->rdev == NULL) {
+		vreg_err(framework_reg,
+			"could not allocate memory for regulator_dev\n");
+		kfree(priv_reg);
+		return ERR_PTR(-ENOMEM);
+	}
+	priv_reg->rdev->reg_data	= priv_reg;
+	priv_reg->rpm_vreg		= rpm_vreg;
+	priv_reg->rdesc.name		= framework_reg->rdesc.name;
+	priv_reg->rdesc.ops		= framework_reg->rdesc.ops;
+	priv_reg->set_active		= framework_reg->set_active;
+	priv_reg->set_sleep		= framework_reg->set_sleep;
+	priv_reg->min_uV		= framework_reg->min_uV;
+	priv_reg->max_uV		= framework_reg->max_uV;
+	priv_reg->system_load		= framework_reg->system_load;
+
+	might_sleep_if(!rpm_vreg->allow_atomic);
+	rpm_vreg_lock(rpm_vreg);
+	list_add(&priv_reg->list, &rpm_vreg->reg_list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	return priv_reg;
+}
+EXPORT_SYMBOL(rpm_regulator_get);
+
+static int rpm_regulator_check_input(struct rpm_regulator *regulator)
+{
+	if (IS_ERR_OR_NULL(regulator) || regulator->rpm_vreg == NULL) {
+		pr_err("invalid rpm_regulator pointer\n");
+		return -EINVAL;
+	}
+
+	might_sleep_if(!regulator->rpm_vreg->allow_atomic);
+
+	return 0;
+}
+
+/**
+ * rpm_regulator_put() - free the RPM regulator handle
+ * @regulator: RPM regulator handle
+ *
+ * Parameter reaggregation does not take place when rpm_regulator_put is called.
+ * Therefore, regulator enable state and voltage must be configured
+ * appropriately before calling rpm_regulator_put.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+void rpm_regulator_put(struct rpm_regulator *regulator)
+{
+	struct rpm_vreg *rpm_vreg;
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return;
+
+	rpm_vreg = regulator->rpm_vreg;
+
+	might_sleep_if(!rpm_vreg->allow_atomic);
+	rpm_vreg_lock(rpm_vreg);
+	list_del(&regulator->list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	kfree(regulator->rdev);
+	kfree(regulator);
+}
+EXPORT_SYMBOL(rpm_regulator_put);
+
+/**
+ * rpm_regulator_enable() - enable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_enable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	return rpm_vreg_enable(regulator->rdev);
+}
+EXPORT_SYMBOL(rpm_regulator_enable);
+
+/**
+ * rpm_regulator_disable() - disable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The enable state of the regulator is determined by aggregating the requests
+ * of all consumers.  Therefore, it is possible that the regulator will remain
+ * enabled even after rpm_regulator_disable is called.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_disable(struct rpm_regulator *regulator)
+{
+	int rc = rpm_regulator_check_input(regulator);
+
+	if (rc)
+		return rc;
+
+	return rpm_vreg_disable(regulator->rdev);
+}
+EXPORT_SYMBOL(rpm_regulator_disable);
+
+/**
+ * rpm_regulator_set_voltage() - set regulator output voltage
+ * @regulator: RPM regulator handle
+ * @min_uV: minimum required voltage in uV
+ * @max_uV: maximum acceptable voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * while the regulator is disabled or enabled.  If the regulator is enabled then
+ * the voltage will change to the new value immediately; otherwise, if the
+ * regulator is disabled, then the regulator will output at the new voltage when
+ * enabled.
+ *
+ * The min_uV to max_uV voltage range requested must intersect with the
+ * voltage constraint range configured for the regulator.
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The final voltage value that is sent to the RPM is aggregated based upon the
+ * values requested by all consumers of the regulator.  This corresponds to the
+ * maximum min_uV value.
+ *
+ * This function may be called from either atomic or nonatomic context.  If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+			      int max_uV)
+{
+	int rc = rpm_regulator_check_input(regulator);
+	int uV = min_uV;
+
+	if (rc)
+		return rc;
+
+	if (regulator->rpm_vreg->regulator_type == RPM_REGULATOR_TYPE_VS) {
+		vreg_err(regulator, "unsupported regulator type: %d\n",
+			regulator->rpm_vreg->regulator_type);
+		return -EINVAL;
+	}
+
+	if (min_uV > max_uV) {
+		vreg_err(regulator, "min_uV=%d must be less than max_uV=%d\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	if (uV < regulator->min_uV && max_uV >= regulator->min_uV)
+		uV = regulator->min_uV;
+
+	if (uV < regulator->min_uV || uV > regulator->max_uV) {
+		vreg_err(regulator,
+			"request v=[%d, %d] is outside allowed v=[%d, %d]\n",
+			min_uV, max_uV, regulator->min_uV, regulator->max_uV);
+		return -EINVAL;
+	}
+
+	return regulator->rdesc.ops->set_voltage(regulator->rdev, uV, uV, NULL);
+}
+EXPORT_SYMBOL(rpm_regulator_set_voltage);
+
+/**
+ * rpm_regulator_set_mode() - set regulator operating mode
+ * @regulator: RPM regulator handle
+ * @mode: operating mode requested for the regulator
+ *
+ * Requests that the mode of the regulator be set to the mode specified.  This
+ * parameter is aggregated using a max function such that AUTO < IPEAK < HPM.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int rpm_regulator_set_mode(struct rpm_regulator *regulator,
+				enum rpm_regulator_mode mode)
+{
+	int index = 0;
+	u32 new_mode, prev_mode;
+	int rc;
+
+	rc = rpm_regulator_check_input(regulator);
+	if (rc)
+		return rc;
+
+	if (mode < 0 || mode >= ARRAY_SIZE(mode_mapping)) {
+		vreg_err(regulator, "invalid mode requested: %d\n", mode);
+		return -EINVAL;
+	}
+
+	switch (regulator->rpm_vreg->regulator_type) {
+	case RPM_REGULATOR_TYPE_SMPS:
+		index = RPM_REGULATOR_PARAM_MODE_SMPS;
+		new_mode = mode_mapping[mode].smps_mode;
+		break;
+	case RPM_REGULATOR_TYPE_LDO:
+		index = RPM_REGULATOR_PARAM_MODE_LDO;
+		new_mode = mode_mapping[mode].ldo_mode;
+		break;
+	default:
+		vreg_err(regulator, "unsupported regulator type: %d\n",
+			regulator->rpm_vreg->regulator_type);
+		return -EINVAL;
+	};
+
+	if (new_mode < params[index].min || new_mode > params[index].max) {
+		vreg_err(regulator, "invalid mode requested: %d for type: %d\n",
+			mode, regulator->rpm_vreg->regulator_type);
+		return -EINVAL;
+	}
+
+	rpm_vreg_lock(regulator->rpm_vreg);
+
+	prev_mode = regulator->req.param[index];
+	regulator->req.param[index] = new_mode;
+	regulator->req.modified |= BIT(index);
+
+	rc = rpm_vreg_aggregate_requests(regulator);
+	if (rc) {
+		vreg_err(regulator, "set mode failed, rc=%d", rc);
+		regulator->req.param[index] = prev_mode;
+	}
+
+	rpm_vreg_unlock(regulator->rpm_vreg);
+
+	return rc;
+}
+EXPORT_SYMBOL(rpm_regulator_set_mode);
+
+static struct regulator_ops ldo_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.set_mode		= rpm_vreg_set_mode,
+	.get_mode		= rpm_vreg_get_mode,
+	.get_optimum_mode	= rpm_vreg_get_optimum_mode,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops smps_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.set_mode		= rpm_vreg_set_mode,
+	.get_mode		= rpm_vreg_get_mode,
+	.get_optimum_mode	= rpm_vreg_get_optimum_mode,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops switch_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops ncp_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops bob_ops = {
+	.enable			= rpm_vreg_enable,
+	.disable		= rpm_vreg_disable,
+	.is_enabled		= rpm_vreg_is_enabled,
+	.set_voltage		= rpm_vreg_set_voltage,
+	.get_voltage		= rpm_vreg_get_voltage,
+	.set_mode		= rpm_vreg_set_bob_mode,
+	.get_mode		= rpm_vreg_get_bob_mode,
+	.enable_time		= rpm_vreg_enable_time,
+};
+
+static struct regulator_ops *vreg_ops[] = {
+	[RPM_REGULATOR_TYPE_LDO]	= &ldo_ops,
+	[RPM_REGULATOR_TYPE_SMPS]	= &smps_ops,
+	[RPM_REGULATOR_TYPE_VS]		= &switch_ops,
+	[RPM_REGULATOR_TYPE_NCP]	= &ncp_ops,
+	[RPM_REGULATOR_TYPE_BOB]	= &bob_ops,
+};
+
+static int rpm_vreg_device_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rpm_regulator *reg;
+	struct rpm_vreg *rpm_vreg;
+
+	reg = platform_get_drvdata(pdev);
+	if (reg) {
+		rpm_vreg = reg->rpm_vreg;
+		rpm_vreg_lock(rpm_vreg);
+		regulator_unregister(reg->rdev);
+		list_del(&reg->list);
+		kfree(reg);
+		rpm_vreg_unlock(rpm_vreg);
+	} else {
+		dev_err(dev, "%s: drvdata missing\n", __func__);
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static int rpm_vreg_resource_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rpm_regulator *reg, *reg_temp;
+	struct rpm_vreg *rpm_vreg;
+
+	rpm_vreg = platform_get_drvdata(pdev);
+	if (rpm_vreg) {
+		rpm_vreg_lock(rpm_vreg);
+		list_for_each_entry_safe(reg, reg_temp, &rpm_vreg->reg_list,
+				list) {
+			/* Only touch data for private consumers. */
+			if (reg->rdev->desc == NULL) {
+				list_del(&reg->list);
+				kfree(reg->rdev);
+				kfree(reg);
+			} else {
+				dev_err(dev, "%s: not all child devices have been removed\n",
+					__func__);
+			}
+		}
+		rpm_vreg_unlock(rpm_vreg);
+
+		msm_rpm_free_request(rpm_vreg->handle_active);
+		msm_rpm_free_request(rpm_vreg->handle_sleep);
+
+		kfree(rpm_vreg);
+	} else {
+		dev_err(dev, "%s: drvdata missing\n", __func__);
+		return -EINVAL;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static int rpm_vreg_set_smps_ldo_voltage_index(struct device *dev,
+					struct rpm_regulator *reg)
+{
+	struct device_node *node = dev->of_node;
+	int chosen = 0;
+
+	if (of_property_read_bool(node, "qcom,use-voltage-corner")) {
+		reg->voltage_index = RPM_REGULATOR_PARAM_CORNER;
+		reg->voltage_offset = RPM_REGULATOR_CORNER_NONE;
+		chosen++;
+	}
+
+	if (of_property_read_bool(node, "qcom,use-voltage-floor-corner")) {
+		reg->voltage_index = RPM_REGULATOR_PARAM_FLOOR_CORNER;
+		reg->voltage_offset = RPM_REGULATOR_CORNER_NONE;
+		chosen++;
+	}
+
+	if (of_property_read_bool(node, "qcom,use-voltage-level")) {
+		reg->voltage_index = RPM_REGULATOR_PARAM_LEVEL;
+		chosen++;
+	}
+
+	if (of_property_read_bool(node, "qcom,use-voltage-floor-level")) {
+		reg->voltage_index = RPM_REGULATOR_PARAM_FLOOR_LEVEL;
+		chosen++;
+	}
+
+	if (chosen > 1) {
+		dev_err(dev, "only one qcom,use-voltage-* may be specified\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rpm_vreg_set_bob_voltage_index(struct device *dev,
+					struct rpm_regulator *reg)
+{
+	struct device_node *node = dev->of_node;
+	int chosen = 0;
+
+	if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage1")) {
+		reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE1;
+		chosen++;
+	}
+
+	if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage2")) {
+		reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE2;
+		chosen++;
+	}
+
+	if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage3")) {
+		reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE3;
+		chosen++;
+	}
+
+	if (chosen > 1) {
+		dev_err(dev, "only one qcom,use-pin-ctrl-voltage* may be specified\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rpm_vreg_device_set_voltage_index(struct device *dev,
+					struct rpm_regulator *reg, int type)
+{
+	int rc = 0;
+
+	reg->voltage_index = RPM_REGULATOR_PARAM_VOLTAGE;
+
+	switch (type) {
+	case RPM_REGULATOR_TYPE_SMPS:
+	case RPM_REGULATOR_TYPE_LDO:
+		rc = rpm_vreg_set_smps_ldo_voltage_index(dev, reg);
+		break;
+	case RPM_REGULATOR_TYPE_BOB:
+		rc = rpm_vreg_set_bob_voltage_index(dev, reg);
+		break;
+	}
+
+	return rc;
+}
+
+/*
+ * This probe is called for child rpm-regulator devices which have
+ * properties which are required to configure individual regulator
+ * framework regulators for a given RPM regulator resource.
+ */
+static int rpm_vreg_device_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct regulator_init_data *init_data;
+	struct rpm_vreg *rpm_vreg;
+	struct rpm_regulator *reg;
+	struct regulator_config reg_config = {};
+	int rc = 0;
+	int i, regulator_type;
+	u32 val;
+
+	if (!dev->of_node) {
+		dev_err(dev, "%s: device tree information missing\n", __func__);
+		return -ENODEV;
+	}
+
+	if (pdev->dev.parent == NULL) {
+		dev_err(dev, "%s: parent device missing\n", __func__);
+		return -ENODEV;
+	}
+
+	rpm_vreg = dev_get_drvdata(pdev->dev.parent);
+	if (rpm_vreg == NULL) {
+		dev_err(dev, "%s: rpm_vreg not found in parent device\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+	if (reg == NULL) {
+		dev_err(dev, "%s: could not allocate memory for reg\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	regulator_type		= rpm_vreg->regulator_type;
+	reg->rpm_vreg		= rpm_vreg;
+	reg->rdesc.owner	= THIS_MODULE;
+	reg->rdesc.type		= REGULATOR_VOLTAGE;
+	reg->rdesc.ops		= vreg_ops[regulator_type];
+
+	rc = rpm_vreg_device_set_voltage_index(dev, reg, regulator_type);
+	if (rc)
+		goto fail_free_reg;
+
+	reg->always_send_voltage
+		= of_property_read_bool(node, "qcom,always-send-voltage");
+	reg->always_send_current
+		= of_property_read_bool(node, "qcom,always-send-current");
+
+	if (regulator_type == RPM_REGULATOR_TYPE_VS)
+		reg->rdesc.n_voltages = 0;
+	else
+		reg->rdesc.n_voltages = 2;
+
+	rc = of_property_read_u32(node, "qcom,set", &val);
+	if (rc) {
+		dev_err(dev, "%s: sleep set and/or active set must be configured via qcom,set property, rc=%d\n",
+			__func__, rc);
+		goto fail_free_reg;
+	} else if (!(val & RPM_SET_CONFIG_BOTH)) {
+		dev_err(dev, "%s: qcom,set=%u property is invalid\n", __func__,
+			val);
+		rc = -EINVAL;
+		goto fail_free_reg;
+	}
+
+	reg->set_active = !!(val & RPM_SET_CONFIG_ACTIVE);
+	reg->set_sleep = !!(val & RPM_SET_CONFIG_SLEEP);
+
+	init_data = of_get_regulator_init_data(dev, node, &reg->rdesc);
+	if (init_data == NULL) {
+		dev_err(dev, "%s: unable to allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail_free_reg;
+	}
+	if (init_data->constraints.name == NULL) {
+		dev_err(dev, "%s: regulator name not specified\n", __func__);
+		rc = -EINVAL;
+		goto fail_free_reg;
+	}
+
+	init_data->constraints.input_uV	= init_data->constraints.max_uV;
+
+	if (of_get_property(node, "parent-supply", NULL))
+		init_data->supply_regulator = "parent";
+
+	/*
+	 * Fill in ops and mode masks based on callbacks specified for
+	 * this type of regulator.
+	 */
+	if (reg->rdesc.ops->enable)
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_STATUS;
+	if (reg->rdesc.ops->get_voltage)
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_VOLTAGE;
+	if (reg->rdesc.ops->get_mode) {
+		init_data->constraints.valid_ops_mask
+			|= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS;
+		init_data->constraints.valid_modes_mask
+			|= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+	}
+
+	reg->rdesc.name		= init_data->constraints.name;
+	reg->min_uV		= init_data->constraints.min_uV;
+	reg->max_uV		= init_data->constraints.max_uV;
+
+	/* Initialize the param array based on optional properties. */
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+		rc = of_property_read_u32(node, params[i].property_name, &val);
+		if (rc == 0) {
+			if (params[i].supported_regulator_types
+					& BIT(regulator_type)) {
+				if (val < params[i].min
+						|| val > params[i].max) {
+					pr_warn("%s: device tree property: %s=%u is outsided allowed range [%u, %u]\n",
+						reg->rdesc.name,
+						params[i].property_name, val,
+						params[i].min, params[i].max);
+					continue;
+				}
+				reg->req.param[i] = val;
+				reg->req.modified |= BIT(i);
+			} else {
+				pr_warn("%s: regulator type=%d does not support device tree property: %s\n",
+					reg->rdesc.name, regulator_type,
+					params[i].property_name);
+			}
+		}
+	}
+
+	of_property_read_u32(node, "qcom,system-load", &reg->system_load);
+
+	rc = rpm_vreg_configure_pin_control_enable(reg, node);
+	if (rc) {
+		vreg_err(reg, "could not configure pin control enable, rc=%d\n",
+			rc);
+		goto fail_free_reg;
+	}
+
+	rpm_vreg_lock(rpm_vreg);
+	list_add(&reg->list, &rpm_vreg->reg_list);
+	rpm_vreg_unlock(rpm_vreg);
+
+	if (of_property_read_bool(node, "qcom,send-defaults")) {
+		rc = rpm_vreg_send_defaults(reg);
+		if (rc) {
+			vreg_err(reg, "could not send defaults, rc=%d\n", rc);
+			goto fail_remove_from_list;
+		}
+	}
+
+	reg_config.dev = dev;
+	reg_config.init_data = init_data;
+	reg_config.of_node = node;
+	reg_config.driver_data = reg;
+	reg->rdev = regulator_register(&reg->rdesc, &reg_config);
+	if (IS_ERR(reg->rdev)) {
+		rc = PTR_ERR(reg->rdev);
+		reg->rdev = NULL;
+		pr_err("regulator_register failed: %s, rc=%d\n",
+			reg->rdesc.name, rc);
+		goto fail_remove_from_list;
+	}
+
+	platform_set_drvdata(pdev, reg);
+
+	pr_debug("successfully probed: %s\n", reg->rdesc.name);
+
+	return 0;
+
+fail_remove_from_list:
+	rpm_vreg_lock(rpm_vreg);
+	list_del(&reg->list);
+	rpm_vreg_unlock(rpm_vreg);
+
+fail_free_reg:
+	kfree(reg);
+	return rc;
+}
+
+/*
+ * This probe is called for parent rpm-regulator devices which have
+ * properties which are required to identify a given RPM resource.
+ */
+static int rpm_vreg_resource_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct rpm_vreg *rpm_vreg;
+	int val = 0;
+	u32 resource_type;
+	int rc;
+
+	if (!dev->of_node) {
+		dev_err(dev, "%s: device tree information missing\n", __func__);
+		return -ENODEV;
+	}
+
+	/* Create new rpm_vreg entry. */
+	rpm_vreg = kzalloc(sizeof(struct rpm_vreg), GFP_KERNEL);
+	if (rpm_vreg == NULL) {
+		dev_err(dev, "%s: could not allocate memory for vreg\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	/* Required device tree properties: */
+	rc = of_property_read_string(node, "qcom,resource-name",
+			&rpm_vreg->resource_name);
+	if (rc) {
+		dev_err(dev, "%s: qcom,resource-name missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+	resource_type = rpm_vreg_string_to_int(rpm_vreg->resource_name);
+
+	rc = of_property_read_u32(node, "qcom,resource-id",
+			&rpm_vreg->resource_id);
+	if (rc) {
+		dev_err(dev, "%s: qcom,resource-id missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+
+	rc = of_property_read_u32(node, "qcom,regulator-type",
+			&rpm_vreg->regulator_type);
+	if (rc) {
+		dev_err(dev, "%s: qcom,regulator-type missing in DT node\n",
+			__func__);
+		goto fail_free_vreg;
+	}
+
+	if ((rpm_vreg->regulator_type < 0)
+	    || (rpm_vreg->regulator_type >= RPM_REGULATOR_TYPE_MAX)) {
+		dev_err(dev, "%s: invalid regulator type: %d\n", __func__,
+			rpm_vreg->regulator_type);
+		rc = -EINVAL;
+		goto fail_free_vreg;
+	}
+
+	/* Optional device tree properties: */
+	of_property_read_u32(node, "qcom,allow-atomic", &val);
+	rpm_vreg->allow_atomic = !!val;
+	of_property_read_u32(node, "qcom,enable-time", &rpm_vreg->enable_time);
+	of_property_read_u32(node, "qcom,hpm-min-load",
+		&rpm_vreg->hpm_min_load);
+	rpm_vreg->apps_only = of_property_read_bool(node, "qcom,apps-only");
+	rpm_vreg->always_wait_for_ack
+		= of_property_read_bool(node, "qcom,always-wait-for-ack");
+
+	rpm_vreg->handle_active = msm_rpm_create_request(RPM_SET_ACTIVE,
+		resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
+	if (rpm_vreg->handle_active == NULL
+	    || IS_ERR(rpm_vreg->handle_active)) {
+		rc = PTR_ERR(rpm_vreg->handle_active);
+		if (rc != -EPROBE_DEFER)
+			dev_err(dev, "%s: failed to create active RPM handle, rc=%d\n",
+				__func__, rc);
+		goto fail_free_vreg;
+	}
+
+	rpm_vreg->handle_sleep = msm_rpm_create_request(RPM_SET_SLEEP,
+		resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
+	if (rpm_vreg->handle_sleep == NULL || IS_ERR(rpm_vreg->handle_sleep)) {
+		rc = PTR_ERR(rpm_vreg->handle_sleep);
+		if (rc != -EPROBE_DEFER)
+			dev_err(dev, "%s: failed to create sleep RPM handle, rc=%d\n",
+				__func__, rc);
+		goto fail_free_handle_active;
+	}
+
+	INIT_LIST_HEAD(&rpm_vreg->reg_list);
+
+	if (rpm_vreg->allow_atomic)
+		spin_lock_init(&rpm_vreg->slock);
+	else
+		mutex_init(&rpm_vreg->mlock);
+
+	platform_set_drvdata(pdev, rpm_vreg);
+
+	rc = of_platform_populate(node, NULL, NULL, dev);
+	if (rc) {
+		dev_err(dev, "%s: failed to add child nodes, rc=%d\n", __func__,
+			rc);
+		goto fail_unset_drvdata;
+	}
+
+	pr_debug("successfully probed: %s (%08X) %u\n", rpm_vreg->resource_name,
+		resource_type, rpm_vreg->resource_id);
+
+	return rc;
+
+fail_unset_drvdata:
+	platform_set_drvdata(pdev, NULL);
+	msm_rpm_free_request(rpm_vreg->handle_sleep);
+
+fail_free_handle_active:
+	msm_rpm_free_request(rpm_vreg->handle_active);
+
+fail_free_vreg:
+	kfree(rpm_vreg);
+
+	return rc;
+}
+
+static struct of_device_id rpm_vreg_match_table_device[] = {
+	{ .compatible = "qcom,rpm-smd-regulator", },
+	{}
+};
+
+static struct of_device_id rpm_vreg_match_table_resource[] = {
+	{ .compatible = "qcom,rpm-smd-regulator-resource", },
+	{}
+};
+
+static struct platform_driver rpm_vreg_device_driver = {
+	.probe = rpm_vreg_device_probe,
+	.remove = rpm_vreg_device_remove,
+	.driver = {
+		.name = "qcom,rpm-smd-regulator",
+		.owner = THIS_MODULE,
+		.of_match_table = rpm_vreg_match_table_device,
+	},
+};
+
+static struct platform_driver rpm_vreg_resource_driver = {
+	.probe = rpm_vreg_resource_probe,
+	.remove = rpm_vreg_resource_remove,
+	.driver = {
+		.name = "qcom,rpm-smd-regulator-resource",
+		.owner = THIS_MODULE,
+		.of_match_table = rpm_vreg_match_table_resource,
+	},
+};
+
+/**
+ * rpm_smd_regulator_driver_init() - initialize the RPM SMD regulator drivers
+ *
+ * This function registers the RPM SMD regulator platform drivers.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init rpm_smd_regulator_driver_init(void)
+{
+	static bool initialized;
+	int i, rc;
+
+	if (initialized)
+		return 0;
+	else
+		initialized = true;
+
+	/* Store parameter string names as integers */
+	for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++)
+		params[i].key = rpm_vreg_string_to_int(params[i].name);
+
+	rc = platform_driver_register(&rpm_vreg_device_driver);
+	if (rc)
+		return rc;
+
+	return platform_driver_register(&rpm_vreg_resource_driver);
+}
+EXPORT_SYMBOL(rpm_smd_regulator_driver_init);
+
+static void __exit rpm_vreg_exit(void)
+{
+	platform_driver_unregister(&rpm_vreg_device_driver);
+	platform_driver_unregister(&rpm_vreg_resource_driver);
+}
+
+arch_initcall(rpm_smd_regulator_driver_init);
+module_exit(rpm_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM RPM SMD regulator driver");
diff --git a/drivers/regulator/spm-regulator.c b/drivers/regulator/spm-regulator.c
new file mode 100644
index 0000000..af8e96f
--- /dev/null
+++ b/drivers/regulator/spm-regulator.c
@@ -0,0 +1,1329 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/arm-smccc.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/spm-regulator.h>
+#include <soc/qcom/spm.h>
+#include <linux/arm-smccc.h>
+
+#if defined(CONFIG_ARM64) || (defined(CONFIG_ARM) && defined(CONFIG_ARM_PSCI))
+#else
+	#define __invoke_psci_fn_smc(a, b, c, d) 0
+#endif
+
+#define SPM_REGULATOR_DRIVER_NAME "qcom,spm-regulator"
+
+struct voltage_range {
+	int min_uV;
+	int set_point_min_uV;
+	int max_uV;
+	int step_uV;
+};
+
+enum qpnp_regulator_uniq_type {
+	QPNP_TYPE_HF,
+	QPNP_TYPE_FTS2,
+	QPNP_TYPE_FTS2p5,
+	QPNP_TYPE_FTS426,
+	QPNP_TYPE_ULT_HF,
+};
+
+enum qpnp_regulator_type {
+	QPNP_HF_TYPE		= 0x03,
+	QPNP_FTS2_TYPE		= 0x1C,
+	QPNP_FTS2p5_TYPE	= 0x1C,
+	QPNP_FTS426_TYPE	= 0x1C,
+	QPNP_ULT_HF_TYPE	= 0x22,
+};
+
+enum qpnp_regulator_subtype {
+	QPNP_FTS2_SUBTYPE	= 0x08,
+	QPNP_HF_SUBTYPE		= 0x08,
+	QPNP_FTS2p5_SUBTYPE	= 0x09,
+	QPNP_FTS426_SUBTYPE	= 0x0A,
+	QPNP_ULT_HF_SUBTYPE	= 0x0D,
+};
+
+enum qpnp_logical_mode {
+	QPNP_LOGICAL_MODE_AUTO,
+	QPNP_LOGICAL_MODE_PWM,
+};
+
+static const struct voltage_range fts2_range0 = {0, 350000, 1275000,  5000};
+static const struct voltage_range fts2_range1 = {0, 700000, 2040000, 10000};
+static const struct voltage_range fts2p5_range0
+					 = { 80000, 350000, 1355000,  5000};
+static const struct voltage_range fts2p5_range1
+					 = {160000, 700000, 2200000, 10000};
+static const struct voltage_range fts426_range = {0, 320000, 1352000, 4000};
+static const struct voltage_range ult_hf_range0 = {375000, 375000, 1562500,
+								12500};
+static const struct voltage_range ult_hf_range1 = {750000, 750000, 1525000,
+								25000};
+static const struct voltage_range hf_range0 = {375000, 375000, 1562500, 12500};
+static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
+								25000};
+
+#define QPNP_SMPS_REG_TYPE		0x04
+#define QPNP_SMPS_REG_SUBTYPE		0x05
+#define QPNP_SMPS_REG_VOLTAGE_RANGE	0x40
+#define QPNP_SMPS_REG_VOLTAGE_SETPOINT	0x41
+#define QPNP_SMPS_REG_MODE		0x45
+#define QPNP_SMPS_REG_STEP_CTRL		0x61
+#define QPNP_SMPS_REG_UL_LL_CTRL	0x68
+
+/* FTS426 voltage control registers */
+#define QPNP_FTS426_REG_VOLTAGE_LB		0x40
+#define QPNP_FTS426_REG_VOLTAGE_UB		0x41
+#define QPNP_FTS426_REG_VOLTAGE_VALID_LB	0x42
+#define QPNP_FTS426_REG_VOLTAGE_VALID_UB	0x43
+
+/* HF voltage limit registers */
+#define QPNP_HF_REG_VOLTAGE_ULS		0x69
+#define QPNP_HF_REG_VOLTAGE_LLS		0x6B
+
+/* FTS voltage limit registers */
+#define QPNP_FTS_REG_VOLTAGE_ULS_VALID	0x6A
+#define QPNP_FTS_REG_VOLTAGE_LLS_VALID	0x6C
+
+/* FTS426 voltage limit registers */
+#define QPNP_FTS426_REG_VOLTAGE_ULS_LB	0x68
+#define QPNP_FTS426_REG_VOLTAGE_ULS_UB	0x69
+
+/* Common regulator UL & LL limits control register layout */
+#define QPNP_COMMON_UL_EN_MASK		0x80
+#define QPNP_COMMON_LL_EN_MASK		0x40
+
+#define QPNP_SMPS_MODE_PWM		0x80
+#define QPNP_SMPS_MODE_AUTO		0x40
+#define QPNP_FTS426_MODE_PWM		0x07
+#define QPNP_FTS426_MODE_AUTO		0x06
+
+#define QPNP_SMPS_STEP_CTRL_STEP_MASK	0x18
+#define QPNP_SMPS_STEP_CTRL_STEP_SHIFT	3
+#define QPNP_SMPS_STEP_CTRL_DELAY_MASK	0x07
+#define QPNP_SMPS_STEP_CTRL_DELAY_SHIFT	0
+#define QPNP_FTS426_STEP_CTRL_DELAY_MASK	0x03
+#define QPNP_FTS426_STEP_CTRL_DELAY_SHIFT	0
+
+/* Clock rate in kHz of the FTS2 regulator reference clock. */
+#define QPNP_SMPS_CLOCK_RATE		19200
+#define QPNP_FTS426_CLOCK_RATE		4800
+
+/* Time to delay in us to ensure that a mode change has completed. */
+#define QPNP_FTS2_MODE_CHANGE_DELAY	50
+
+/* Minimum time in us that it takes to complete a single SPMI write. */
+#define QPNP_SPMI_WRITE_MIN_DELAY	8
+
+/* Minimum voltage stepper delay for each step. */
+#define QPNP_FTS2_STEP_DELAY		8
+#define QPNP_HF_STEP_DELAY		20
+#define QPNP_FTS426_STEP_DELAY		2
+
+/* Arbitrarily large max step size used to avoid possible numerical overflow */
+#define SPM_REGULATOR_MAX_STEP_UV	10000000
+
+/*
+ * The ratio QPNP_FTS2_STEP_MARGIN_NUM/QPNP_FTS2_STEP_MARGIN_DEN is use to
+ * adjust the step rate in order to account for oscillator variance.
+ */
+#define QPNP_FTS2_STEP_MARGIN_NUM	4
+#define QPNP_FTS2_STEP_MARGIN_DEN	5
+#define QPNP_FTS426_STEP_MARGIN_NUM	10
+#define QPNP_FTS426_STEP_MARGIN_DEN	11
+
+/*
+ * Settling delay for FTS2.5
+ * Warm-up=20uS, 0-10% & 90-100% non-linear V-ramp delay = 50uS
+ */
+#define FTS2P5_SETTLING_DELAY_US	70
+
+/* VSET value to decide the range of ULT SMPS */
+#define ULT_SMPS_RANGE_SPLIT 0x60
+
+struct spm_vreg {
+	struct regulator_desc		rdesc;
+	struct regulator_dev		*rdev;
+	struct platform_device		*pdev;
+	struct regmap			*regmap;
+	const struct voltage_range	*range;
+	int				uV;
+	int				last_set_uV;
+	unsigned			vlevel;
+	unsigned			last_set_vlevel;
+	u32				max_step_uV;
+	bool				online;
+	u16				spmi_base_addr;
+	enum qpnp_logical_mode		init_mode;
+	enum qpnp_logical_mode		mode;
+	int				step_rate;
+	enum qpnp_regulator_uniq_type	regulator_type;
+	u32				cpu_num;
+	bool				bypass_spm;
+	struct regulator_desc		avs_rdesc;
+	struct regulator_dev		*avs_rdev;
+	int				avs_min_uV;
+	int				avs_max_uV;
+	bool				avs_enabled;
+	u32				recal_cluster_mask;
+};
+
+static inline bool spm_regulator_using_avs(struct spm_vreg *vreg)
+{
+	return vreg->avs_rdev && !vreg->bypass_spm;
+}
+
+static int spm_regulator_uv_to_vlevel(struct spm_vreg *vreg, int uV)
+{
+	int vlevel;
+
+	if (vreg->regulator_type == QPNP_TYPE_FTS426)
+		return roundup(uV, vreg->range->step_uV) / 1000;
+
+	vlevel = DIV_ROUND_UP(uV - vreg->range->min_uV, vreg->range->step_uV);
+
+	/* Fix VSET for ULT HF Buck */
+	if (vreg->regulator_type == QPNP_TYPE_ULT_HF
+	    && vreg->range == &ult_hf_range1) {
+		vlevel &= 0x1F;
+		vlevel |= ULT_SMPS_RANGE_SPLIT;
+	}
+
+	return vlevel;
+}
+
+static int spm_regulator_vlevel_to_uv(struct spm_vreg *vreg, int vlevel)
+{
+	if (vreg->regulator_type == QPNP_TYPE_FTS426)
+		return vlevel * 1000;
+	/*
+	 * Calculate ULT HF buck VSET based on range:
+	 * In case of range 0: VSET is a 7 bit value.
+	 * In case of range 1: VSET is a 5 bit value.
+	 */
+	if (vreg->regulator_type == QPNP_TYPE_ULT_HF
+	    && vreg->range == &ult_hf_range1)
+		vlevel &= ~ULT_SMPS_RANGE_SPLIT;
+
+	return vlevel * vreg->range->step_uV + vreg->range->min_uV;
+}
+
+static unsigned spm_regulator_vlevel_to_selector(struct spm_vreg *vreg,
+						 unsigned vlevel)
+{
+	/* Fix VSET for ULT HF Buck */
+	if (vreg->regulator_type == QPNP_TYPE_ULT_HF
+	    && vreg->range == &ult_hf_range1)
+		vlevel &= ~ULT_SMPS_RANGE_SPLIT;
+
+	return vlevel - (vreg->range->set_point_min_uV - vreg->range->min_uV)
+				/ vreg->range->step_uV;
+}
+
+static int qpnp_smps_read_voltage(struct spm_vreg *vreg)
+{
+	int rc;
+	u8 val[2] = {0};
+
+	if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+		rc = regmap_bulk_read(vreg->regmap,
+			vreg->spmi_base_addr + QPNP_FTS426_REG_VOLTAGE_VALID_LB,
+				 val, 2);
+		if (rc) {
+			dev_err(&vreg->pdev->dev, "%s: could not read voltage setpoint registers, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		vreg->last_set_vlevel = ((unsigned)val[1] << 8) | val[0];
+	} else {
+		rc = regmap_bulk_read(vreg->regmap,
+			vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+				val, 1);
+		if (rc) {
+			dev_err(&vreg->pdev->dev, "%s: could not read voltage setpoint register, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+		vreg->last_set_vlevel = val[0];
+	}
+
+	vreg->last_set_uV = spm_regulator_vlevel_to_uv(vreg,
+						vreg->last_set_vlevel);
+	return rc;
+}
+
+static int qpnp_smps_write_voltage(struct spm_vreg *vreg, unsigned vlevel)
+{
+	int rc = 0;
+	u8 reg[2];
+
+	/* Set voltage control registers via SPMI. */
+	reg[0] = vlevel & 0xFF;
+	reg[1] = (vlevel >> 8) & 0xFF;
+
+	if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+		rc = regmap_bulk_write(vreg->regmap,
+			  vreg->spmi_base_addr + QPNP_FTS426_REG_VOLTAGE_LB,
+			  reg, 2);
+	} else {
+		rc = regmap_write(vreg->regmap,
+			  vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+			  reg[0]);
+	}
+
+	if (rc)
+		pr_err("%s: regmap_write failed, rc=%d\n",
+			vreg->rdesc.name, rc);
+
+	return rc;
+}
+
+static inline enum qpnp_logical_mode qpnp_regval_to_mode(struct spm_vreg *vreg,
+							u8 regval)
+{
+	if (vreg->regulator_type == QPNP_TYPE_FTS426)
+		return (regval == QPNP_FTS426_MODE_PWM)
+			? QPNP_LOGICAL_MODE_PWM : QPNP_LOGICAL_MODE_AUTO;
+	else
+		return (regval & QPNP_SMPS_MODE_PWM)
+			? QPNP_LOGICAL_MODE_PWM : QPNP_LOGICAL_MODE_AUTO;
+}
+
+static inline u8 qpnp_mode_to_regval(struct spm_vreg *vreg,
+					enum qpnp_logical_mode mode)
+{
+	if (vreg->regulator_type == QPNP_TYPE_FTS426)
+		return (mode == QPNP_LOGICAL_MODE_PWM)
+			? QPNP_FTS426_MODE_PWM : QPNP_FTS426_MODE_AUTO;
+	else
+		return (mode == QPNP_LOGICAL_MODE_PWM)
+			? QPNP_SMPS_MODE_PWM : QPNP_SMPS_MODE_AUTO;
+}
+
+static int qpnp_smps_set_mode(struct spm_vreg *vreg, u8 mode)
+{
+	int rc;
+
+	rc = regmap_write(vreg->regmap,
+			  vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
+			  qpnp_mode_to_regval(vreg, mode));
+	if (rc)
+		dev_err(&vreg->pdev->dev,
+			"%s: could not write to mode register, rc=%d\n",
+			__func__, rc);
+
+	return rc;
+}
+
+static int spm_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+	int vlevel, rc;
+
+	if (spm_regulator_using_avs(vreg)) {
+		vlevel = msm_spm_get_vdd(vreg->cpu_num);
+
+		if (vlevel < 0) {
+			pr_debug("%s: msm_spm_get_vdd failed, rc=%d; falling back on SPMI read\n",
+				vreg->rdesc.name, vlevel);
+
+			rc = qpnp_smps_read_voltage(vreg);
+			if (rc) {
+				pr_err("%s: voltage read failed, rc=%d\n",
+				       vreg->rdesc.name, rc);
+				return rc;
+			}
+
+			return vreg->last_set_uV;
+		}
+
+		vreg->last_set_vlevel = vlevel;
+		vreg->last_set_uV = spm_regulator_vlevel_to_uv(vreg, vlevel);
+
+		return vreg->last_set_uV;
+	} else {
+		return vreg->uV;
+	}
+};
+
+static int spm_regulator_write_voltage(struct spm_vreg *vreg, int uV)
+{
+	unsigned vlevel = spm_regulator_uv_to_vlevel(vreg, uV);
+	bool spm_failed = false;
+	int rc = 0;
+	u32 slew_delay;
+
+	if (likely(!vreg->bypass_spm)) {
+		/* Set voltage control register via SPM. */
+		rc = msm_spm_set_vdd(vreg->cpu_num, vlevel);
+		if (rc) {
+			pr_debug("%s: msm_spm_set_vdd failed, rc=%d; falling back on SPMI write\n",
+				vreg->rdesc.name, rc);
+			spm_failed = true;
+		}
+	}
+
+	if (unlikely(vreg->bypass_spm || spm_failed)) {
+		rc = qpnp_smps_write_voltage(vreg, vlevel);
+		if (rc) {
+			pr_err("%s: voltage write failed, rc=%d\n",
+				vreg->rdesc.name, rc);
+			return rc;
+		}
+	}
+
+	if (uV > vreg->last_set_uV) {
+		/* Wait for voltage stepping to complete. */
+		slew_delay = DIV_ROUND_UP(uV - vreg->last_set_uV,
+					vreg->step_rate);
+		if (vreg->regulator_type == QPNP_TYPE_FTS2p5)
+			slew_delay += FTS2P5_SETTLING_DELAY_US;
+		udelay(slew_delay);
+	} else if (vreg->regulator_type == QPNP_TYPE_FTS2p5) {
+		/* add the ramp-down delay */
+		slew_delay = DIV_ROUND_UP(vreg->last_set_uV - uV,
+				vreg->step_rate) + FTS2P5_SETTLING_DELAY_US;
+		udelay(slew_delay);
+	}
+
+	vreg->last_set_uV = uV;
+	vreg->last_set_vlevel = vlevel;
+
+	return rc;
+}
+
+static int spm_regulator_recalibrate(struct spm_vreg *vreg)
+{
+	struct arm_smccc_res res;
+
+	if (!vreg->recal_cluster_mask)
+		return 0;
+
+	arm_smccc_smc(0xC4000020, vreg->recal_cluster_mask, 2, 0, 0, 0, 0, 0, &res);
+	if (res.a0)
+		pr_err("%s: recalibration failed, rc=%ld\n", vreg->rdesc.name,
+			res.a0);
+
+	return res.a0;
+}
+
+static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+	bool pwm_required;
+	int rc = 0;
+	int uV;
+
+	rc = spm_regulator_get_voltage(rdev);
+	if (rc < 0)
+		return rc;
+
+	if (vreg->vlevel == vreg->last_set_vlevel)
+		return 0;
+
+	pwm_required = (vreg->regulator_type == QPNP_TYPE_FTS2)
+			&& (vreg->init_mode != QPNP_LOGICAL_MODE_PWM)
+			&& vreg->uV > vreg->last_set_uV;
+
+	if (pwm_required) {
+		/* Switch to PWM mode so that voltage ramping is fast. */
+		rc = qpnp_smps_set_mode(vreg, QPNP_LOGICAL_MODE_PWM);
+		if (rc)
+			return rc;
+	}
+
+	do {
+		uV = vreg->uV > vreg->last_set_uV
+		    ? min(vreg->uV, vreg->last_set_uV + (int)vreg->max_step_uV)
+		    : max(vreg->uV, vreg->last_set_uV - (int)vreg->max_step_uV);
+
+		rc = spm_regulator_write_voltage(vreg, uV);
+		if (rc)
+			return rc;
+	} while (vreg->last_set_uV != vreg->uV);
+
+	if (pwm_required) {
+		/* Wait for mode transition to complete. */
+		udelay(QPNP_FTS2_MODE_CHANGE_DELAY - QPNP_SPMI_WRITE_MIN_DELAY);
+		/* Switch to AUTO mode so that power consumption is lowered. */
+		rc = qpnp_smps_set_mode(vreg, QPNP_LOGICAL_MODE_AUTO);
+		if (rc)
+			return rc;
+	}
+
+	rc = spm_regulator_recalibrate(vreg);
+
+	return rc;
+}
+
+static int spm_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
+					int max_uV, unsigned *selector)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+	const struct voltage_range *range = vreg->range;
+	int uV = min_uV;
+	unsigned vlevel;
+
+	if (uV < range->set_point_min_uV && max_uV >= range->set_point_min_uV)
+		uV = range->set_point_min_uV;
+
+	if (uV < range->set_point_min_uV || uV > range->max_uV) {
+		pr_err("%s: request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			vreg->rdesc.name, min_uV, max_uV,
+			range->set_point_min_uV, range->max_uV);
+		return -EINVAL;
+	}
+
+	vlevel = spm_regulator_uv_to_vlevel(vreg, uV);
+	uV = spm_regulator_vlevel_to_uv(vreg, vlevel);
+
+	if (uV > max_uV) {
+		pr_err("%s: request v=[%d, %d] cannot be met by any set point\n",
+			vreg->rdesc.name, min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	*selector = spm_regulator_vlevel_to_selector(vreg, vlevel);
+	vreg->vlevel = vlevel;
+	vreg->uV = uV;
+
+	if (!vreg->online)
+		return 0;
+
+	return _spm_regulator_set_voltage(rdev);
+}
+
+static int spm_regulator_list_voltage(struct regulator_dev *rdev,
+					unsigned selector)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+	if (selector >= vreg->rdesc.n_voltages)
+		return 0;
+
+	return selector * vreg->range->step_uV + vreg->range->set_point_min_uV;
+}
+
+static int spm_regulator_enable(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = _spm_regulator_set_voltage(rdev);
+
+	if (!rc)
+		vreg->online = true;
+
+	return rc;
+}
+
+static int spm_regulator_disable(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+	vreg->online = false;
+
+	return 0;
+}
+
+static int spm_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->online;
+}
+
+static unsigned int spm_regulator_get_mode(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->mode == QPNP_LOGICAL_MODE_PWM
+			? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static int spm_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+	/*
+	 * Map REGULATOR_MODE_NORMAL to PWM mode and REGULATOR_MODE_IDLE to
+	 * init_mode.  This ensures that the regulator always stays in PWM mode
+	 * in the case that qcom,mode has been specified as "pwm" in device
+	 * tree.
+	 */
+	vreg->mode = (mode == REGULATOR_MODE_NORMAL) ? QPNP_LOGICAL_MODE_PWM
+						     : vreg->init_mode;
+
+	return qpnp_smps_set_mode(vreg, vreg->mode);
+}
+
+static struct regulator_ops spm_regulator_ops = {
+	.get_voltage	= spm_regulator_get_voltage,
+	.set_voltage	= spm_regulator_set_voltage,
+	.list_voltage	= spm_regulator_list_voltage,
+	.get_mode	= spm_regulator_get_mode,
+	.set_mode	= spm_regulator_set_mode,
+	.enable		= spm_regulator_enable,
+	.disable	= spm_regulator_disable,
+	.is_enabled	= spm_regulator_is_enabled,
+};
+
+static int spm_regulator_avs_set_voltage(struct regulator_dev *rdev, int min_uV,
+					int max_uV, unsigned *selector)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+	const struct voltage_range *range = vreg->range;
+	unsigned vlevel_min, vlevel_max;
+	int uV, avs_min_uV, avs_max_uV, rc;
+
+	uV = min_uV;
+
+	if (uV < range->set_point_min_uV && max_uV >= range->set_point_min_uV)
+		uV = range->set_point_min_uV;
+
+	if (uV < range->set_point_min_uV || uV > range->max_uV) {
+		pr_err("%s: request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			vreg->avs_rdesc.name, min_uV, max_uV,
+			range->set_point_min_uV, range->max_uV);
+		return -EINVAL;
+	}
+
+	vlevel_min = spm_regulator_uv_to_vlevel(vreg, uV);
+	avs_min_uV = spm_regulator_vlevel_to_uv(vreg, vlevel_min);
+
+	if (avs_min_uV > max_uV) {
+		pr_err("%s: request v=[%d, %d] cannot be met by any set point\n",
+			vreg->avs_rdesc.name, min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	uV = max_uV;
+
+	if (uV > range->max_uV && min_uV <= range->max_uV)
+		uV = range->max_uV;
+
+	if (uV < range->set_point_min_uV || uV > range->max_uV) {
+		pr_err("%s: request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			vreg->avs_rdesc.name, min_uV, max_uV,
+			range->set_point_min_uV, range->max_uV);
+		return -EINVAL;
+	}
+
+	vlevel_max = spm_regulator_uv_to_vlevel(vreg, uV);
+	avs_max_uV = spm_regulator_vlevel_to_uv(vreg, vlevel_max);
+
+	if (avs_max_uV < min_uV) {
+		pr_err("%s: request v=[%d, %d] cannot be met by any set point\n",
+			vreg->avs_rdesc.name, min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	if (likely(!vreg->bypass_spm)) {
+		rc = msm_spm_avs_set_limit(vreg->cpu_num, vlevel_min,
+						vlevel_max);
+		if (rc) {
+			pr_err("%s: AVS limit setting failed, rc=%d\n",
+				vreg->avs_rdesc.name, rc);
+			return rc;
+		}
+	}
+
+	*selector = spm_regulator_vlevel_to_selector(vreg, vlevel_min);
+	vreg->avs_min_uV = avs_min_uV;
+	vreg->avs_max_uV = avs_max_uV;
+
+	return 0;
+}
+
+static int spm_regulator_avs_get_voltage(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->avs_min_uV;
+}
+
+static int spm_regulator_avs_enable(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	if (likely(!vreg->bypass_spm)) {
+		rc = msm_spm_avs_enable(vreg->cpu_num);
+		if (rc) {
+			pr_err("%s: AVS enable failed, rc=%d\n",
+				vreg->avs_rdesc.name, rc);
+			return rc;
+		}
+	}
+
+	vreg->avs_enabled = true;
+
+	return 0;
+}
+
+static int spm_regulator_avs_disable(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	if (likely(!vreg->bypass_spm)) {
+		rc = msm_spm_avs_disable(vreg->cpu_num);
+		if (rc) {
+			pr_err("%s: AVS disable failed, rc=%d\n",
+				vreg->avs_rdesc.name, rc);
+			return rc;
+		}
+	}
+
+	vreg->avs_enabled = false;
+
+	return 0;
+}
+
+static int spm_regulator_avs_is_enabled(struct regulator_dev *rdev)
+{
+	struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->avs_enabled;
+}
+
+static struct regulator_ops spm_regulator_avs_ops = {
+	.get_voltage	= spm_regulator_avs_get_voltage,
+	.set_voltage	= spm_regulator_avs_set_voltage,
+	.list_voltage	= spm_regulator_list_voltage,
+	.enable		= spm_regulator_avs_enable,
+	.disable	= spm_regulator_avs_disable,
+	.is_enabled	= spm_regulator_avs_is_enabled,
+};
+
+static int qpnp_smps_check_type(struct spm_vreg *vreg)
+{
+	int rc;
+	u8 type[2];
+
+	rc = regmap_bulk_read(vreg->regmap,
+			      vreg->spmi_base_addr + QPNP_SMPS_REG_TYPE,
+			      type,
+			      2);
+	if (rc) {
+		dev_err(&vreg->pdev->dev,
+			"%s: could not read type register, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	if (type[0] == QPNP_FTS2_TYPE && type[1] == QPNP_FTS2_SUBTYPE) {
+		vreg->regulator_type = QPNP_TYPE_FTS2;
+	} else if (type[0] == QPNP_FTS2p5_TYPE
+					&& type[1] == QPNP_FTS2p5_SUBTYPE) {
+		vreg->regulator_type = QPNP_TYPE_FTS2p5;
+	} else if (type[0] == QPNP_FTS426_TYPE
+					&& type[1] == QPNP_FTS426_SUBTYPE) {
+		vreg->regulator_type = QPNP_TYPE_FTS426;
+	} else if (type[0] == QPNP_ULT_HF_TYPE
+					&& type[1] == QPNP_ULT_HF_SUBTYPE) {
+		vreg->regulator_type = QPNP_TYPE_ULT_HF;
+	} else if (type[0] == QPNP_HF_TYPE
+					&& type[1] == QPNP_HF_SUBTYPE) {
+		vreg->regulator_type = QPNP_TYPE_HF;
+	} else {
+		dev_err(&vreg->pdev->dev,
+			"%s: invalid type=0x%02X, subtype=0x%02X register pair\n",
+			 __func__, type[0], type[1]);
+		return -ENODEV;
+	};
+
+	return rc;
+}
+
+static int qpnp_smps_init_range(struct spm_vreg *vreg,
+	const struct voltage_range *range0, const struct voltage_range *range1)
+{
+	int rc;
+	u8 reg = 0;
+	uint val;
+
+	rc = regmap_read(vreg->regmap,
+			 vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_RANGE,
+			 &val);
+	if (rc) {
+		dev_err(&vreg->pdev->dev,
+			"%s: could not read voltage range register, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+	reg = (u8)val;
+
+	if (reg == 0x00) {
+		vreg->range = range0;
+	} else if (reg == 0x01) {
+		vreg->range = range1;
+	} else {
+		dev_err(&vreg->pdev->dev, "%s: voltage range=%d is invalid\n",
+			__func__, reg);
+		rc = -EINVAL;
+	}
+
+	return rc;
+}
+
+static int qpnp_ult_hf_init_range(struct spm_vreg *vreg)
+{
+	int rc;
+	u8 reg = 0;
+	uint val;
+
+	rc = regmap_read(vreg->regmap,
+			 vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+			 &val);
+	if (rc) {
+		dev_err(&vreg->pdev->dev,
+			"%s: could not read voltage range register, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+	reg = (u8)val;
+
+	vreg->range = (reg < ULT_SMPS_RANGE_SPLIT) ? &ult_hf_range0 :
+							&ult_hf_range1;
+	return rc;
+}
+
+static int qpnp_smps_init_voltage(struct spm_vreg *vreg)
+{
+	int rc;
+
+	rc = qpnp_smps_read_voltage(vreg);
+	if (rc) {
+		pr_err("%s: voltage read failed, rc=%d\n", vreg->rdesc.name,
+			rc);
+		return rc;
+	}
+
+	vreg->vlevel = vreg->last_set_vlevel;
+	vreg->uV = vreg->last_set_uV;
+
+	/* Initialize SAW voltage control register */
+	if (!vreg->bypass_spm) {
+		rc = msm_spm_set_vdd(vreg->cpu_num, vreg->vlevel);
+		if (rc)
+			pr_err("%s: msm_spm_set_vdd failed, rc=%d\n",
+			       vreg->rdesc.name, rc);
+	}
+
+	return 0;
+}
+
+static int qpnp_smps_init_mode(struct spm_vreg *vreg)
+{
+	const char *mode_name;
+	int rc;
+	uint val;
+
+	rc = of_property_read_string(vreg->pdev->dev.of_node, "qcom,mode",
+					&mode_name);
+	if (!rc) {
+		if (strcmp("pwm", mode_name) == 0) {
+			vreg->init_mode = QPNP_LOGICAL_MODE_PWM;
+		} else if ((strcmp("auto", mode_name) == 0) &&
+				(vreg->regulator_type != QPNP_TYPE_ULT_HF)) {
+			vreg->init_mode = QPNP_LOGICAL_MODE_AUTO;
+		} else {
+			dev_err(&vreg->pdev->dev,
+				"%s: unknown regulator mode: %s\n",
+				__func__, mode_name);
+			return -EINVAL;
+		}
+
+		rc = qpnp_smps_set_mode(vreg, vreg->init_mode);
+		if (rc)
+			return rc;
+	} else {
+		rc = regmap_read(vreg->regmap,
+				 vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
+				 &val);
+		if (rc)
+			dev_err(&vreg->pdev->dev,
+				"%s: could not read mode register, rc=%d\n",
+				__func__, rc);
+		 vreg->init_mode = qpnp_regval_to_mode(vreg, val);
+	}
+
+	vreg->mode = vreg->init_mode;
+
+	return rc;
+}
+
+static int qpnp_smps_init_step_rate(struct spm_vreg *vreg)
+{
+	int rc;
+	u8 reg = 0;
+	int step = 0, delay;
+	uint val;
+
+	rc = regmap_read(vreg->regmap,
+			 vreg->spmi_base_addr + QPNP_SMPS_REG_STEP_CTRL, &val);
+	if (rc) {
+		dev_err(&vreg->pdev->dev,
+			"%s: could not read stepping control register, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+	reg = (u8)val;
+
+	/* ULT and FTS426 bucks do not support steps */
+	if (vreg->regulator_type != QPNP_TYPE_ULT_HF && vreg->regulator_type !=
+			QPNP_TYPE_FTS426)
+		step = (reg & QPNP_SMPS_STEP_CTRL_STEP_MASK)
+			>> QPNP_SMPS_STEP_CTRL_STEP_SHIFT;
+
+	if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+		delay = (reg & QPNP_FTS426_STEP_CTRL_DELAY_MASK)
+			>> QPNP_FTS426_STEP_CTRL_DELAY_SHIFT;
+
+		/* step_rate has units of uV/us. */
+		vreg->step_rate = QPNP_FTS426_CLOCK_RATE * vreg->range->step_uV;
+	} else {
+		delay = (reg & QPNP_SMPS_STEP_CTRL_DELAY_MASK)
+			>> QPNP_SMPS_STEP_CTRL_DELAY_SHIFT;
+
+		/* step_rate has units of uV/us. */
+		vreg->step_rate = QPNP_SMPS_CLOCK_RATE * vreg->range->step_uV
+					* (1 << step);
+	}
+
+	if ((vreg->regulator_type == QPNP_TYPE_ULT_HF)
+			|| (vreg->regulator_type == QPNP_TYPE_HF))
+		vreg->step_rate /= 1000 * (QPNP_HF_STEP_DELAY << delay);
+	else if (vreg->regulator_type == QPNP_TYPE_FTS426)
+		vreg->step_rate /= 1000 * (QPNP_FTS426_STEP_DELAY << delay);
+	else
+		vreg->step_rate /= 1000 * (QPNP_FTS2_STEP_DELAY << delay);
+
+	if (vreg->regulator_type == QPNP_TYPE_FTS426)
+		vreg->step_rate = vreg->step_rate * QPNP_FTS426_STEP_MARGIN_NUM
+					/ QPNP_FTS426_STEP_MARGIN_DEN;
+	else
+		vreg->step_rate = vreg->step_rate * QPNP_FTS2_STEP_MARGIN_NUM
+					/ QPNP_FTS2_STEP_MARGIN_DEN;
+
+	/* Ensure that the stepping rate is greater than 0. */
+	vreg->step_rate = max(vreg->step_rate, 1);
+
+	return rc;
+}
+
+static int qpnp_smps_check_constraints(struct spm_vreg *vreg,
+					struct regulator_init_data *init_data)
+{
+	int rc = 0, limit_min_uV, limit_max_uV;
+	u16 ul_reg, ll_reg;
+	u8 reg[2];
+
+	limit_min_uV = 0;
+	limit_max_uV = INT_MAX;
+
+	ul_reg = QPNP_FTS_REG_VOLTAGE_ULS_VALID;
+	ll_reg = QPNP_FTS_REG_VOLTAGE_LLS_VALID;
+
+	switch (vreg->regulator_type) {
+	case QPNP_TYPE_HF:
+		ul_reg = QPNP_HF_REG_VOLTAGE_ULS;
+		ll_reg = QPNP_HF_REG_VOLTAGE_LLS;
+	case QPNP_TYPE_FTS2:
+	case QPNP_TYPE_FTS2p5:
+		rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+					+ QPNP_SMPS_REG_UL_LL_CTRL, reg, 1);
+		if (rc) {
+			dev_err(&vreg->pdev->dev, "%s: UL_LL register read failed, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		if (reg[0] & QPNP_COMMON_UL_EN_MASK) {
+			rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+						+ ul_reg, &reg[1], 1);
+			if (rc) {
+				dev_err(&vreg->pdev->dev, "%s: ULS register read failed, rc=%d\n",
+					__func__, rc);
+				return rc;
+			}
+
+			limit_max_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+		}
+
+		if (reg[0] & QPNP_COMMON_LL_EN_MASK) {
+			rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+						+ ll_reg, &reg[1], 1);
+			if (rc) {
+				dev_err(&vreg->pdev->dev, "%s: LLS register read failed, rc=%d\n",
+					__func__, rc);
+				return rc;
+			}
+
+			limit_min_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+		}
+
+		break;
+	case QPNP_TYPE_FTS426:
+		rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+					+ QPNP_FTS426_REG_VOLTAGE_ULS_LB,
+					reg, 2);
+		if (rc) {
+			dev_err(&vreg->pdev->dev, "%s: could not read voltage limit registers, rc=%d\n",
+				__func__, rc);
+			return rc;
+		}
+
+		limit_max_uV = spm_regulator_vlevel_to_uv(vreg,
+					((unsigned)reg[1] << 8) | reg[0]);
+		break;
+	case QPNP_TYPE_ULT_HF:
+		/* no HW voltage limit configuration */
+		break;
+	}
+
+	if (init_data->constraints.min_uV < limit_min_uV
+	    || init_data->constraints.max_uV >  limit_max_uV) {
+		dev_err(&vreg->pdev->dev, "regulator min/max(%d/%d) constraints do not fit within HW configured min/max(%d/%d) constraints\n",
+			init_data->constraints.min_uV,
+			init_data->constraints.max_uV, limit_min_uV,
+			limit_max_uV);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static bool spm_regulator_using_range0(struct spm_vreg *vreg)
+{
+	return vreg->range == &fts2_range0 || vreg->range == &fts2p5_range0
+		|| vreg->range == &ult_hf_range0 || vreg->range == &hf_range0
+		|| vreg->range == &fts426_range;
+}
+
+/* Register a regulator to enable/disable AVS and set AVS min/max limits. */
+static int spm_regulator_avs_register(struct spm_vreg *vreg,
+				struct device *dev, struct device_node *node)
+{
+	struct regulator_config reg_config = {};
+	struct device_node *avs_node = NULL;
+	struct device_node *child_node;
+	struct regulator_init_data *init_data;
+	int rc;
+
+	/*
+	 * Find the first available child node (if any).  It corresponds to an
+	 * AVS limits regulator.
+	 */
+	for_each_available_child_of_node(node, child_node) {
+		avs_node = child_node;
+		break;
+	}
+
+	if (!avs_node)
+		return 0;
+
+	init_data = of_get_regulator_init_data(dev, avs_node, &vreg->avs_rdesc);
+	if (!init_data) {
+		dev_err(dev, "%s: unable to allocate memory\n", __func__);
+		return -ENOMEM;
+	}
+	init_data->constraints.input_uV = init_data->constraints.max_uV;
+	init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS
+						| REGULATOR_CHANGE_VOLTAGE;
+
+	if (!init_data->constraints.name) {
+		dev_err(dev, "%s: AVS node is missing regulator name\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	vreg->avs_rdesc.name	= init_data->constraints.name;
+	vreg->avs_rdesc.type	= REGULATOR_VOLTAGE;
+	vreg->avs_rdesc.owner	= THIS_MODULE;
+	vreg->avs_rdesc.ops	= &spm_regulator_avs_ops;
+	vreg->avs_rdesc.n_voltages
+		= (vreg->range->max_uV - vreg->range->set_point_min_uV)
+			/ vreg->range->step_uV + 1;
+
+	reg_config.dev = dev;
+	reg_config.init_data = init_data;
+	reg_config.driver_data = vreg;
+	reg_config.of_node = avs_node;
+
+	vreg->avs_rdev = regulator_register(&vreg->avs_rdesc, &reg_config);
+	if (IS_ERR(vreg->avs_rdev)) {
+		rc = PTR_ERR(vreg->avs_rdev);
+		dev_err(dev, "%s: AVS regulator_register failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	if (vreg->bypass_spm)
+		pr_debug("%s: SPM bypassed so AVS regulator calls are no-ops\n",
+			vreg->avs_rdesc.name);
+
+	return 0;
+}
+
+static int spm_regulator_probe(struct platform_device *pdev)
+{
+	struct regulator_config reg_config = {};
+	struct device_node *node = pdev->dev.of_node;
+	struct regulator_init_data *init_data;
+	struct spm_vreg *vreg;
+	unsigned int base;
+	bool bypass_spm;
+	int rc;
+
+	if (!node) {
+		dev_err(&pdev->dev, "%s: device node missing\n", __func__);
+		return -ENODEV;
+	}
+
+	bypass_spm = of_property_read_bool(node, "qcom,bypass-spm");
+	if (!bypass_spm) {
+		rc = msm_spm_probe_done();
+		if (rc) {
+			if (rc != -EPROBE_DEFER)
+				dev_err(&pdev->dev,
+					"%s: spm unavailable, rc=%d\n",
+					__func__, rc);
+			return rc;
+		}
+	}
+
+	vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
+	if (!vreg) {
+		pr_err("allocation failed.\n");
+		return -ENOMEM;
+	}
+	vreg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!vreg->regmap) {
+		dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+		return -EINVAL;
+	}
+	vreg->pdev = pdev;
+	vreg->bypass_spm = bypass_spm;
+
+	rc = of_property_read_u32(pdev->dev.of_node, "reg", &base);
+	if (rc < 0) {
+		dev_err(&pdev->dev,
+			"Couldn't find reg in node = %s rc = %d\n",
+			pdev->dev.of_node->full_name, rc);
+		return rc;
+	}
+	vreg->spmi_base_addr = base;
+
+	rc = qpnp_smps_check_type(vreg);
+	if (rc)
+		return rc;
+
+	/* Specify CPU 0 as default in order to handle shared regulator case. */
+	vreg->cpu_num = 0;
+	of_property_read_u32(vreg->pdev->dev.of_node, "qcom,cpu-num",
+						&vreg->cpu_num);
+
+	of_property_read_u32(vreg->pdev->dev.of_node, "qcom,recal-mask",
+						&vreg->recal_cluster_mask);
+
+	/*
+	 * The regulator must be initialized to range 0 or range 1 during
+	 * PMIC power on sequence.  Once it is set, it cannot be changed
+	 * dynamically.
+	 */
+	if (vreg->regulator_type == QPNP_TYPE_FTS2)
+		rc = qpnp_smps_init_range(vreg, &fts2_range0, &fts2_range1);
+	else if (vreg->regulator_type == QPNP_TYPE_FTS2p5)
+		rc = qpnp_smps_init_range(vreg, &fts2p5_range0, &fts2p5_range1);
+	else if (vreg->regulator_type == QPNP_TYPE_FTS426)
+		vreg->range = &fts426_range;
+	else if (vreg->regulator_type == QPNP_TYPE_HF)
+		rc = qpnp_smps_init_range(vreg, &hf_range0, &hf_range1);
+	else if (vreg->regulator_type == QPNP_TYPE_ULT_HF)
+		rc = qpnp_ult_hf_init_range(vreg);
+	if (rc)
+		return rc;
+
+	rc = qpnp_smps_init_voltage(vreg);
+	if (rc)
+		return rc;
+
+	rc = qpnp_smps_init_mode(vreg);
+	if (rc)
+		return rc;
+
+	rc = qpnp_smps_init_step_rate(vreg);
+	if (rc)
+		return rc;
+
+	init_data = of_get_regulator_init_data(&pdev->dev, node, &vreg->rdesc);
+	if (!init_data) {
+		dev_err(&pdev->dev, "%s: unable to allocate memory\n",
+				__func__);
+		return -ENOMEM;
+	}
+	init_data->constraints.input_uV = init_data->constraints.max_uV;
+	init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS
+			| REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE;
+	init_data->constraints.valid_modes_mask
+				= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+
+	if (!init_data->constraints.name) {
+		dev_err(&pdev->dev, "%s: node is missing regulator name\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	rc = qpnp_smps_check_constraints(vreg, init_data);
+	if (rc) {
+		dev_err(&pdev->dev, "%s: regulator constraints check failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	vreg->rdesc.name	= init_data->constraints.name;
+	vreg->rdesc.type	= REGULATOR_VOLTAGE;
+	vreg->rdesc.owner	= THIS_MODULE;
+	vreg->rdesc.ops		= &spm_regulator_ops;
+	vreg->rdesc.n_voltages
+		= (vreg->range->max_uV - vreg->range->set_point_min_uV)
+			/ vreg->range->step_uV + 1;
+
+	vreg->max_step_uV = SPM_REGULATOR_MAX_STEP_UV;
+	of_property_read_u32(vreg->pdev->dev.of_node,
+				"qcom,max-voltage-step", &vreg->max_step_uV);
+
+	if (vreg->max_step_uV > SPM_REGULATOR_MAX_STEP_UV)
+		vreg->max_step_uV = SPM_REGULATOR_MAX_STEP_UV;
+
+	vreg->max_step_uV = rounddown(vreg->max_step_uV, vreg->range->step_uV);
+	pr_debug("%s: max single voltage step size=%u uV\n",
+		vreg->rdesc.name, vreg->max_step_uV);
+
+	reg_config.dev = &pdev->dev;
+	reg_config.init_data = init_data;
+	reg_config.driver_data = vreg;
+	reg_config.of_node = node;
+	vreg->rdev = regulator_register(&vreg->rdesc, &reg_config);
+
+	if (IS_ERR(vreg->rdev)) {
+		rc = PTR_ERR(vreg->rdev);
+		dev_err(&pdev->dev, "%s: regulator_register failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	rc = spm_regulator_avs_register(vreg, &pdev->dev, node);
+	if (rc) {
+		regulator_unregister(vreg->rdev);
+		return rc;
+	}
+
+	dev_set_drvdata(&pdev->dev, vreg);
+
+	pr_info("name=%s, range=%s, voltage=%d uV, mode=%s, step rate=%d uV/us\n",
+		vreg->rdesc.name,
+		spm_regulator_using_range0(vreg) ? "LV" : "MV",
+		vreg->uV,
+		vreg->init_mode == QPNP_LOGICAL_MODE_PWM ? "PWM" :
+		   (vreg->init_mode == QPNP_LOGICAL_MODE_AUTO ? "AUTO" : "PFM"),
+		vreg->step_rate);
+
+	return rc;
+}
+
+static int spm_regulator_remove(struct platform_device *pdev)
+{
+	struct spm_vreg *vreg = dev_get_drvdata(&pdev->dev);
+
+	if (vreg->avs_rdev)
+		regulator_unregister(vreg->avs_rdev);
+	regulator_unregister(vreg->rdev);
+
+	return 0;
+}
+
+static struct of_device_id spm_regulator_match_table[] = {
+	{ .compatible = SPM_REGULATOR_DRIVER_NAME, },
+	{}
+};
+
+static const struct platform_device_id spm_regulator_id[] = {
+	{ SPM_REGULATOR_DRIVER_NAME, 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(spmi, spm_regulator_id);
+
+static struct platform_driver spm_regulator_driver = {
+	.driver = {
+		.name		= SPM_REGULATOR_DRIVER_NAME,
+		.of_match_table = spm_regulator_match_table,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= spm_regulator_probe,
+	.remove		= spm_regulator_remove,
+	.id_table	= spm_regulator_id,
+};
+
+/**
+ * spm_regulator_init() - register spmi driver for spm-regulator
+ *
+ * This initialization function should be called in systems in which driver
+ * registration ordering must be controlled precisely.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init spm_regulator_init(void)
+{
+	static bool has_registered;
+
+	if (has_registered)
+		return 0;
+	else
+		has_registered = true;
+
+	return platform_driver_register(&spm_regulator_driver);
+}
+EXPORT_SYMBOL(spm_regulator_init);
+
+static void __exit spm_regulator_exit(void)
+{
+	platform_driver_unregister(&spm_regulator_driver);
+}
+
+arch_initcall(spm_regulator_init);
+module_exit(spm_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SPM regulator driver");
+MODULE_ALIAS("platform:spm-regulator");
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 6f0c38d..e475041 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -2156,6 +2156,12 @@
 	if (!priv->ops || !priv->ops->reinit)
 		goto out;
 
+	if (test_bit(ICNSS_FW_DOWN, &priv->state)) {
+		icnss_pr_err("FW is in bad state, state: 0x%lx\n",
+			     priv->state);
+		goto out;
+	}
+
 	if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
 		goto call_probe;
 
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 9d22925..e0df954 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -511,11 +511,12 @@
 }
 
 static int pil_alloc_region(struct pil_priv *priv, phys_addr_t min_addr,
-				phys_addr_t max_addr, size_t align)
+				phys_addr_t max_addr, size_t align,
+				size_t mdt_size)
 {
 	void *region;
 	size_t size = max_addr - min_addr;
-	size_t aligned_size;
+	size_t aligned_size = max(size, mdt_size);
 
 	/* Don't reallocate due to fragmentation concerns, just sanity check */
 	if (priv->region) {
@@ -526,9 +527,11 @@
 	}
 
 	if (align > SZ_4M)
-		aligned_size = ALIGN(size, SZ_4M);
+		aligned_size = ALIGN(aligned_size, SZ_4M);
+	else if (align > SZ_1M)
+		aligned_size = ALIGN(aligned_size, SZ_1M);
 	else
-		aligned_size = ALIGN(size, SZ_1M);
+		aligned_size = ALIGN(aligned_size, SZ_4K);
 
 	priv->desc->attrs = 0;
 	priv->desc->attrs |= DMA_ATTR_SKIP_ZEROING | DMA_ATTR_NO_KERNEL_MAPPING;
@@ -553,7 +556,8 @@
 	return 0;
 }
 
-static int pil_setup_region(struct pil_priv *priv, const struct pil_mdt *mdt)
+static int pil_setup_region(struct pil_priv *priv, const struct pil_mdt *mdt,
+				size_t mdt_size)
 {
 	const struct elf32_phdr *phdr;
 	phys_addr_t min_addr_r, min_addr_n, max_addr_r, max_addr_n, start, end;
@@ -598,7 +602,8 @@
 	max_addr_r = ALIGN(max_addr_r, SZ_4K);
 
 	if (relocatable) {
-		ret = pil_alloc_region(priv, min_addr_r, max_addr_r, align);
+		ret = pil_alloc_region(priv, min_addr_r, max_addr_r, align,
+					mdt_size);
 	} else {
 		priv->region_start = min_addr_n;
 		priv->region_end = max_addr_n;
@@ -629,14 +634,15 @@
 	return ret;
 }
 
-static int pil_init_mmap(struct pil_desc *desc, const struct pil_mdt *mdt)
+static int pil_init_mmap(struct pil_desc *desc, const struct pil_mdt *mdt,
+			size_t mdt_size)
 {
 	struct pil_priv *priv = desc->priv;
 	const struct elf32_phdr *phdr;
 	struct pil_seg *seg;
 	int i, ret;
 
-	ret = pil_setup_region(priv, mdt);
+	ret = pil_setup_region(priv, mdt, mdt_size);
 	if (ret)
 		return ret;
 
@@ -922,7 +928,7 @@
 		goto release_fw;
 	}
 
-	ret = pil_init_mmap(desc, mdt);
+	ret = pil_init_mmap(desc, mdt, fw->size);
 	if (ret)
 		goto release_fw;
 
@@ -935,7 +941,8 @@
 
 	trace_pil_event("before_init_image", desc);
 	if (desc->ops->init_image)
-		ret = desc->ops->init_image(desc, fw->data, fw->size);
+		ret = desc->ops->init_image(desc, fw->data, fw->size,
+				priv->region_start, priv->region);
 	if (ret) {
 		pil_err(desc, "Initializing image failed(rc:%d)\n", ret);
 		goto err_boot;
diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h
index f09adf5..27ed336 100644
--- a/drivers/soc/qcom/peripheral-loader.h
+++ b/drivers/soc/qcom/peripheral-loader.h
@@ -119,7 +119,7 @@
  */
 struct pil_reset_ops {
 	int (*init_image)(struct pil_desc *pil, const u8 *metadata,
-			  size_t size);
+			  size_t size, phys_addr_t mdata_phys, void *region);
 	int (*mem_setup)(struct pil_desc *pil, phys_addr_t addr, size_t size);
 	int (*verify_blob)(struct pil_desc *pil, phys_addr_t phy_addr,
 			   size_t size);
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index a3eb551..ce31d66 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -769,7 +769,8 @@
 }
 
 static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
-					size_t size)
+					size_t size, phys_addr_t region_start,
+					void *region)
 {
 	struct modem_data *drv = dev_get_drvdata(pil->dev);
 	void *mdata_virt;
@@ -851,7 +852,8 @@
 }
 
 static int pil_msa_mss_reset_mba_load_auth_mdt(struct pil_desc *pil,
-				  const u8 *metadata, size_t size)
+				const u8 *metadata, size_t size,
+				phys_addr_t region_start, void *region)
 {
 	int ret;
 
@@ -859,7 +861,8 @@
 	if (ret)
 		return ret;
 
-	return pil_msa_auth_modem_mdt(pil, metadata, size);
+	return pil_msa_auth_modem_mdt(pil, metadata, size, region_start,
+								region);
 }
 
 static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index 2ca0615..728a68c 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -60,9 +60,6 @@
 
 	strlcpy(reason, smem_reason, min(size, MAX_SSR_REASON_LEN));
 	pr_err("modem subsystem failure reason: %s.\n", reason);
-
-	smem_reason[0] = '\0';
-	wmb();
 }
 
 static void restart_modem(struct modem_data *drv)
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index 86f314a..b7472a4 100644
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -471,7 +471,7 @@
 	case QBT1000_SEND_TZCMD:
 	{
 		struct qbt1000_send_tz_cmd tzcmd;
-		void *rsp_buf;
+		void *rsp_buf = NULL;
 
 		if (copy_from_user(&tzcmd, priv_arg,
 			sizeof(tzcmd))
@@ -861,8 +861,8 @@
 static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
 {
 	uint8_t *msg_buffer;
-	struct fw_ipc_cmd *rx_cmd;
-	struct fw_ipc_header *header;
+	struct fw_ipc_cmd *rx_cmd = NULL;
+	struct fw_ipc_header *header = NULL;
 	int i, j;
 	uint32_t rxipc = FP_APP_CMD_RX_IPC;
 	struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id;
diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index f4c67f1..dc45b20 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -105,6 +105,7 @@
 	struct work_struct ind_ack;
 	struct work_struct qmi_handle_free;
 	struct workqueue_struct *svc_event_wq;
+	struct rw_semaphore qmi_client_handle_rwlock;
 	struct qmi_handle *clnt_handle;
 	struct notifier_block notifier;
 	void *ssr_handle;
@@ -115,7 +116,6 @@
 };
 static LIST_HEAD(qmi_client_list);
 static DEFINE_MUTEX(qmi_list_lock);
-static DEFINE_MUTEX(qmi_client_release_lock);
 
 static DEFINE_MUTEX(notif_add_lock);
 
@@ -128,11 +128,11 @@
 	struct qmi_client_info *data = container_of(work,
 				struct qmi_client_info, qmi_handle_free);
 
-	mutex_lock(&qmi_client_release_lock);
+	down_write(&data->qmi_client_handle_rwlock);
 	data->service_connected = false;
 	qmi_handle_destroy(data->clnt_handle);
 	data->clnt_handle = NULL;
-	mutex_unlock(&qmi_client_release_lock);
+	up_write(&data->qmi_client_handle_rwlock);
 }
 
 static struct service_notif_info *_find_service_info(const char *service_path)
@@ -170,10 +170,12 @@
 	struct qmi_client_info *data = container_of(work,
 					struct qmi_client_info, svc_rcv_msg);
 
+	down_read(&data->qmi_client_handle_rwlock);
 	do {
 		pr_debug("Polling for QMI recv msg(instance-id: %d)\n",
 							data->instance_id);
 	} while ((ret = qmi_recv_msg(data->clnt_handle)) == 0);
+	up_read(&data->qmi_client_handle_rwlock);
 
 	pr_debug("Notified about a Receive event (instance-id: %d)\n",
 							data->instance_id);
@@ -237,9 +239,11 @@
 	resp_desc.max_msg_len = SERVREG_NOTIF_SET_ACK_RESP_MSG_LEN;
 	resp_desc.ei_array = qmi_servreg_notif_set_ack_resp_msg_v01_ei;
 
+	down_read(&data->qmi_client_handle_rwlock);
 	rc = qmi_send_req_wait(data->clnt_handle, &req_desc,
 				&req, sizeof(req), &resp_desc, &resp,
 				sizeof(resp), SERVER_TIMEOUT);
+	up_read(&data->qmi_client_handle_rwlock);
 	if (rc < 0) {
 		pr_err("%s: Sending Ack failed/server timeout, ret - %d\n",
 						data->ind_msg.service_path, rc);
@@ -308,9 +312,11 @@
 	resp_desc.ei_array =
 			qmi_servreg_notif_register_listener_resp_msg_v01_ei;
 
+	down_read(&data->qmi_client_handle_rwlock);
 	rc = qmi_send_req_wait(data->clnt_handle, &req_desc, &req, sizeof(req),
 				&resp_desc, &resp, sizeof(resp),
 				SERVER_TIMEOUT);
+	up_read(&data->qmi_client_handle_rwlock);
 	if (rc < 0) {
 		pr_err("%s: Message sending failed/server timeout, ret - %d\n",
 					service_notif->service_path, rc);
@@ -349,13 +355,13 @@
 	int rc;
 	int curr_state;
 
-	mutex_lock(&qmi_client_release_lock);
+	down_read(&data->qmi_client_handle_rwlock);
 	/* Create a Local client port for QMI communication */
 	data->clnt_handle = qmi_handle_create(root_service_clnt_notify, work);
 	if (!data->clnt_handle) {
 		pr_err("QMI client handle alloc failed (instance-id: %d)\n",
 							data->instance_id);
-		mutex_unlock(&qmi_client_release_lock);
+		up_read(&data->qmi_client_handle_rwlock);
 		return;
 	}
 
@@ -368,11 +374,11 @@
 							data->instance_id, rc);
 		qmi_handle_destroy(data->clnt_handle);
 		data->clnt_handle = NULL;
-		mutex_unlock(&qmi_client_release_lock);
+		up_read(&data->qmi_client_handle_rwlock);
 		return;
 	}
 	data->service_connected = true;
-	mutex_unlock(&qmi_client_release_lock);
+	up_read(&data->qmi_client_handle_rwlock);
 	pr_info("Connection established between QMI handle and %d service\n",
 							data->instance_id);
 	/* Register for indication messages about service */
@@ -554,6 +560,7 @@
 	}
 
 	qmi_data->instance_id = instance_id;
+	init_rwsem(&qmi_data->qmi_client_handle_rwlock);
 	qmi_data->clnt_handle = NULL;
 	qmi_data->notifier.notifier_call = service_event_notify;
 
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index 5b600f6..d3819b6 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -47,6 +47,13 @@
 #define desc_to_data(d) container_of(d, struct pil_tz_data, desc)
 #define subsys_to_data(d) container_of(d, struct pil_tz_data, subsys_desc)
 
+struct pil_map_fw_info {
+	void *region;
+	unsigned long attrs;
+	phys_addr_t base_addr;
+	struct device *dev;
+};
+
 /**
  * struct reg_info - regulator info
  * @reg: regulator handle
@@ -586,7 +593,8 @@
 }
 
 static int pil_init_image_trusted(struct pil_desc *pil,
-		const u8 *metadata, size_t size)
+		const u8 *metadata, size_t size, phys_addr_t mdata_phys,
+		void *region)
 {
 	struct pil_tz_data *d = desc_to_data(pil);
 	struct pas_init_image_req {
@@ -595,11 +603,15 @@
 	} request;
 	u32 scm_ret = 0;
 	void *mdata_buf;
-	dma_addr_t mdata_phys;
 	int ret;
-	unsigned long attrs = 0;
-	struct device dev = {0};
 	struct scm_desc desc = {0};
+	struct pil_map_fw_info map_fw_info = {
+		.attrs = pil->attrs,
+		.region = region,
+		.base_addr = mdata_phys,
+		.dev = pil->dev,
+	};
+	void *map_data = pil->map_data ? pil->map_data : &map_fw_info;
 
 	if (d->subsys_desc.no_auth)
 		return 0;
@@ -607,15 +619,10 @@
 	ret = scm_pas_enable_bw();
 	if (ret)
 		return ret;
-	arch_setup_dma_ops(&dev, 0, 0, NULL, 0);
 
-	dev.coherent_dma_mask =
-		DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
-	attrs |= DMA_ATTR_STRONGLY_ORDERED;
-	mdata_buf = dma_alloc_attrs(&dev, size, &mdata_phys, GFP_KERNEL,
-					attrs);
+	mdata_buf = pil->map_fw_mem(mdata_phys, size, map_data);
 	if (!mdata_buf) {
-		pr_err("scm-pas: Allocation for metadata failed.\n");
+		dev_err(pil->dev, "Failed to map memory for metadata.\n");
 		scm_pas_disable_bw();
 		return -ENOMEM;
 	}
@@ -637,7 +644,7 @@
 		scm_ret = desc.ret[0];
 	}
 
-	dma_free_attrs(&dev, size, mdata_buf, mdata_phys, attrs);
+	pil->unmap_fw_mem(mdata_buf, size, map_data);
 	scm_pas_disable_bw();
 	if (ret)
 		return ret;
@@ -857,9 +864,6 @@
 
 	strlcpy(reason, smem_reason, min(size, MAX_SSR_REASON_LEN));
 	pr_err("%s subsystem failure reason: %s.\n", name, reason);
-
-	smem_reason[0] = '\0';
-	wmb();
 }
 
 static int subsys_shutdown(const struct subsys_desc *subsys, bool force_stop)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 7aaf08b..186e7ae 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -230,8 +230,8 @@
 	u32 cpha = geni_read_reg(mas->base, SE_SPI_CPHA);
 	u32 demux_sel = 0;
 	u32 demux_output_inv = 0;
-	u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
-	u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
+	u32 clk_sel = 0;
+	u32 m_clk_cfg = 0;
 	int ret = 0;
 	int idx;
 	int div;
@@ -884,8 +884,8 @@
 	/* Speed and bits per word can be overridden per transfer */
 	if (xfer->speed_hz != mas->cur_speed_hz) {
 		int ret = 0;
-		u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
-		u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
+		u32 clk_sel = 0;
+		u32 m_clk_cfg = 0;
 		int idx = 0;
 		int div = 0;
 
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 89c1681..67a71ba 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -493,6 +493,7 @@
 			} else {
 				pm_runtime_get_noresume(uport->dev);
 				pm_runtime_set_active(uport->dev);
+				enable_irq(uport->irq);
 			}
 			pm_runtime_enable(uport->dev);
 			if (lock)
@@ -2576,7 +2577,8 @@
 						SE_UART_MANUAL_RFR);
 	/* Ensure that the Rx is running before enabling interrupts */
 	mb();
-	enable_irq(port->uport.irq);
+	if (pm_runtime_enabled(dev))
+		enable_irq(port->uport.irq);
 	IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
 exit_runtime_resume:
 	return ret;
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a5e050a..64ed834 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1243,7 +1243,7 @@
 	dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI);
 	if (!dwc->dwc_wq) {
 		pr_err("%s: Unable to create workqueue dwc_wq\n", __func__);
-		return -ENOMEM;
+		goto err0;
 	}
 
 	INIT_WORK(&dwc->bh_work, dwc3_bh_work);
@@ -1290,7 +1290,7 @@
 
 	ret = dwc3_core_init_mode(dwc);
 	if (ret)
-		goto err0;
+		goto err1;
 
 	ret = dwc3_debugfs_init(dwc);
 	if (ret) {
@@ -1312,6 +1312,8 @@
 
 err_core_init:
 	dwc3_core_exit_mode(dwc);
+err1:
+	destroy_workqueue(dwc->dwc_wq);
 err0:
 	/*
 	 * restore res->start back to its original value so that, in case the
@@ -1319,7 +1321,6 @@
 	 * memory region the next time probe is called.
 	 */
 	res->start -= DWC3_GLOBALS_REGS_START;
-	destroy_workqueue(dwc->dwc_wq);
 
 	return ret;
 }
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5571374..51504b0 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -989,7 +989,7 @@
 			 */
 			if (speed == USB_SPEED_HIGH) {
 				struct usb_ep *ep = &dep->endpoint;
-				unsigned int mult = ep->mult - 1;
+				unsigned int mult = 2;
 				unsigned int maxp;
 
 				maxp = usb_endpoint_maxp(ep->desc) & 0x07ff;
@@ -1058,6 +1058,9 @@
 {
 	u8 tmp = index;
 
+	if (!dep->trb_pool)
+		return NULL;
+
 	if (!tmp)
 		tmp = DWC3_TRB_NUM - 1;
 
@@ -1163,7 +1166,7 @@
 static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
 {
 	struct dwc3_gadget_ep_cmd_params params;
-	struct dwc3_request		*req;
+	struct dwc3_request		*req, *req1, *n;
 	struct dwc3			*dwc = dep->dwc;
 	int				starting;
 	int				ret;
@@ -1193,6 +1196,30 @@
 
 	ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
 	if (ret < 0) {
+		if ((ret == -EAGAIN) && starting &&
+				usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+			/* If bit13 in Command complete event is set, software
+			 * must issue ENDTRANDFER command and wait for
+			 * Xfernotready event to queue the requests again.
+			 */
+			if (!dep->resource_index) {
+				dep->resource_index =
+					 dwc3_gadget_ep_get_transfer_index(dep);
+				WARN_ON_ONCE(!dep->resource_index);
+			}
+			dwc3_stop_active_transfer(dwc, dep->number, true);
+
+			list_for_each_entry_safe_reverse(req1, n,
+						&dep->started_list, list) {
+				req1->trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+				req1->trb = NULL;
+				dwc3_gadget_move_pending_list_front(req1);
+				dwc3_ep_inc_deq(dep);
+			}
+
+			return ret;
+		}
+
 		/*
 		 * FIXME we need to iterate over the list of requests
 		 * here and stop, unmap, free and del each of the linked
@@ -1240,7 +1267,7 @@
 	 * Schedule the first trb for one interval in the future or at
 	 * least 4 microframes.
 	 */
-	uf = cur_uf + max_t(u32, 4, dep->interval);
+	uf = cur_uf + max_t(u32, 16, dep->interval);
 
 	ret = __dwc3_gadget_kick_transfer(dep, uf);
 	if (ret < 0)
@@ -1570,7 +1597,11 @@
 		else
 			trb = &dwc->ep0_trb[dep->trb_enqueue];
 
-		transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO;
+		if (trb)
+			transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO;
+		else
+			transfer_in_flight = false;
+
 		started = !list_empty(&dep->started_list);
 
 		if (!protocol && ((dep->direction && transfer_in_flight) ||
@@ -2638,6 +2669,9 @@
 		unsigned actual;
 		int chain;
 
+		if (req->trb->ctrl & DWC3_TRB_CTRL_HWO)
+			return 0;
+
 		length = req->request.length;
 		chain = req->num_pending_sgs > 0;
 		if (chain) {
@@ -2696,18 +2730,17 @@
 
 	if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
 			list_empty(&dep->started_list)) {
-		if (list_empty(&dep->pending_list)) {
+		if (list_empty(&dep->pending_list))
 			/*
 			 * If there is no entry in request list then do
 			 * not issue END TRANSFER now. Just set PENDING
 			 * flag, so that END TRANSFER is issued when an
 			 * entry is added into request list.
 			 */
-			dep->flags = DWC3_EP_PENDING_REQUEST;
-		} else {
+			dep->flags |= DWC3_EP_PENDING_REQUEST;
+		else
 			dwc3_stop_active_transfer(dwc, dep->number, true);
-			dep->flags = DWC3_EP_ENABLED;
-		}
+		dep->flags &= ~DWC3_EP_MISSED_ISOC;
 		return 1;
 	}
 
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 8d0a5eb..25d8d8f 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -68,6 +68,14 @@
 	return list_first_entry(list, struct dwc3_request, list);
 }
 
+static inline void dwc3_gadget_move_pending_list_front(struct dwc3_request *req)
+{
+	struct dwc3_ep		*dep = req->dep;
+
+	req->started = false;
+	list_move(&req->list, &dep->pending_list);
+}
+
 static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
 {
 	struct dwc3_ep		*dep = req->dep;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 31b2731..4aee8c8 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -35,6 +35,12 @@
 	(speed == USB_SPEED_SUPER ?\
 	 SSUSB_GADGET_VBUS_DRAW : CONFIG_USB_GADGET_VBUS_DRAW)
 
+/* disable LPM by default */
+static bool disable_l1_for_hs = true;
+module_param(disable_l1_for_hs, bool, 0644);
+MODULE_PARM_DESC(disable_l1_for_hs,
+	"Disable support for L1 LPM for HS devices");
+
 /**
  * struct usb_os_string - represents OS String to be reported by a gadget
  * @bLength: total length of the entire descritor, always 0x12
@@ -357,8 +363,11 @@
 
 	spin_lock_irqsave(&cdev->lock, flags);
 
-	if (cdev->deactivations == 0)
+	if (cdev->deactivations == 0) {
+		spin_unlock_irqrestore(&cdev->lock, flags);
 		status = usb_gadget_deactivate(cdev->gadget);
+		spin_lock_irqsave(&cdev->lock, flags);
+	}
 	if (status == 0)
 		cdev->deactivations++;
 
@@ -389,8 +398,11 @@
 		status = -EINVAL;
 	else {
 		cdev->deactivations--;
-		if (cdev->deactivations == 0)
+		if (cdev->deactivations == 0) {
+			spin_unlock_irqrestore(&cdev->lock, flags);
 			status = usb_gadget_activate(cdev->gadget);
+			spin_lock_irqsave(&cdev->lock, flags);
+		}
 	}
 
 	spin_unlock_irqrestore(&cdev->lock, flags);
@@ -1718,10 +1730,10 @@
 				if (gadget->speed >= USB_SPEED_SUPER) {
 					cdev->desc.bcdUSB = cpu_to_le16(0x0310);
 					cdev->desc.bMaxPacketSize0 = 9;
-				} else {
+				} else if (!disable_l1_for_hs) {
 					cdev->desc.bcdUSB = cpu_to_le16(0x0210);
 				}
-			} else if (gadget->l1_supported) {
+			} else if (!disable_l1_for_hs) {
 				cdev->desc.bcdUSB = cpu_to_le16(0x0210);
 				DBG(cdev, "Config HS device with LPM(L1)\n");
 			}
@@ -1755,7 +1767,7 @@
 			break;
 		case USB_DT_BOS:
 			if (gadget_is_superspeed(gadget) ||
-				gadget->l1_supported) {
+				!disable_l1_for_hs) {
 				value = bos_desc(cdev);
 				value = min(w_length, (u16) value);
 			}
diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c
index 4cb2817..0e86d28 100644
--- a/drivers/usb/gadget/function/f_cdev.c
+++ b/drivers/usb/gadget/function/f_cdev.c
@@ -48,7 +48,7 @@
 
 #define DEVICE_NAME "at_usb"
 #define MODULE_NAME "msm_usb_bridge"
-#define NUM_INSTANCE 2
+#define NUM_INSTANCE 3
 
 #define MAX_CDEV_INST_NAME	15
 #define MAX_CDEV_FUNC_NAME	5
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index bdd0dfa..295f681 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -572,7 +572,7 @@
 static struct usb_endpoint_descriptor rndis_gsi_fs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
-
+	.wMaxPacketSize =	cpu_to_le16(64),
 	.bEndpointAddress =	USB_DIR_IN,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
@@ -580,7 +580,7 @@
 static struct usb_endpoint_descriptor rndis_gsi_fs_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
-
+	.wMaxPacketSize =	cpu_to_le16(64),
 	.bEndpointAddress =	USB_DIR_OUT,
 	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 };
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index aea32e4..239d9bf 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -1464,6 +1464,7 @@
 		mtp_ss_out_comp_desc.bMaxBurst = max_burst;
 	}
 
+	fi_mtp->func_inst.f = &dev->function;
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 		gadget_is_superspeed(c->cdev->gadget) ? "super" :
 		(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full"),
@@ -1475,9 +1476,10 @@
 mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct mtp_dev	*dev = func_to_mtp(f);
+	struct mtp_instance *fi_mtp;
 	struct usb_request *req;
 	int i;
-
+	fi_mtp = container_of(f->fi, struct mtp_instance, func_inst);
 	mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
 	mutex_lock(&dev->read_mutex);
 	while ((req = mtp_req_get(dev, &dev->tx_idle)))
@@ -1490,6 +1492,7 @@
 	dev->state = STATE_OFFLINE;
 	kfree(f->os_desc_table);
 	f->os_desc_n = 0;
+	fi_mtp->func_inst.f = NULL;
 }
 
 static int mtp_function_set_alt(struct usb_function *f,
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 5434902..643e087 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -23,6 +23,7 @@
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
+#include <linux/usb/phy.h>
 
 #include "xhci.h"
 #include "xhci-trace.h"
@@ -1065,6 +1066,7 @@
 	u16 wake_mask = 0;
 	u16 timeout = 0;
 	u16 test_mode = 0;
+	enum usb_device_speed s = hcd->self.root_hub->speed;
 
 	max_ports = xhci_get_ports(hcd, &port_array);
 	bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -1314,6 +1316,10 @@
 			writel(temp, port_array[wIndex]);
 
 			temp = readl(port_array[wIndex]);
+
+			if (s == USB_SPEED_HIGH)
+				usb_phy_start_port_reset(hcd->usb_phy);
+
 			xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);
 			break;
 		case USB_PORT_FEAT_REMOTE_WAKE_MASK:
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 44ab6d6..0091f41 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -477,6 +477,21 @@
 }
 EXPORT_SYMBOL(usbpd_get_plug_orientation);
 
+static unsigned int get_connector_type(struct usbpd *pd)
+{
+	int ret;
+	union power_supply_propval val;
+
+	ret = power_supply_get_property(pd->usb_psy,
+		POWER_SUPPLY_PROP_CONNECTOR_TYPE, &val);
+
+	if (ret) {
+		dev_err(&pd->dev, "Unable to read CONNECTOR TYPE: %d\n", ret);
+		return ret;
+	}
+	return val.intval;
+}
+
 static inline void stop_usb_host(struct usbpd *pd)
 {
 	extcon_set_state_sync(pd->extcon, EXTCON_USB_HOST, 0);
@@ -894,7 +909,7 @@
 		/* allocate new message if first chunk */
 		rx_msg = kzalloc(sizeof(*rx_msg) +
 				PD_MSG_EXT_HDR_DATA_SIZE(ext_hdr),
-				GFP_KERNEL);
+				GFP_ATOMIC);
 		if (!rx_msg)
 			return NULL;
 
@@ -947,7 +962,7 @@
 
 		pd->rx_ext_msg = rx_msg;
 
-		req = kzalloc(sizeof(*req), GFP_KERNEL);
+		req = kzalloc(sizeof(*req), GFP_ATOMIC);
 		if (!req)
 			goto queue_rx; /* return what we have anyway */
 
@@ -1021,7 +1036,7 @@
 			PD_MSG_HDR_TYPE(header), PD_MSG_HDR_COUNT(header));
 
 	if (!PD_MSG_HDR_IS_EXTENDED(header)) {
-		rx_msg = kzalloc(sizeof(*rx_msg) + len, GFP_KERNEL);
+		rx_msg = kzalloc(sizeof(*rx_msg) + len, GFP_ATOMIC);
 		if (!rx_msg)
 			return;
 
@@ -3906,6 +3921,11 @@
 		goto destroy_wq;
 	}
 
+	if (get_connector_type(pd) == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
+		usbpd_dbg(&pd->dev, "USB connector is microAB hence failing pdphy_probe\n");
+		ret = -EINVAL;
+		goto put_psy;
+	}
 	/*
 	 * associate extcon with the parent dev as it could have a DT
 	 * node which will be useful for extcon_get_edev_by_phandle()
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 8a4f3d4..2997976 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -675,7 +675,7 @@
 			BIST_MODE_MASK | BIST_ENABLE, bist_mode | BIST_ENABLE);
 }
 
-static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
+static irqreturn_t pdphy_msg_rx_irq(int irq, void *data)
 {
 	u8 size, rx_status, frame_type;
 	u8 buf[32];
@@ -816,8 +816,8 @@
 		return ret;
 
 	ret = pdphy_request_irq(pdphy, pdev->dev.of_node,
-		&pdphy->msg_rx_irq, "msg-rx", NULL,
-		pdphy_msg_rx_irq_thread, (IRQF_TRIGGER_RISING | IRQF_ONESHOT));
+		&pdphy->msg_rx_irq, "msg-rx", pdphy_msg_rx_irq,
+		NULL, (IRQF_TRIGGER_RISING | IRQF_ONESHOT));
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 81c39a3..cce17e0 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -27,6 +27,7 @@
 #include <linux/usb/phy.h>
 #include <linux/reset.h>
 #include <linux/debugfs.h>
+#include <linux/hrtimer.h>
 
 /* QUSB2PHY_PWR_CTRL1 register related bits */
 #define PWR_CTRL1_POWR_DOWN		BIT(0)
@@ -126,6 +127,10 @@
 	u32			sq_ctrl2_default;
 	bool			chirp_disable;
 
+	struct pinctrl		*pinctrl;
+	struct pinctrl_state	*atest_usb13_suspend;
+	struct pinctrl_state	*atest_usb13_active;
+
 	/* emulation targets specific */
 	void __iomem		*emu_phy_base;
 	bool			emulation;
@@ -139,6 +144,8 @@
 	/* override TUNEX registers value */
 	struct dentry		*root;
 	u8			tune[5];
+
+	struct hrtimer		timer;
 };
 
 static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
@@ -511,6 +518,42 @@
 	return 0;
 }
 
+static enum hrtimer_restart qusb_dis_ext_pulldown_timer(struct hrtimer *timer)
+{
+	struct qusb_phy *qphy = container_of(timer, struct qusb_phy, timer);
+	int ret = 0;
+
+	if (qphy->pinctrl && qphy->atest_usb13_suspend) {
+		ret = pinctrl_select_state(qphy->pinctrl,
+				qphy->atest_usb13_suspend);
+		if (ret < 0)
+			dev_err(qphy->phy.dev,
+				"pinctrl state suspend select failed\n");
+	}
+
+	return HRTIMER_NORESTART;
+}
+
+static void qusb_phy_enable_ext_pulldown(struct usb_phy *phy)
+{
+	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+	int ret = 0;
+
+	dev_dbg(phy->dev, "%s\n", __func__);
+
+	if (qphy->pinctrl && qphy->atest_usb13_active) {
+		ret = pinctrl_select_state(qphy->pinctrl,
+				qphy->atest_usb13_active);
+		if (ret < 0) {
+			dev_err(phy->dev,
+					"pinctrl state active select failed\n");
+			return;
+		}
+
+		hrtimer_start(&qphy->timer, ms_to_ktime(10), HRTIMER_MODE_REL);
+	}
+}
+
 static void qusb_phy_shutdown(struct usb_phy *phy)
 {
 	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
@@ -1082,6 +1125,30 @@
 		return PTR_ERR(qphy->vdda18);
 	}
 
+	qphy->pinctrl = devm_pinctrl_get(dev);
+	if (IS_ERR(qphy->pinctrl)) {
+		ret = PTR_ERR(qphy->pinctrl);
+		if (ret == -EPROBE_DEFER)
+			return ret;
+		dev_err(dev, "pinctrl not available\n");
+		goto skip_pinctrl_config;
+	}
+	qphy->atest_usb13_suspend = pinctrl_lookup_state(qphy->pinctrl,
+							"atest_usb13_suspend");
+	if (IS_ERR(qphy->atest_usb13_suspend)) {
+		dev_err(dev, "pinctrl lookup atest_usb13_suspend failed\n");
+		goto skip_pinctrl_config;
+	}
+
+	qphy->atest_usb13_active = pinctrl_lookup_state(qphy->pinctrl,
+							"atest_usb13_active");
+	if (IS_ERR(qphy->atest_usb13_active))
+		dev_err(dev, "pinctrl lookup atest_usb13_active failed\n");
+
+	hrtimer_init(&qphy->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	qphy->timer.function = qusb_dis_ext_pulldown_timer;
+
+skip_pinctrl_config:
 	mutex_init(&qphy->lock);
 	platform_set_drvdata(pdev, qphy);
 
@@ -1093,6 +1160,7 @@
 	qphy->phy.notify_connect        = qusb_phy_notify_connect;
 	qphy->phy.notify_disconnect     = qusb_phy_notify_disconnect;
 	qphy->phy.disable_chirp		= qusb_phy_disable_chirp;
+	qphy->phy.start_port_reset	= qusb_phy_enable_ext_pulldown;
 
 	ret = usb_add_phy_dev(&qphy->phy);
 	if (ret)
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
index 2d18faf..fd84889 100644
--- a/drivers/usb/phy/phy-msm-snps-hs.c
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -74,7 +74,7 @@
 #define USB_HSPHY_3P3_HPM_LOAD			16000	/* uA */
 #define USB_HSPHY_3P3_VOL_FSHOST		3150000 /* uV */
 
-#define USB_HSPHY_1P8_VOL_MIN			1800000 /* uV */
+#define USB_HSPHY_1P8_VOL_MIN			1704000 /* uV */
 #define USB_HSPHY_1P8_VOL_MAX			1800000 /* uV */
 #define USB_HSPHY_1P8_HPM_LOAD			19000	/* uA */
 
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 7d4b557..6cb3a8c 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -276,11 +276,11 @@
 	goto loop;
 
 end_loop:
-	write_unlock(&journal->j_state_lock);
 	del_timer_sync(&journal->j_commit_timer);
 	journal->j_task = NULL;
 	wake_up(&journal->j_wait_done_commit);
 	jbd_debug(1, "Journal thread exiting.\n");
+	write_unlock(&journal->j_state_lock);
 	return 0;
 }
 
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 4a971e2..8ed0ea1 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -600,7 +600,7 @@
 
 static int sdcardfs_permission_wrn(struct inode *inode, int mask)
 {
-	WARN_RATELIMIT(1, "sdcardfs does not support permission. Use permission2.\n");
+	pr_debug("sdcardfs does not support permission. Use permission2.\n");
 	return -EINVAL;
 }
 
diff --git a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
index 950811f..7e1394c 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
@@ -65,43 +65,44 @@
 #define GCC_MSS_CFG_AHB_CLK					47
 #define GCC_MSS_GPLL0_DIV_CLK_SRC				48
 #define GCC_MSS_SNOC_AXI_CLK					49
-#define GCC_PCIE_AUX_CLK					50
-#define GCC_PCIE_AUX_PHY_CLK_SRC				51
-#define GCC_PCIE_CFG_AHB_CLK					52
-#define GCC_PCIE_MSTR_AXI_CLK					53
-#define GCC_PCIE_PHY_REFGEN_CLK					54
-#define GCC_PCIE_PHY_REFGEN_CLK_SRC				55
-#define GCC_PCIE_PIPE_CLK					56
-#define GCC_PCIE_SLEEP_CLK					57
-#define GCC_PCIE_SLV_AXI_CLK					58
-#define GCC_PCIE_SLV_Q2A_AXI_CLK				59
-#define GCC_PDM2_CLK						60
-#define GCC_PDM2_CLK_SRC					61
-#define GCC_PDM_AHB_CLK						62
-#define GCC_PDM_XO4_CLK						63
-#define GCC_PRNG_AHB_CLK					64
-#define GCC_SDCC1_AHB_CLK					65
-#define GCC_SDCC1_APPS_CLK					66
-#define GCC_SDCC1_APPS_CLK_SRC					67
-#define GCC_SPMI_FETCHER_AHB_CLK				68
-#define GCC_SPMI_FETCHER_CLK					69
-#define GCC_SPMI_FETCHER_CLK_SRC				70
-#define GCC_SYS_NOC_CPUSS_AHB_CLK				71
-#define GCC_SYS_NOC_USB3_CLK					72
-#define GCC_USB30_MASTER_CLK					73
-#define GCC_USB30_MASTER_CLK_SRC				74
-#define GCC_USB30_MOCK_UTMI_CLK					75
-#define GCC_USB30_MOCK_UTMI_CLK_SRC				76
-#define GCC_USB30_SLEEP_CLK					77
-#define GCC_USB3_PHY_AUX_CLK					78
-#define GCC_USB3_PHY_AUX_CLK_SRC				79
-#define GCC_USB3_PHY_PIPE_CLK					80
-#define GCC_USB_PHY_CFG_AHB2PHY_CLK				81
-#define GPLL0							82
-#define GPLL0_OUT_EVEN						83
-#define GPLL4							84
-#define GPLL4_OUT_EVEN						85
-#define GCC_USB3_PRIM_CLKREF_CLK				86
+#define GCC_PCIE_0_CLKREF_CLK					50
+#define GCC_PCIE_AUX_CLK					51
+#define GCC_PCIE_AUX_PHY_CLK_SRC				52
+#define GCC_PCIE_CFG_AHB_CLK					53
+#define GCC_PCIE_MSTR_AXI_CLK					54
+#define GCC_PCIE_PHY_REFGEN_CLK					55
+#define GCC_PCIE_PHY_REFGEN_CLK_SRC				56
+#define GCC_PCIE_PIPE_CLK					57
+#define GCC_PCIE_SLEEP_CLK					58
+#define GCC_PCIE_SLV_AXI_CLK					59
+#define GCC_PCIE_SLV_Q2A_AXI_CLK				60
+#define GCC_PDM2_CLK						61
+#define GCC_PDM2_CLK_SRC					62
+#define GCC_PDM_AHB_CLK						63
+#define GCC_PDM_XO4_CLK						64
+#define GCC_PRNG_AHB_CLK					65
+#define GCC_SDCC1_AHB_CLK					66
+#define GCC_SDCC1_APPS_CLK					67
+#define GCC_SDCC1_APPS_CLK_SRC					68
+#define GCC_SPMI_FETCHER_AHB_CLK				69
+#define GCC_SPMI_FETCHER_CLK					70
+#define GCC_SPMI_FETCHER_CLK_SRC				71
+#define GCC_SYS_NOC_CPUSS_AHB_CLK				72
+#define GCC_SYS_NOC_USB3_CLK					73
+#define GCC_USB30_MASTER_CLK					74
+#define GCC_USB30_MASTER_CLK_SRC				75
+#define GCC_USB30_MOCK_UTMI_CLK					76
+#define GCC_USB30_MOCK_UTMI_CLK_SRC				77
+#define GCC_USB30_SLEEP_CLK					78
+#define GCC_USB3_PHY_AUX_CLK					79
+#define GCC_USB3_PHY_AUX_CLK_SRC				80
+#define GCC_USB3_PHY_PIPE_CLK					81
+#define GCC_USB3_PRIM_CLKREF_CLK				82
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK				83
+#define GPLL0							84
+#define GPLL0_OUT_EVEN						85
+#define GPLL4							86
+#define GPLL4_OUT_EVEN						87
 
 /* CPU clocks */
 #define CLOCK_A7SS						0
diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h
index ffa4bb0..f43b73b 100644
--- a/include/dt-bindings/msm/msm-bus-ids.h
+++ b/include/dt-bindings/msm/msm-bus-ids.h
@@ -262,7 +262,7 @@
 #define	MSM_BUS_MASTER_SPMI_FETCHER 151
 #define	MSM_BUS_MASTER_ANOC_SNOC 152
 #define	MSM_BUS_MASTER_ANOC_IPA 153
-#define	MSM_BUS_MASTER_MASTER_LAST 154
+#define	MSM_BUS_MASTER_IPA_PCIE 154
 
 #define MSM_BUS_MASTER_LLCC_DISPLAY 20000
 #define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001
@@ -343,10 +343,8 @@
 #define	MSM_BUS_SNOC_INT_2 10066
 #define	MSM_BUS_A0NOC_QDSS_INT	10067
 #define MSM_BUS_SLAVE_ANOC_PCIE_A1NOC_SNOC 10068
-#define	MSM_BUS_INT_LAST 10069
 
 #define	MSM_BUS_INT_TEST_ID	20000
-#define	MSM_BUS_INT_TEST_LAST	20050
 
 #define	MSM_BUS_SLAVE_FIRST 512
 #define	MSM_BUS_SLAVE_EBI_CH0 512
@@ -607,7 +605,6 @@
 #define	MSM_BUS_SLAVE_ANOC_IPA 780
 #define	MSM_BUS_SLAVE_EMAC_CFG 781
 #define	MSM_BUS_SLAVE_EMMC_CFG 782
-#define	MSM_BUS_SLAVE_LAST 783
 
 #define	MSM_BUS_SLAVE_EBI_CH0_DISPLAY 20512
 #define	MSM_BUS_SLAVE_LLCC_DISPLAY 20513
diff --git a/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h b/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h
new file mode 100644
index 0000000..8718c47
--- /dev/null
+++ b/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_RPM_SMD_REGULATOR_H
+#define __QCOM_RPM_SMD_REGULATOR_H
+
+#define RPM_SMD_REGULATOR_LEVEL_NONE		0
+#define RPM_SMD_REGULATOR_LEVEL_RETENTION	16
+#define RPM_SMD_REGULATOR_LEVEL_RETENTION_PLUS	32
+#define RPM_SMD_REGULATOR_LEVEL_MIN_SVS		48
+#define RPM_SMD_REGULATOR_LEVEL_LOW_SVS		64
+#define RPM_SMD_REGULATOR_LEVEL_SVS		128
+#define RPM_SMD_REGULATOR_LEVEL_SVS_PLUS	192
+#define RPM_SMD_REGULATOR_LEVEL_NOM		256
+#define RPM_SMD_REGULATOR_LEVEL_NOM_PLUS	320
+#define RPM_SMD_REGULATOR_LEVEL_TURBO		384
+#define RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR	416
+#define RPM_SMD_REGULATOR_LEVEL_BINNING		512
+
+#endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9b21e2a..907e029 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1164,8 +1164,6 @@
 	struct address_space *check_mapping;	/* Check page->mapping if set */
 	pgoff_t	first_index;			/* Lowest page->index to unmap */
 	pgoff_t last_index;			/* Highest page->index to unmap */
-	bool ignore_dirty;			/* Ignore dirty pages */
-	bool check_swap_entries;		/* Check also swap entries */
 };
 
 struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 33440fa..70936bf 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -497,7 +497,8 @@
  * enum perf_event_active_state - the states of a event
  */
 enum perf_event_active_state {
-	PERF_EVENT_STATE_DEAD		= -4,
+	PERF_EVENT_STATE_DEAD		= -5,
+	PERF_EVENT_STATE_ZOMBIE		= -4,
 	PERF_EVENT_STATE_EXIT		= -3,
 	PERF_EVENT_STATE_ERROR		= -2,
 	PERF_EVENT_STATE_OFF		= -1,
@@ -720,6 +721,7 @@
 
 	/* Is this event shared with other events */
 	bool					shared;
+	struct list_head		zombie_entry;
 #endif /* CONFIG_PERF_EVENTS */
 };
 
diff --git a/include/linux/regulator/rpm-smd-regulator.h b/include/linux/regulator/rpm-smd-regulator.h
new file mode 100644
index 0000000..1c735cd
--- /dev/null
+++ b/include/linux/regulator/rpm-smd-regulator.h
@@ -0,0 +1,134 @@
+/* Copyright (c) 2012-2013, 2015, 2017 The Linux Foundation. All rights
+ * reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _LINUX_REGULATOR_RPM_SMD_H
+#define _LINUX_REGULATOR_RPM_SMD_H
+
+#include <linux/device.h>
+
+struct rpm_regulator;
+
+/**
+ * enum rpm_regulator_voltage_corner - possible voltage corner values
+ *
+ * These should be used in regulator_set_voltage() and
+ * rpm_regulator_set_voltage() calls for corner type regulators as if they had
+ * units of uV.
+ *
+ * Note, the meaning of corner values is set by the RPM.  It is possible that
+ * future platforms will utilize different corner values.  The values specified
+ * in this enum correspond to MSM8974 for PMIC PM8841 SMPS 2 (VDD_Dig).
+ */
+enum rpm_regulator_voltage_corner {
+	RPM_REGULATOR_CORNER_NONE = 1,
+	RPM_REGULATOR_CORNER_RETENTION,
+	RPM_REGULATOR_CORNER_SVS_KRAIT,
+	RPM_REGULATOR_CORNER_SVS_SOC,
+	RPM_REGULATOR_CORNER_NORMAL,
+	RPM_REGULATOR_CORNER_TURBO,
+	RPM_REGULATOR_CORNER_SUPER_TURBO,
+};
+
+/**
+ * enum rpm_regulator_voltage_level - possible voltage level values
+ *
+ * These should be used in regulator_set_voltage() and
+ * rpm_regulator_set_voltage() calls for level type regulators as if they had
+ * units of uV.
+ *
+ * Note: the meaning of level values is set by the RPM.
+ */
+enum rpm_regulator_voltage_level {
+	RPM_REGULATOR_LEVEL_NONE		= 0,
+	RPM_REGULATOR_LEVEL_RETENTION		= 16,
+	RPM_REGULATOR_LEVEL_RETENTION_PLUS	= 32,
+	RPM_REGULATOR_LEVEL_MIN_SVS		= 48,
+	RPM_REGULATOR_LEVEL_LOW_SVS		= 64,
+	RPM_REGULATOR_LEVEL_SVS			= 128,
+	RPM_REGULATOR_LEVEL_SVS_PLUS		= 192,
+	RPM_REGULATOR_LEVEL_NOM			= 256,
+	RPM_REGULATOR_LEVEL_NOM_PLUS		= 320,
+	RPM_REGULATOR_LEVEL_TURBO		= 384,
+	RPM_REGULATOR_LEVEL_TURBO_NO_CPR	= 416,
+	RPM_REGULATOR_LEVEL_BINNING		= 512,
+	RPM_REGULATOR_LEVEL_MAX			= 65535,
+};
+
+/**
+ * enum rpm_regulator_mode - control mode for LDO or SMPS type regulators
+ * %RPM_REGULATOR_MODE_AUTO:	For SMPS type regulators, use SMPS auto mode so
+ *				that the hardware can automatically switch
+ *				between PFM and PWM modes based on realtime
+ *				load.
+ *				LDO type regulators do not support this mode.
+ * %RPM_REGULATOR_MODE_IPEAK:	For SMPS type regulators, use aggregated
+ *				software current requests to determine
+ *				usage of PFM or PWM mode.
+ *				For LDO type regulators, use aggregated
+ *				software current requests to determine
+ *				usage of LPM or HPM mode.
+ * %RPM_REGULATOR_MODE_HPM:	For SMPS type regulators, force the
+ *				usage of PWM mode.
+ *				For LDO type regulators, force the
+ *				usage of HPM mode.
+ *
+ * These values should be used in calls to rpm_regulator_set_mode().
+ */
+enum rpm_regulator_mode {
+	RPM_REGULATOR_MODE_AUTO,
+	RPM_REGULATOR_MODE_IPEAK,
+	RPM_REGULATOR_MODE_HPM,
+};
+
+#ifdef CONFIG_REGULATOR_RPM_SMD
+
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply);
+
+void rpm_regulator_put(struct rpm_regulator *regulator);
+
+int rpm_regulator_enable(struct rpm_regulator *regulator);
+
+int rpm_regulator_disable(struct rpm_regulator *regulator);
+
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+			      int max_uV);
+
+int rpm_regulator_set_mode(struct rpm_regulator *regulator,
+				enum rpm_regulator_mode mode);
+
+int __init rpm_smd_regulator_driver_init(void);
+
+#else
+
+static inline struct rpm_regulator *rpm_regulator_get(struct device *dev,
+					const char *supply) { return NULL; }
+
+static inline void rpm_regulator_put(struct rpm_regulator *regulator) { }
+
+static inline int rpm_regulator_enable(struct rpm_regulator *regulator)
+			{ return 0; }
+
+static inline int rpm_regulator_disable(struct rpm_regulator *regulator)
+			{ return 0; }
+
+static inline int rpm_regulator_set_voltage(struct rpm_regulator *regulator,
+					int min_uV, int max_uV) { return 0; }
+
+static inline int rpm_regulator_set_mode(struct rpm_regulator *regulator,
+				enum rpm_regulator_mode mode) { return 0; }
+
+static inline int __init rpm_smd_regulator_driver_init(void) { return 0; }
+
+#endif /* CONFIG_REGULATOR_RPM_SMD */
+
+#endif
diff --git a/include/linux/regulator/spm-regulator.h b/include/linux/regulator/spm-regulator.h
new file mode 100644
index 0000000..bd5da2e
--- /dev/null
+++ b/include/linux/regulator/spm-regulator.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013-2014, 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 _LINUX_REGULATOR_SPM_H
+#define _LINUX_REGULATOR_SPM_H
+
+#include <linux/err.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_REGULATOR_SPM
+int __init spm_regulator_init(void);
+#else
+static inline int __init spm_regulator_init(void) { return -ENODEV; }
+#endif
+
+#endif
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
index cda2654..d2c1a95 100644
--- a/include/linux/sde_rsc.h
+++ b/include/linux/sde_rsc.h
@@ -186,6 +186,26 @@
 	int *wait_vblank_crtc_id);
 
 /**
+ * sde_rsc_client_get_vsync_refcount() - returns the status of the vsync
+ * refcount, to signal if the client needs to reset the refcounting logic
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: true if the state update has completed.
+ */
+int sde_rsc_client_get_vsync_refcount(
+		struct sde_rsc_client *caller_client);
+
+/**
+ * sde_rsc_client_reset_vsync_refcount() - reduces the refcounting
+ * logic that waits for the vsync.
+ * @client:	 Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: true if the state update has completed.
+ */
+int sde_rsc_client_reset_vsync_refcount(
+		struct sde_rsc_client *caller_client);
+
+/**
  * sde_rsc_client_is_state_update_complete() - check if state update is complete
  * RSC state transition is not complete until HW receives VBLANK signal. This
  * function checks RSC HW to determine whether that signal has been received.
@@ -265,6 +285,18 @@
 	return 0;
 }
 
+int sde_rsc_client_get_vsync_refcount(
+		struct sde_rsc_client *caller_client)
+{
+	return 0;
+}
+
+int sde_rsc_client_reset_vsync_refcount(
+		struct sde_rsc_client *caller_client)
+{
+	return 0;
+}
+
 static inline bool sde_rsc_client_is_state_update_complete(
 		struct sde_rsc_client *caller_client)
 {
diff --git a/include/linux/string.h b/include/linux/string.h
index 0463dfb..4691e7f 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -173,9 +173,16 @@
 #define __RENAME(x) __asm__(#x)
 
 void fortify_panic(const char *name) __noreturn __cold;
+
+#ifdef CONFIG_FORTIFY_COMPILE_CHECK
 void __read_overflow(void) __compiletime_error("detected read beyond size of object passed as 1st parameter");
 void __read_overflow2(void) __compiletime_error("detected read beyond size of object passed as 2nd parameter");
 void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter");
+#else
+#define __read_overflow(void) do { } while (0)
+#define __read_overflow2(void) do { } while (0)
+#define __write_overflow(void) do { } while (0)
+#endif
 
 #if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE)
 __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size)
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index ddd8f4d..4f56e98 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -520,7 +520,6 @@
 	unsigned			is_selfpowered:1;
 	unsigned			deactivated:1;
 	unsigned			connected:1;
-	bool				l1_supported;
 	bool				remote_wakeup;
 };
 #define work_to_gadget(w)	(container_of((w), struct usb_gadget, work))
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 092c32e..742ef8d 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -114,6 +114,8 @@
 
 	/* enable/disable VBUS */
 	int	(*set_vbus)(struct usb_phy *x, int on);
+	/* callback to indicate port is being reset or reset the port */
+	void	(*start_port_reset)(struct usb_phy *x);
 
 	/* effective for B devices, ignored for A-peripheral */
 	int	(*set_power)(struct usb_phy *x,
@@ -213,6 +215,15 @@
 	return x->set_vbus(x, false);
 }
 
+static inline void
+usb_phy_start_port_reset(struct usb_phy *x)
+{
+	if (!x || !x->start_port_reset)
+		return;
+
+	x->start_port_reset(x);
+}
+
 static inline int
 usb_phy_reset(struct usb_phy *x)
 {
diff --git a/include/trace/events/oom.h b/include/trace/events/oom.h
index 1e97498..beddb19 100644
--- a/include/trace/events/oom.h
+++ b/include/trace/events/oom.h
@@ -27,6 +27,85 @@
 		__entry->pid, __entry->comm, __entry->oom_score_adj)
 );
 
+TRACE_EVENT(mark_victim,
+	TP_PROTO(int pid),
+
+	TP_ARGS(pid),
+
+	TP_STRUCT__entry(
+		__field(int, pid)
+	),
+
+	TP_fast_assign(
+		__entry->pid = pid;
+	),
+
+	TP_printk("pid=%d", __entry->pid)
+);
+
+TRACE_EVENT(wake_reaper,
+	TP_PROTO(int pid),
+
+	TP_ARGS(pid),
+
+	TP_STRUCT__entry(
+		__field(int, pid)
+	),
+
+	TP_fast_assign(
+		__entry->pid = pid;
+	),
+
+	TP_printk("pid=%d", __entry->pid)
+);
+
+TRACE_EVENT(start_task_reaping,
+	TP_PROTO(int pid),
+
+	TP_ARGS(pid),
+
+	TP_STRUCT__entry(
+		__field(int, pid)
+	),
+
+	TP_fast_assign(
+		__entry->pid = pid;
+	),
+
+	TP_printk("pid=%d", __entry->pid)
+);
+
+TRACE_EVENT(finish_task_reaping,
+	TP_PROTO(int pid),
+
+	TP_ARGS(pid),
+
+	TP_STRUCT__entry(
+		__field(int, pid)
+	),
+
+	TP_fast_assign(
+		__entry->pid = pid;
+	),
+
+	TP_printk("pid=%d", __entry->pid)
+);
+
+TRACE_EVENT(skip_task_reaping,
+	TP_PROTO(int pid),
+
+	TP_ARGS(pid),
+
+	TP_STRUCT__entry(
+		__field(int, pid)
+	),
+
+	TP_fast_assign(
+		__entry->pid = pid;
+	),
+
+	TP_printk("pid=%d", __entry->pid)
+);
 #endif
 
 /* This part must be outside protection */
diff --git a/kernel/compat.c b/kernel/compat.c
index 333d364..1cd7051 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -109,7 +109,7 @@
 		       struct timezone __user *, tz)
 {
 	struct timeval user_tv;
-	struct timespec	new_ts;
+	struct timespec	new_ts = {0};
 	struct timezone new_tz;
 
 	if (tv) {
diff --git a/kernel/events/core.c b/kernel/events/core.c
index ed27a8c..712ba4e 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4263,6 +4263,14 @@
 }
 
 /*
+ * Maintain a zombie list to collect all the zombie events
+ */
+#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static LIST_HEAD(zombie_list);
+static DEFINE_SPINLOCK(zombie_list_lock);
+#endif
+
+/*
  * Kill an event dead; while event:refcount will preserve the event
  * object, it will not preserve its functionality. Once the last 'user'
  * gives up the object, we'll destroy the thing.
@@ -4273,6 +4281,26 @@
 	struct perf_event *child, *tmp;
 
 	/*
+	 * If the cpu associated to this event is offline, set the event as a
+	 *  zombie event. The cleanup of the cpu would be done if the CPU is
+	 *  back online.
+	 */
+#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+	if (!cpu_online(event->cpu)) {
+		if (event->state == PERF_EVENT_STATE_ZOMBIE)
+			return 0;
+
+		event->state = PERF_EVENT_STATE_ZOMBIE;
+
+		spin_lock(&zombie_list_lock);
+		list_add_tail(&event->zombie_entry, &zombie_list);
+		spin_unlock(&zombie_list_lock);
+
+		return 0;
+	}
+#endif
+
+	/*
 	 * If we got here through err_file: fput(event_file); we will not have
 	 * attached to a context yet.
 	 */
@@ -9388,6 +9416,7 @@
 	INIT_LIST_HEAD(&event->rb_entry);
 	INIT_LIST_HEAD(&event->active_entry);
 	INIT_LIST_HEAD(&event->addr_filters.list);
+	INIT_LIST_HEAD(&event->zombie_entry);
 	INIT_HLIST_NODE(&event->hlist_entry);
 
 
@@ -11043,6 +11072,32 @@
 		event->pmu->start(event, 0);
 }
 
+static void perf_event_zombie_cleanup(unsigned int cpu)
+{
+	struct perf_event *event, *tmp;
+
+	spin_lock(&zombie_list_lock);
+
+	list_for_each_entry_safe(event, tmp, &zombie_list, zombie_entry) {
+		if (event->cpu != cpu)
+			continue;
+
+		list_del(&event->zombie_entry);
+		spin_unlock(&zombie_list_lock);
+
+		/*
+		 * The detachment of the event with the
+		 * PMU expects it to be in an active state
+		 */
+		event->state = PERF_EVENT_STATE_ACTIVE;
+		perf_event_release_kernel(event);
+
+		spin_lock(&zombie_list_lock);
+	}
+
+	spin_unlock(&zombie_list_lock);
+}
+
 static int perf_event_start_swevents(unsigned int cpu)
 {
 	struct perf_event_context *ctx;
@@ -11050,6 +11105,8 @@
 	struct perf_event *event;
 	int idx;
 
+	perf_event_zombie_cleanup(cpu);
+
 	idx = srcu_read_lock(&pmus_srcu);
 	list_for_each_entry_rcu(pmu, &pmus, entry) {
 		ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx;
diff --git a/kernel/fork.c b/kernel/fork.c
index 610aded..b83adf9 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -879,7 +879,6 @@
 	}
 	if (mm->binfmt)
 		module_put(mm->binfmt->module);
-	set_bit(MMF_OOM_SKIP, &mm->flags);
 	mmdrop(mm);
 }
 
diff --git a/kernel/time/time.c b/kernel/time/time.c
index bd62fb8..1b2d209 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -194,7 +194,7 @@
 		struct timezone __user *, tz)
 {
 	struct timeval user_tv;
-	struct timespec	new_ts;
+	struct timespec	new_ts = {0};
 	struct timezone new_tz;
 
 	if (tv) {
diff --git a/mm/internal.h b/mm/internal.h
index 0ee4f54..6aa1c51 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -41,6 +41,11 @@
 void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
 		unsigned long floor, unsigned long ceiling);
 
+static inline bool can_madv_dontneed_vma(struct vm_area_struct *vma)
+{
+	return !(vma->vm_flags & (VM_LOCKED|VM_HUGETLB|VM_PFNMAP));
+}
+
 void unmap_page_range(struct mmu_gather *tlb,
 			     struct vm_area_struct *vma,
 			     unsigned long addr, unsigned long end,
diff --git a/mm/madvise.c b/mm/madvise.c
index 088a5b22..8b25167 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -25,6 +25,8 @@
 
 #include <asm/tlb.h>
 
+#include "internal.h"
+
 /*
  * Any behaviour which results in changes to the vma->vm_flags needs to
  * take mmap_sem for writing. Others, which simply traverse vmas, need
@@ -474,7 +476,7 @@
 			     unsigned long start, unsigned long end)
 {
 	*prev = vma;
-	if (vma->vm_flags & (VM_LOCKED|VM_HUGETLB|VM_PFNMAP))
+	if (!can_madv_dontneed_vma(vma))
 		return -EINVAL;
 
 	zap_page_range(vma, start, end - start, NULL);
diff --git a/mm/memory.c b/mm/memory.c
index 378ebc0..82d2000 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1154,12 +1154,6 @@
 
 			if (!PageAnon(page)) {
 				if (pte_dirty(ptent)) {
-					/*
-					 * oom_reaper cannot tear down dirty
-					 * pages
-					 */
-					if (unlikely(details && details->ignore_dirty))
-						continue;
 					force_flush = 1;
 					set_page_dirty(page);
 				}
@@ -1179,8 +1173,8 @@
 			}
 			continue;
 		}
-		/* only check swap_entries if explicitly asked for in details */
-		if (unlikely(details && !details->check_swap_entries))
+		/* If details->check_mapping, we leave swap entries. */
+		if (unlikely(details))
 			continue;
 
 		entry = pte_to_swp_entry(ptent);
diff --git a/mm/mmap.c b/mm/mmap.c
index 6f90f07..7e6c049 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -44,6 +44,7 @@
 #include <linux/userfaultfd_k.h>
 #include <linux/moduleparam.h>
 #include <linux/pkeys.h>
+#include <linux/oom.h>
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -2983,6 +2984,23 @@
 	/* Use -1 here to ensure all VMAs in the mm are unmapped */
 	unmap_vmas(&tlb, vma, 0, -1);
 
+	set_bit(MMF_OOM_SKIP, &mm->flags);
+	if (unlikely(tsk_is_oom_victim(current))) {
+		/*
+		 * Wait for oom_reap_task() to stop working on this
+		 * mm. Because MMF_OOM_SKIP is already set before
+		 * calling down_read(), oom_reap_task() will not run
+		 * on this "mm" post up_write().
+		 *
+		 * tsk_is_oom_victim() cannot be set from under us
+		 * either because current->mm is already set to NULL
+		 * under task_lock before calling mmput and oom_mm is
+		 * set not NULL by the OOM killer only if current->mm
+		 * is found not NULL while holding the task_lock.
+		 */
+		down_write(&mm->mmap_sem);
+		up_write(&mm->mmap_sem);
+	}
 	free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, USER_PGTABLES_CEILING);
 	tlb_finish_mmu(&tlb, 0, -1);
 
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 1f13413..af9a8a6 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -470,8 +470,6 @@
 {
 	struct mmu_gather tlb;
 	struct vm_area_struct *vma;
-	struct zap_details details = {.check_swap_entries = true,
-				      .ignore_dirty = true};
 	bool ret = true;
 
 	/*
@@ -492,6 +490,7 @@
 
 	if (!down_read_trylock(&mm->mmap_sem)) {
 		ret = false;
+		trace_skip_task_reaping(tsk->pid);
 		goto unlock_oom;
 	}
 
@@ -511,15 +510,19 @@
 	}
 
 	/*
-	 * increase mm_users only after we know we will reap something so
-	 * that the mmput_async is called only when we have reaped something
-	 * and delayed __mmput doesn't matter that much
+	 * MMF_OOM_SKIP is set by exit_mmap when the OOM reaper can't
+	 * work on the mm anymore. The check for MMF_OOM_SKIP must run
+	 * under mmap_sem for reading because it serializes against the
+	 * down_write();up_write() cycle in exit_mmap().
 	 */
-	if (!mmget_not_zero(mm)) {
+	if (test_bit(MMF_OOM_SKIP, &mm->flags)) {
 		up_read(&mm->mmap_sem);
+		trace_skip_task_reaping(tsk->pid);
 		goto unlock_oom;
 	}
 
+	trace_start_task_reaping(tsk->pid);
+
 	/*
 	 * Tell all users of get_user/copy_from_user etc... that the content
 	 * is no longer stable. No barriers really needed because unmapping
@@ -528,16 +531,8 @@
 	 */
 	set_bit(MMF_UNSTABLE, &mm->flags);
 
-	tlb_gather_mmu(&tlb, mm, 0, -1);
 	for (vma = mm->mmap ; vma; vma = vma->vm_next) {
-		if (is_vm_hugetlb_page(vma))
-			continue;
-
-		/*
-		 * mlocked VMAs require explicit munlocking before unmap.
-		 * Let's keep it simple here and skip such VMAs.
-		 */
-		if (vma->vm_flags & VM_LOCKED)
+		if (!can_madv_dontneed_vma(vma))
 			continue;
 
 		/*
@@ -550,11 +545,13 @@
 		 * we do not want to block exit_mmap by keeping mm ref
 		 * count elevated without a good reason.
 		 */
-		if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED))
+		if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED)) {
+			tlb_gather_mmu(&tlb, mm, vma->vm_start, vma->vm_end);
 			unmap_page_range(&tlb, vma, vma->vm_start, vma->vm_end,
-					 &details);
+					 NULL);
+			tlb_finish_mmu(&tlb, vma->vm_start, vma->vm_end);
+		}
 	}
-	tlb_finish_mmu(&tlb, 0, -1);
 	pr_info("oom_reaper: reaped process %d (%s), now anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
 			task_pid_nr(tsk), tsk->comm,
 			K(get_mm_counter(mm, MM_ANONPAGES)),
@@ -562,12 +559,7 @@
 			K(get_mm_counter(mm, MM_SHMEMPAGES)));
 	up_read(&mm->mmap_sem);
 
-	/*
-	 * Drop our reference but make sure the mmput slow path is called from a
-	 * different context because we shouldn't risk we get stuck there and
-	 * put the oom_reaper out of the way.
-	 */
-	mmput_async(mm);
+	trace_finish_task_reaping(tsk->pid);
 unlock_oom:
 	mutex_unlock(&oom_lock);
 	return ret;
@@ -644,6 +636,7 @@
 	tsk->oom_reaper_list = oom_reaper_list;
 	oom_reaper_list = tsk;
 	spin_unlock(&oom_reaper_lock);
+	trace_wake_reaper(tsk->pid);
 	wake_up(&oom_reaper_wait);
 }
 
@@ -695,6 +688,7 @@
 	 */
 	__thaw_task(tsk);
 	atomic_inc(&oom_victims);
+	trace_mark_victim(tsk->pid);
 }
 
 /**
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index bcfc58b..baf31df 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7428,10 +7428,10 @@
 	}
 
 	/* Make sure the range is really isolated. */
-	if (test_pages_isolated(outer_start, end, false)) {
+	ret = test_pages_isolated(outer_start, end, false);
+	if (ret) {
 		pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
 			__func__, outer_start, end);
-		ret = -EBUSY;
 		goto done;
 	}